@nebulr-group/bridge-cli 0.1.0-beta.0 → 0.1.2

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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +75 -18
  3. package/dist/auth/api-client.d.ts +48 -0
  4. package/dist/auth/api-client.d.ts.map +1 -0
  5. package/dist/auth/api-client.js +109 -0
  6. package/dist/auth/api-client.js.map +1 -0
  7. package/dist/auth/browser-open.d.ts +12 -0
  8. package/dist/auth/browser-open.d.ts.map +1 -0
  9. package/dist/auth/browser-open.js +82 -0
  10. package/dist/auth/browser-open.js.map +1 -0
  11. package/dist/auth/loopback.d.ts +63 -0
  12. package/dist/auth/loopback.d.ts.map +1 -0
  13. package/dist/auth/loopback.js +290 -0
  14. package/dist/auth/loopback.js.map +1 -0
  15. package/dist/auth/pkce.d.ts +19 -0
  16. package/dist/auth/pkce.d.ts.map +1 -0
  17. package/dist/auth/pkce.js +46 -0
  18. package/dist/auth/pkce.js.map +1 -0
  19. package/dist/auth/relative-time.d.ts +2 -0
  20. package/dist/auth/relative-time.d.ts.map +1 -0
  21. package/dist/auth/relative-time.js +27 -0
  22. package/dist/auth/relative-time.js.map +1 -0
  23. package/dist/cli.d.ts.map +1 -1
  24. package/dist/cli.js +9 -1
  25. package/dist/cli.js.map +1 -1
  26. package/dist/commands/auth/config.command.d.ts +8 -0
  27. package/dist/commands/auth/config.command.d.ts.map +1 -0
  28. package/dist/commands/auth/config.command.js +60 -0
  29. package/dist/commands/auth/config.command.js.map +1 -0
  30. package/dist/commands/auth/login.command.d.ts +20 -0
  31. package/dist/commands/auth/login.command.d.ts.map +1 -0
  32. package/dist/commands/auth/login.command.js +141 -0
  33. package/dist/commands/auth/login.command.js.map +1 -0
  34. package/dist/commands/auth/logout.command.d.ts +14 -0
  35. package/dist/commands/auth/logout.command.d.ts.map +1 -0
  36. package/dist/commands/auth/logout.command.js +57 -0
  37. package/dist/commands/auth/logout.command.js.map +1 -0
  38. package/dist/commands/auth/status.command.d.ts +14 -0
  39. package/dist/commands/auth/status.command.d.ts.map +1 -0
  40. package/dist/commands/auth/status.command.js +59 -0
  41. package/dist/commands/auth/status.command.js.map +1 -0
  42. package/dist/commands/auth.command.d.ts +10 -1
  43. package/dist/commands/auth.command.d.ts.map +1 -1
  44. package/dist/commands/auth.command.js +13 -55
  45. package/dist/commands/auth.command.js.map +1 -1
  46. package/dist/commands/guide.command.js +5 -5
  47. package/dist/commands/guide.command.js.map +1 -1
  48. package/dist/config.d.ts +24 -0
  49. package/dist/config.d.ts.map +1 -1
  50. package/dist/config.js +79 -9
  51. package/dist/config.js.map +1 -1
  52. package/dist/credentials.d.ts +57 -0
  53. package/dist/credentials.d.ts.map +1 -0
  54. package/dist/credentials.js +136 -0
  55. package/dist/credentials.js.map +1 -0
  56. package/package.json +2 -2
@@ -0,0 +1,141 @@
1
+ import { writeCredentials } from '../../credentials.js';
2
+ import { resetManagementClient } from '../../config.js';
3
+ import { generateCodeVerifier, codeChallengeFor, generateState } from '../../auth/pkce.js';
4
+ import { startLoopback, LoopbackError } from '../../auth/loopback.js';
5
+ import { openBrowser } from '../../auth/browser-open.js';
6
+ import { createCliApiClient, CliAuthApiError } from '../../auth/api-client.js';
7
+ const DEFAULT_API_BASE_URL = 'https://api.thebridge.dev';
8
+ const DEFAULT_AUTH_BASE_URL = 'https://auth.thebridge.dev';
9
+ export function registerAuthLoginCommand(auth) {
10
+ auth
11
+ .command('login')
12
+ .description('Authenticate via browser (loopback PKCE) and save credentials')
13
+ .option('--app <id|name>', 'Pin to a specific app (skips the picker on the consent screen)')
14
+ .option('--label <text>', 'Friendly label stored on the token (default: "bridge-cli")')
15
+ .option('--no-browser', 'Print the authorization URL instead of opening a browser')
16
+ .action(async (opts) => {
17
+ try {
18
+ await runLogin(opts);
19
+ process.exitCode = 0;
20
+ }
21
+ catch (err) {
22
+ // Friendly, single-line stderr — never log JWTs / verifiers.
23
+ const msg = err instanceof Error ? err.message : String(err);
24
+ process.stderr.write(`bridge auth login: ${msg}\n`);
25
+ process.exitCode = 1;
26
+ }
27
+ });
28
+ }
29
+ async function runLogin(opts) {
30
+ const apiBaseUrl = (process.env.BRIDGE_BASE_URL?.trim() || DEFAULT_API_BASE_URL).replace(/\/$/, '');
31
+ const authBaseUrl = (process.env.BRIDGE_AUTH_BASE_URL?.trim() || DEFAULT_AUTH_BASE_URL).replace(/\/$/, '');
32
+ // 1. PKCE + state.
33
+ const codeVerifier = generateCodeVerifier();
34
+ const codeChallenge = codeChallengeFor(codeVerifier);
35
+ const state = generateState();
36
+ // 2. Boot the single-shot loopback listener.
37
+ let loopback;
38
+ try {
39
+ loopback = await startLoopback({
40
+ expectedState: state,
41
+ // Bounce the browser to a branded success page on cloud-views instead
42
+ // of leaving the user staring at 127.0.0.1.
43
+ successRedirectUrl: `${authBaseUrl}/cli/login-complete`,
44
+ });
45
+ }
46
+ catch (err) {
47
+ throw new Error(`Could not bind a loopback port: ${err instanceof Error ? err.message : String(err)}. ` +
48
+ 'Try `bridge auth login --device` once TBP-108 lands, or check whether your firewall blocks 127.0.0.1.');
49
+ }
50
+ const authorizeUrl = buildAuthorizeUrl(authBaseUrl, {
51
+ challenge: codeChallenge,
52
+ redirect: loopback.redirectUri,
53
+ state,
54
+ appId: opts.app,
55
+ label: opts.label,
56
+ });
57
+ // 3. Open browser (or print URL if --no-browser or open fails).
58
+ const stdout = process.stdout;
59
+ // commander's `--no-browser` sets opts.browser === false. Treat unset as the
60
+ // default (open browser); only skip when explicitly false.
61
+ const useBrowser = opts.browser !== false;
62
+ if (!useBrowser) {
63
+ stdout.write(`Open this URL in your browser to continue:\n ${authorizeUrl}\n`);
64
+ }
65
+ else {
66
+ const open = await openBrowser(authorizeUrl);
67
+ if (!open.ok) {
68
+ stdout.write(`Could not open a browser automatically (${open.reason ?? 'unknown'}). ` +
69
+ `Open this URL manually:\n ${authorizeUrl}\n`);
70
+ }
71
+ else {
72
+ stdout.write('Opened your browser. Waiting for authorization...\n');
73
+ }
74
+ }
75
+ // 4. Await the callback. Translate cancel/CSRF/timeout into friendly errors.
76
+ let result;
77
+ try {
78
+ result = await loopback.result;
79
+ }
80
+ catch (err) {
81
+ if (err instanceof LoopbackError) {
82
+ throw new Error(err.message);
83
+ }
84
+ throw err;
85
+ }
86
+ // 5. Exchange the code for a JWT.
87
+ const api = createCliApiClient({ baseUrl: apiBaseUrl });
88
+ let exchanged;
89
+ try {
90
+ exchanged = await api.exchangeCode({
91
+ code: result.code,
92
+ codeVerifier,
93
+ });
94
+ }
95
+ catch (err) {
96
+ if (err instanceof CliAuthApiError) {
97
+ throw new Error(err.message);
98
+ }
99
+ throw err;
100
+ }
101
+ // 6. Persist credentials with mode 0600.
102
+ const issuedAt = new Date().toISOString();
103
+ const stored = {
104
+ apiKey: exchanged.api_token,
105
+ expiresAt: exchanged.expires_at,
106
+ issuedAt,
107
+ app: { id: exchanged.app.id, name: exchanged.app.name },
108
+ user: { id: exchanged.user.id, email: exchanged.user.email },
109
+ baseUrl: apiBaseUrl,
110
+ ...(opts.label ? { label: opts.label } : {}),
111
+ };
112
+ writeCredentials(stored);
113
+ // Reset the cached BridgeManagement client so the next command picks up the
114
+ // new token (relevant when `auth login` is called within the same process).
115
+ resetManagementClient();
116
+ // 7. Friendly confirmation.
117
+ const expiryHuman = formatExpiryDate(exchanged.expires_at);
118
+ stdout.write(`Logged in as ${exchanged.user.email}. App: ${exchanged.app.name}. Token valid until ${expiryHuman}.\n`);
119
+ }
120
+ function buildAuthorizeUrl(authBaseUrl, params) {
121
+ const url = new URL(`${authBaseUrl}/cli/authorize`);
122
+ url.searchParams.set('challenge', params.challenge);
123
+ url.searchParams.set('redirect', params.redirect);
124
+ url.searchParams.set('state', params.state);
125
+ url.searchParams.set('scope', 'management');
126
+ if (params.appId)
127
+ url.searchParams.set('app_id', params.appId);
128
+ if (params.label)
129
+ url.searchParams.set('label', params.label);
130
+ return url.toString();
131
+ }
132
+ function formatExpiryDate(iso) {
133
+ const d = new Date(iso);
134
+ if (Number.isNaN(d.getTime()))
135
+ return iso;
136
+ // YYYY-MM-DD HH:MM (local) — easier to glance at than a full ISO.
137
+ const pad = (n) => String(n).padStart(2, '0');
138
+ return (`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +
139
+ `${pad(d.getHours())}:${pad(d.getMinutes())}`);
140
+ }
141
+ //# sourceMappingURL=login.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.command.js","sourceRoot":"","sources":["../../../src/commands/auth/login.command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `bridge auth logout` — best-effort revoke + delete credentials file.
3
+ *
4
+ * Behavior:
5
+ * - No credentials file → "Not logged in." (exit 0).
6
+ * - File present → call `POST /v1/auth/cli/revoke` with `x-api-key`,
7
+ * treat 401 as success (token already gone), then
8
+ * delete the file. Network errors → warn but still
9
+ * delete (the local file is the source of truth for
10
+ * "logged in" on this machine).
11
+ */
12
+ import type { Command } from 'commander';
13
+ export declare function registerAuthLogoutCommand(auth: Command): void;
14
+ //# sourceMappingURL=logout.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.command.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/logout.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAc7D"}
@@ -0,0 +1,57 @@
1
+ import { credentialsPath, deleteCredentials, readCredentials } from '../../credentials.js';
2
+ import { resetManagementClient } from '../../config.js';
3
+ import { createCliApiClient, CliAuthApiError } from '../../auth/api-client.js';
4
+ export function registerAuthLogoutCommand(auth) {
5
+ auth
6
+ .command('logout')
7
+ .description('Revoke the saved CLI token and delete local credentials')
8
+ .action(async () => {
9
+ try {
10
+ await runLogout();
11
+ process.exitCode = 0;
12
+ }
13
+ catch (err) {
14
+ const msg = err instanceof Error ? err.message : String(err);
15
+ process.stderr.write(`bridge auth logout: ${msg}\n`);
16
+ process.exitCode = 1;
17
+ }
18
+ });
19
+ }
20
+ async function runLogout() {
21
+ const stdout = process.stdout;
22
+ const stderr = process.stderr;
23
+ let creds;
24
+ try {
25
+ creds = readCredentials();
26
+ }
27
+ catch (err) {
28
+ // Malformed credentials file — still try to delete it so the user gets unstuck.
29
+ stderr.write(`Warning: existing credentials file at ${credentialsPath()} could not be parsed (${err instanceof Error ? err.message : String(err)}). Removing it.\n`);
30
+ deleteCredentials();
31
+ stdout.write('Logged out (credentials file removed).\n');
32
+ return;
33
+ }
34
+ if (!creds) {
35
+ stdout.write('Not logged in.\n');
36
+ return;
37
+ }
38
+ const api = createCliApiClient({ baseUrl: creds.baseUrl });
39
+ try {
40
+ await api.revokeToken(creds.apiKey);
41
+ }
42
+ catch (err) {
43
+ // Network failure — warn but still proceed with local deletion.
44
+ 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`);
46
+ }
47
+ else {
48
+ // Any other API error is also non-fatal for the local cleanup, but we
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`);
51
+ }
52
+ }
53
+ deleteCredentials();
54
+ resetManagementClient();
55
+ stdout.write(`Logged out ${creds.user.email}.\n`);
56
+ }
57
+ //# sourceMappingURL=logout.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.command.js","sourceRoot":"","sources":["../../../src/commands/auth/logout.command.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE/E,MAAM,UAAU,yBAAyB,CAAC,IAAa;IACrD,IAAI;SACD,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,yDAAyD,CAAC;SACtE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,SAAS,EAAE,CAAC;YAClB,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,uBAAuB,GAAG,IAAI,CAAC,CAAC;YACrD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAE9B,IAAI,KAAK,CAAC;IACV,IAAI,CAAC;QACH,KAAK,GAAG,eAAe,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,gFAAgF;QAChF,MAAM,CAAC,KAAK,CACV,yCAAyC,eAAe,EAAE,yBACxD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,mBAAmB,CACpB,CAAC;QACF,iBAAiB,EAAE,CAAC;QACpB,MAAM,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QACzD,OAAO;IACT,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,gEAAgE;QAChE,IAAI,GAAG,YAAY,eAAe,IAAI,GAAG,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACnE,MAAM,CAAC,KAAK,CAAC,8DAA8D,GAAG,CAAC,OAAO,yCAAyC,CAAC,CAAC;QACnI,CAAC;aAAM,CAAC;YACN,sEAAsE;YACtE,qEAAqE;YACrE,MAAM,CAAC,KAAK,CACV,kDACE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,yCAAyC,CAC1C,CAAC;QACJ,CAAC;IACH,CAAC;IAED,iBAAiB,EAAE,CAAC;IACpB,qBAAqB,EAAE,CAAC;IACxB,MAAM,CAAC,KAAK,CAAC,cAAc,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `bridge auth status` — prints whether a credentials file exists, who it's
3
+ * for, and how long until it expires.
4
+ *
5
+ * Output is plain text (one key=value per line after the first), tuned for
6
+ * humans. Other CLI commands emit structured JSON — auth status is the one
7
+ * place where a developer is most likely to be eyeballing the result, so we
8
+ * optimize for readability over machine-parseability.
9
+ *
10
+ * If the user wants JSON, they can run `cat ~/.config/bridge/credentials.json`.
11
+ */
12
+ import type { Command } from 'commander';
13
+ export declare function registerAuthStatusCommand(auth: Command): void;
14
+ //# sourceMappingURL=status.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.command.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/status.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAc7D"}
@@ -0,0 +1,59 @@
1
+ import { credentialsPath, isExpired, readCredentials } from '../../credentials.js';
2
+ import { formatRelativeTime } from '../../auth/relative-time.js';
3
+ export function registerAuthStatusCommand(auth) {
4
+ auth
5
+ .command('status')
6
+ .description('Show current authentication state (who, which app, expiry)')
7
+ .action(() => {
8
+ try {
9
+ runStatus();
10
+ process.exitCode = 0;
11
+ }
12
+ catch (err) {
13
+ const msg = err instanceof Error ? err.message : String(err);
14
+ process.stderr.write(`bridge auth status: ${msg}\n`);
15
+ process.exitCode = 1;
16
+ }
17
+ });
18
+ }
19
+ function runStatus() {
20
+ const stdout = process.stdout;
21
+ // Prefer the credentials file; report on `BRIDGE_API_KEY` separately if set
22
+ // (so a CI user setting the env var sees something useful).
23
+ const envApiKey = process.env.BRIDGE_API_KEY?.trim();
24
+ let creds;
25
+ try {
26
+ creds = readCredentials();
27
+ }
28
+ catch (err) {
29
+ 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
+ return;
31
+ }
32
+ if (!creds) {
33
+ if (envApiKey && envApiKey.length > 0) {
34
+ stdout.write('Using BRIDGE_API_KEY from environment (service-account / CI path).\n' +
35
+ 'Run `bridge auth login` to switch to interactive credentials.\n');
36
+ return;
37
+ }
38
+ stdout.write('Not logged in. Run `bridge auth login`.\n');
39
+ return;
40
+ }
41
+ const expiryDate = new Date(creds.expiresAt);
42
+ const expiryDelta = expiryDate.getTime() - Date.now();
43
+ const expiryRel = formatRelativeTime(expiryDelta);
44
+ const expiredLabel = isExpired(creds) ? ' (EXPIRED)' : '';
45
+ stdout.write(`Logged in as ${creds.user.email}\n`);
46
+ stdout.write(` app=${creds.app.name} (${creds.app.id})\n`);
47
+ stdout.write(` expires=${expiryRel} — ${creds.expiresAt}${expiredLabel}\n`);
48
+ stdout.write(` baseUrl=${creds.baseUrl}\n`);
49
+ if (creds.label)
50
+ stdout.write(` label=${creds.label}\n`);
51
+ stdout.write(` credentials=${credentialsPath()}\n`);
52
+ if (envApiKey && envApiKey.length > 0) {
53
+ stdout.write('\nNote: BRIDGE_API_KEY is also set in your environment — it takes precedence over the credentials file.\n');
54
+ }
55
+ if (isExpired(creds)) {
56
+ process.exitCode = 0; // status is informational; don't fail just because expired.
57
+ }
58
+ }
59
+ //# sourceMappingURL=status.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.command.js","sourceRoot":"","sources":["../../../src/commands/auth/status.command.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,12 @@
1
- import { Command } from 'commander';
1
+ /**
2
+ * `bridge auth …` — top-level wiring for the auth command tree.
3
+ *
4
+ * Subcommand modules live in `./auth/*.command.ts`:
5
+ * - `login` (TBP-113): browser-based PKCE auth.
6
+ * - `logout` (TBP-113): revoke + delete credentials.
7
+ * - `status` (TBP-113): show current login state.
8
+ * - `config`/`mfa`/`password-policy`: pre-existing app auth-config commands.
9
+ */
10
+ import type { Command } from 'commander';
2
11
  export declare function registerAuthCommands(program: Command): void;
3
12
  //# sourceMappingURL=auth.command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.command.d.ts","sourceRoot":"","sources":["../../src/commands/auth.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiD3D"}
1
+ {"version":3,"file":"auth.command.d.ts","sourceRoot":"","sources":["../../src/commands/auth.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAY3D"}
@@ -1,58 +1,16 @@
1
- import { getManagementClient } from '../config.js';
2
- import { outputSuccess, outputError } from '../output.js';
1
+ import { registerAuthLoginCommand } from './auth/login.command.js';
2
+ import { registerAuthLogoutCommand } from './auth/logout.command.js';
3
+ import { registerAuthStatusCommand } from './auth/status.command.js';
4
+ import { registerAuthConfigCommands } from './auth/config.command.js';
3
5
  export function registerAuthCommands(program) {
4
- const auth = program.command('auth').description('Manage authentication configuration');
5
- auth.command('config')
6
- .description('Get current auth configuration')
7
- .action(async () => {
8
- try {
9
- const app = await getManagementClient().app.get();
10
- outputSuccess({
11
- mfaEnabled: app.mfaEnabled,
12
- passkeysEnabled: app.passkeysEnabled,
13
- magicLinkEnabled: app.magicLinkEnabled,
14
- googleSsoEnabled: app.googleSsoEnabled,
15
- azureAdSsoEnabled: app.azureAdSsoEnabled,
16
- githubSsoEnabled: app.githubSsoEnabled,
17
- linkedinSsoEnabled: app.linkedinSsoEnabled,
18
- facebookSsoEnabled: app.facebookSsoEnabled,
19
- appleSsoEnabled: app.appleSsoEnabled,
20
- onboardingFlow: app.onboardingFlow,
21
- tenantSelfSignup: app.tenantSelfSignup,
22
- accessTokenTTL: app.accessTokenTTL,
23
- refreshTokenTTL: app.refreshTokenTTL,
24
- });
25
- }
26
- catch (err) {
27
- outputError(err);
28
- }
29
- });
30
- auth.command('mfa')
31
- .description('Enable or disable MFA')
32
- .requiredOption('--enabled <bool>', 'true or false', (v) => v === 'true')
33
- .action(async (opts) => {
34
- try {
35
- outputSuccess(await getManagementClient().app.update({ mfaEnabled: opts.enabled }));
36
- }
37
- catch (err) {
38
- outputError(err);
39
- }
40
- });
41
- auth.command('password-policy')
42
- .description('Update access token TTL')
43
- .option('--access-token-ttl <seconds>', 'Access token TTL in seconds', parseInt)
44
- .option('--refresh-token-ttl <seconds>', 'Refresh token TTL in seconds', parseInt)
45
- .action(async (opts) => {
46
- try {
47
- const data = Object.fromEntries(Object.entries({
48
- accessTokenTTL: opts.accessTokenTtl,
49
- refreshTokenTTL: opts.refreshTokenTtl,
50
- }).filter(([, v]) => v !== undefined));
51
- outputSuccess(await getManagementClient().app.update(data));
52
- }
53
- catch (err) {
54
- outputError(err);
55
- }
56
- });
6
+ const auth = program
7
+ .command('auth')
8
+ .description('Authenticate with Bridge and manage app auth configuration');
9
+ // TBP-113 interactive credentials.
10
+ registerAuthLoginCommand(auth);
11
+ registerAuthLogoutCommand(auth);
12
+ registerAuthStatusCommand(auth);
13
+ // Pre-existing — app-level auth configuration.
14
+ registerAuthConfigCommands(auth);
57
15
  }
58
16
  //# sourceMappingURL=auth.command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.command.js","sourceRoot":"","sources":["../../src/commands/auth.command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE1D,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,qCAAqC,CAAC,CAAC;IAExF,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;SACnB,WAAW,CAAC,gCAAgC,CAAC;SAC7C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,mBAAmB,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;YAClD,aAAa,CAAC;gBACZ,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,eAAe,EAAE,GAAG,CAAC,eAAe;gBACpC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;gBACtC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;gBACtC,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;gBACxC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;gBACtC,kBAAkB,EAAE,GAAG,CAAC,kBAAkB;gBAC1C,kBAAkB,EAAE,GAAG,CAAC,kBAAkB;gBAC1C,eAAe,EAAE,GAAG,CAAC,eAAe;gBACpC,cAAc,EAAE,GAAG,CAAC,cAAc;gBAClC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;gBACtC,cAAc,EAAE,GAAG,CAAC,cAAc;gBAClC,eAAe,EAAE,GAAG,CAAC,eAAe;aACrC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEL,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;SAChB,WAAW,CAAC,uBAAuB,CAAC;SACpC,cAAc,CAAC,kBAAkB,EAAE,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC;SACxE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YAAC,aAAa,CAAC,MAAM,mBAAmB,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAAC,CAAC;QAC5F,OAAO,GAAG,EAAE,CAAC;YAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEL,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC;SAC5B,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CAAC,8BAA8B,EAAE,6BAA6B,EAAE,QAAQ,CAAC;SAC/E,MAAM,CAAC,+BAA+B,EAAE,8BAA8B,EAAE,QAAQ,CAAC;SACjF,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAC7B,MAAM,CAAC,OAAO,CAAC;gBACb,cAAc,EAAE,IAAI,CAAC,cAAc;gBACnC,eAAe,EAAE,IAAI,CAAC,eAAe;aACtC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CACtC,CAAC;YACF,aAAa,CAAC,MAAM,mBAAmB,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"auth.command.js","sourceRoot":"","sources":["../../src/commands/auth.command.ts"],"names":[],"mappings":"AAUA,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,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,+CAA+C;IAC/C,0BAA0B,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { outputSuccess, outputError } from '../output.js';
4
- const GUIDE_BASE_URL = 'https://raw.githubusercontent.com/nebulr-group';
4
+ const GUIDE_BASE_URL = 'https://raw.githubusercontent.com/thebridgedev';
5
5
  const GUIDE_REPOS = {
6
6
  react: 'bridge-react/main',
7
7
  svelte: 'bridge-svelte/main',
@@ -94,7 +94,7 @@ async function fetchGuide(tech, feature) {
94
94
  guideCache.set(cacheKey, { content, fetchedAt: Date.now() });
95
95
  return content;
96
96
  }
97
- const MASTER_PROMPT_GITHUB_URL = 'https://raw.githubusercontent.com/nebulr-group/bridge-cli/main/prompts/master-integration-prompt.md';
97
+ const MASTER_PROMPT_GITHUB_URL = 'https://raw.githubusercontent.com/thebridgedev/bridge-cli/main/bridge-cli/prompts/master-integration-prompt.md';
98
98
  async function fetchMasterPrompt() {
99
99
  // Local override for development
100
100
  const localDir = process.env.BRIDGE_GUIDE_LOCAL_DIR;
@@ -121,7 +121,7 @@ This guide covers integrating Bridge into any language/framework using the REST
121
121
  Bridge issues JWTs signed with PS256. Verify them using your app's JWKS endpoint:
122
122
 
123
123
  \`\`\`
124
- GET https://account-api.thebridge.dev/v1/account/app/.well-known/jwks.json
124
+ GET https://api.thebridge.dev/v1/account/app/.well-known/jwks.json
125
125
  \`\`\`
126
126
 
127
127
  Use a JWT library in your language that supports JWKS auto-refresh:
@@ -144,7 +144,7 @@ The access token contains:
144
144
 
145
145
  Evaluate flags server-side:
146
146
  \`\`\`
147
- POST https://account-api.thebridge.dev/cloud-views/flags/bulkEvaluate/{appId}
147
+ POST https://api.thebridge.dev/cloud-views/flags/bulkEvaluate/{appId}
148
148
  Authorization: Bearer <user-access-token>
149
149
  \`\`\`
150
150
 
@@ -152,7 +152,7 @@ Authorization: Bearer <user-access-token>
152
152
 
153
153
  Use the Bridge REST API with an API token:
154
154
  \`\`\`
155
- GET https://account-api.thebridge.dev/v1/account/tenant
155
+ GET https://api.thebridge.dev/v1/account/tenant
156
156
  x-api-key: <your-api-token>
157
157
  \`\`\`
158
158
 
@@ -1 +1 @@
1
- {"version":3,"file":"guide.command.js","sourceRoot":"","sources":["../../src/commands/guide.command.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"guide.command.js","sourceRoot":"","sources":["../../src/commands/guide.command.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -1,5 +1,29 @@
1
1
  import { BridgeManagement } from '@nebulr-group/bridge-auth-core';
2
+ export declare const DEFAULT_BASE_URL = "https://api.thebridge.dev";
3
+ /**
4
+ * Resolution order:
5
+ * 1. `~/.config/bridge/credentials.json` (or `$XDG_CONFIG_HOME/bridge/credentials.json`)
6
+ * written by `bridge auth login`. The interactive primary path. Token
7
+ * carries the appId baked in by /v1/auth/cli/token, so post-login the
8
+ * JWT is the source of truth for which app the CLI operates on.
9
+ * 2. `BRIDGE_API_KEY` env var (CI / service-account fallback). Used when no
10
+ * credentials file exists — typical CI runner shape.
11
+ * 3. Throw `ConfigError("Not logged in. Run `bridge auth login`.")`.
12
+ *
13
+ * Note: credentials-file wins over env so `bridge auth login` does what users
14
+ * expect — the new login takes effect immediately. CI is unaffected because
15
+ * runners typically have no credentials file and fall through to step 2.
16
+ *
17
+ * If a credentials file exists but its `expiresAt` is in the past, we fall
18
+ * through to env (if set) — same as if there were no file. Otherwise throw a
19
+ * friendly error pointing the user back to `bridge auth login`.
20
+ */
2
21
  export declare function getManagementClient(): BridgeManagement;
22
+ /**
23
+ * For tests and for `bridge auth logout` / `bridge auth status` — they need
24
+ * to reset the cached client between operations.
25
+ */
26
+ export declare function resetManagementClient(): void;
3
27
  export declare function resolveTenantId(opts: {
4
28
  tenantId?: string;
5
29
  }): string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAIlE,wBAAgB,mBAAmB,IAAI,gBAAgB,CAetD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAQnE;AAED,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGlE,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAI5D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CA+CtD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAQnE;AAED,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B"}
package/dist/config.js CHANGED
@@ -1,19 +1,75 @@
1
1
  import { BridgeManagement } from '@nebulr-group/bridge-auth-core';
2
+ import { isExpired, readCredentials } from './credentials.js';
3
+ export const DEFAULT_BASE_URL = 'https://api.thebridge.dev';
2
4
  let _client = null;
5
+ /**
6
+ * Resolution order:
7
+ * 1. `~/.config/bridge/credentials.json` (or `$XDG_CONFIG_HOME/bridge/credentials.json`)
8
+ * written by `bridge auth login`. The interactive primary path. Token
9
+ * carries the appId baked in by /v1/auth/cli/token, so post-login the
10
+ * JWT is the source of truth for which app the CLI operates on.
11
+ * 2. `BRIDGE_API_KEY` env var (CI / service-account fallback). Used when no
12
+ * credentials file exists — typical CI runner shape.
13
+ * 3. Throw `ConfigError("Not logged in. Run `bridge auth login`.")`.
14
+ *
15
+ * Note: credentials-file wins over env so `bridge auth login` does what users
16
+ * expect — the new login takes effect immediately. CI is unaffected because
17
+ * runners typically have no credentials file and fall through to step 2.
18
+ *
19
+ * If a credentials file exists but its `expiresAt` is in the past, we fall
20
+ * through to env (if set) — same as if there were no file. Otherwise throw a
21
+ * friendly error pointing the user back to `bridge auth login`.
22
+ */
3
23
  export function getManagementClient() {
4
24
  if (_client)
5
25
  return _client;
6
- const apiKey = process.env.BRIDGE_API_KEY;
7
- if (!apiKey) {
8
- throw new ConfigError('BRIDGE_API_KEY environment variable is required.');
9
- }
10
- _client = new BridgeManagement({
11
- apiKey,
12
- baseUrl: process.env.BRIDGE_BASE_URL || undefined,
13
- debug: process.env.BRIDGE_DEBUG === 'true',
14
- });
26
+ const debug = process.env.BRIDGE_DEBUG === 'true';
27
+ const envApiKey = process.env.BRIDGE_API_KEY?.trim();
28
+ const envBaseUrl = process.env.BRIDGE_BASE_URL?.trim();
29
+ let apiKey;
30
+ let baseUrl;
31
+ let source;
32
+ // 1. Credentials file from `bridge auth login` (interactive primary).
33
+ const creds = safeReadCredentials();
34
+ if (creds && !isExpired(creds)) {
35
+ apiKey = creds.apiKey;
36
+ // Env override still wins for baseUrl (useful for hitting a local bridge-api
37
+ // with a token issued by prod, or vice versa during dev).
38
+ baseUrl = envBaseUrl && envBaseUrl.length > 0 ? envBaseUrl : creds.baseUrl;
39
+ source = 'credentials-file';
40
+ }
41
+ else if (envApiKey && envApiKey.length > 0) {
42
+ // 2. BRIDGE_API_KEY env var (CI / service-account fallback).
43
+ apiKey = envApiKey;
44
+ baseUrl = envBaseUrl && envBaseUrl.length > 0 ? envBaseUrl : DEFAULT_BASE_URL;
45
+ source = 'env';
46
+ }
47
+ else if (creds && isExpired(creds)) {
48
+ // 3a. Found a credentials file but token expired; no env fallback either.
49
+ throw new ConfigError('Token expired. Run `bridge auth login` to re-authenticate.');
50
+ }
51
+ else {
52
+ // 3b. No credentials at all.
53
+ throw new ConfigError('Not logged in. Run `bridge auth login`.');
54
+ }
55
+ if (debug) {
56
+ const baseSource = envBaseUrl && envBaseUrl.length > 0
57
+ ? 'env'
58
+ : source === 'env'
59
+ ? 'default'
60
+ : 'credentials-file';
61
+ console.error(`[bridge-cli] apiKey=<redacted from ${source}> baseUrl=${baseUrl} (${baseSource})`);
62
+ }
63
+ _client = new BridgeManagement({ apiKey, baseUrl, debug });
15
64
  return _client;
16
65
  }
66
+ /**
67
+ * For tests and for `bridge auth logout` / `bridge auth status` — they need
68
+ * to reset the cached client between operations.
69
+ */
70
+ export function resetManagementClient() {
71
+ _client = null;
72
+ }
17
73
  export function resolveTenantId(opts) {
18
74
  const tenantId = opts.tenantId || process.env.BRIDGE_TENANT_ID;
19
75
  if (!tenantId) {
@@ -27,4 +83,18 @@ export class ConfigError extends Error {
27
83
  this.name = 'ConfigError';
28
84
  }
29
85
  }
86
+ /**
87
+ * Wraps `readCredentials()` so a malformed file produces a `ConfigError` (caught
88
+ * by `outputError`) rather than a raw `Error` stack trace. Returns `null` if
89
+ * the file just doesn't exist (caller decides what to do).
90
+ */
91
+ function safeReadCredentials() {
92
+ try {
93
+ return readCredentials();
94
+ }
95
+ catch (err) {
96
+ throw new ConfigError(`Could not read credentials file: ${err instanceof Error ? err.message : String(err)}\n` +
97
+ 'Run `bridge auth login` to refresh, or delete the file manually.');
98
+ }
99
+ }
30
100
  //# sourceMappingURL=config.js.map