@nebulr-group/bridge-cli 0.6.5 → 1.0.0-alpha.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 +93 -460
- package/dist/api/accounts.d.ts +69 -0
- package/dist/api/accounts.d.ts.map +1 -0
- package/dist/api/accounts.js +42 -0
- package/dist/api/accounts.js.map +1 -0
- package/dist/api/apps.d.ts +50 -0
- package/dist/api/apps.d.ts.map +1 -0
- package/dist/api/apps.js +62 -0
- package/dist/api/apps.js.map +1 -0
- package/dist/api/billing.d.ts +131 -0
- package/dist/api/billing.d.ts.map +1 -0
- package/dist/api/billing.js +42 -0
- package/dist/api/billing.js.map +1 -0
- package/dist/api/flags.d.ts +73 -0
- package/dist/api/flags.d.ts.map +1 -0
- package/dist/api/flags.js +108 -0
- package/dist/api/flags.js.map +1 -0
- package/dist/api/keys.d.ts +48 -0
- package/dist/api/keys.d.ts.map +1 -0
- package/dist/api/keys.js +87 -0
- package/dist/api/keys.js.map +1 -0
- package/dist/auth/browser-open.d.ts +21 -4
- package/dist/auth/browser-open.d.ts.map +1 -1
- package/dist/auth/browser-open.js +45 -65
- package/dist/auth/browser-open.js.map +1 -1
- package/dist/auth/lock.d.ts +8 -0
- package/dist/auth/lock.d.ts.map +1 -0
- package/dist/auth/lock.js +43 -0
- package/dist/auth/lock.js.map +1 -0
- package/dist/auth/loopback.d.ts +8 -12
- package/dist/auth/loopback.d.ts.map +1 -1
- package/dist/auth/loopback.js +40 -45
- package/dist/auth/loopback.js.map +1 -1
- package/dist/auth/session.d.ts +61 -0
- package/dist/auth/session.d.ts.map +1 -0
- package/dist/auth/session.js +142 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/auth/sign-in.d.ts +67 -0
- package/dist/auth/sign-in.d.ts.map +1 -0
- package/dist/auth/sign-in.js +113 -0
- package/dist/auth/sign-in.js.map +1 -0
- package/dist/auth/store.d.ts +89 -0
- package/dist/auth/store.d.ts.map +1 -0
- package/dist/auth/store.js +214 -0
- package/dist/auth/store.js.map +1 -0
- package/dist/bin.js +0 -2
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts +1 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +13 -17
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +31 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +67 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/accounts.command.d.ts +4 -0
- package/dist/commands/accounts.command.d.ts.map +1 -0
- package/dist/commands/accounts.command.js +116 -0
- package/dist/commands/accounts.command.js.map +1 -0
- package/dist/commands/app.command.d.ts +3 -2
- package/dist/commands/app.command.d.ts.map +1 -1
- package/dist/commands/app.command.js +132 -233
- package/dist/commands/app.command.js.map +1 -1
- package/dist/commands/auth.command.d.ts +2 -12
- package/dist/commands/auth.command.d.ts.map +1 -1
- package/dist/commands/auth.command.js +147 -20
- package/dist/commands/auth.command.js.map +1 -1
- package/dist/commands/billing.command.d.ts +4 -0
- package/dist/commands/billing.command.d.ts.map +1 -0
- package/dist/commands/billing.command.js +185 -0
- package/dist/commands/billing.command.js.map +1 -0
- package/dist/commands/check.command.d.ts +2 -1
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +11 -14
- package/dist/commands/check.command.js.map +1 -1
- package/dist/commands/context.d.ts +58 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +78 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/flag.command.d.ts +3 -62
- package/dist/commands/flag.command.d.ts.map +1 -1
- package/dist/commands/flag.command.js +181 -864
- package/dist/commands/flag.command.js.map +1 -1
- package/dist/commands/key.command.d.ts +4 -0
- package/dist/commands/key.command.d.ts.map +1 -0
- package/dist/commands/key.command.js +44 -0
- package/dist/commands/key.command.js.map +1 -0
- package/dist/commands/plan.command.d.ts +3 -203
- package/dist/commands/plan.command.d.ts.map +1 -1
- package/dist/commands/plan.command.js +200 -759
- package/dist/commands/plan.command.js.map +1 -1
- package/dist/config.d.ts +19 -101
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +51 -364
- package/dist/config.js.map +1 -1
- package/dist/core/discovery.d.ts +27 -0
- package/dist/core/discovery.d.ts.map +1 -0
- package/dist/core/discovery.js +97 -0
- package/dist/core/discovery.js.map +1 -0
- package/dist/core/errors.d.ts +26 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +33 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/http.d.ts +23 -0
- package/dist/core/http.d.ts.map +1 -0
- package/dist/core/http.js +153 -0
- package/dist/core/http.js.map +1 -0
- package/dist/core/private-files.d.ts +6 -0
- package/dist/core/private-files.d.ts.map +1 -0
- package/dist/core/private-files.js +96 -0
- package/dist/core/private-files.js.map +1 -0
- package/dist/core/routes.d.ts +94 -0
- package/dist/core/routes.d.ts.map +1 -0
- package/dist/core/routes.js +91 -0
- package/dist/core/routes.js.map +1 -0
- package/dist/core/urls.d.ts +15 -0
- package/dist/core/urls.d.ts.map +1 -0
- package/dist/core/urls.js +55 -0
- package/dist/core/urls.js.map +1 -0
- package/dist/gate-rules.d.ts +1 -2
- package/dist/gate-rules.d.ts.map +1 -1
- package/dist/gate-rules.js +4 -5
- package/dist/gate-rules.js.map +1 -1
- package/dist/index.d.ts +23 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/dist/io.d.ts +21 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +59 -0
- package/dist/io.js.map +1 -0
- package/dist/money.d.ts +42 -0
- package/dist/money.d.ts.map +1 -0
- package/dist/money.js +112 -0
- package/dist/money.js.map +1 -0
- package/dist/program.d.ts +5 -24
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +25 -113
- package/dist/program.js.map +1 -1
- package/package.json +7 -8
- package/dist/auth/api-client.d.ts +0 -50
- package/dist/auth/api-client.d.ts.map +0 -1
- package/dist/auth/api-client.js +0 -109
- package/dist/auth/api-client.js.map +0 -1
- package/dist/auth/relative-time.d.ts +0 -2
- package/dist/auth/relative-time.d.ts.map +0 -1
- package/dist/auth/relative-time.js +0 -27
- package/dist/auth/relative-time.js.map +0 -1
- package/dist/auth/scopes.d.ts +0 -30
- package/dist/auth/scopes.d.ts.map +0 -1
- package/dist/auth/scopes.js +0 -39
- package/dist/auth/scopes.js.map +0 -1
- package/dist/auth/workspace-client.d.ts +0 -70
- package/dist/auth/workspace-client.d.ts.map +0 -1
- package/dist/auth/workspace-client.js +0 -105
- package/dist/auth/workspace-client.js.map +0 -1
- package/dist/commands/auth/config.command.d.ts +0 -8
- package/dist/commands/auth/config.command.d.ts.map +0 -1
- package/dist/commands/auth/config.command.js +0 -60
- package/dist/commands/auth/config.command.js.map +0 -1
- package/dist/commands/auth/login.command.d.ts +0 -46
- package/dist/commands/auth/login.command.d.ts.map +0 -1
- package/dist/commands/auth/login.command.js +0 -166
- package/dist/commands/auth/login.command.js.map +0 -1
- package/dist/commands/auth/logout.command.d.ts +0 -21
- package/dist/commands/auth/logout.command.d.ts.map +0 -1
- package/dist/commands/auth/logout.command.js +0 -97
- package/dist/commands/auth/logout.command.js.map +0 -1
- package/dist/commands/auth/methods.command.d.ts +0 -68
- package/dist/commands/auth/methods.command.d.ts.map +0 -1
- package/dist/commands/auth/methods.command.js +0 -91
- package/dist/commands/auth/methods.command.js.map +0 -1
- package/dist/commands/auth/status.command.d.ts +0 -18
- package/dist/commands/auth/status.command.d.ts.map +0 -1
- package/dist/commands/auth/status.command.js +0 -104
- package/dist/commands/auth/status.command.js.map +0 -1
- package/dist/commands/auth/use.command.d.ts +0 -17
- package/dist/commands/auth/use.command.d.ts.map +0 -1
- package/dist/commands/auth/use.command.js +0 -47
- package/dist/commands/auth/use.command.js.map +0 -1
- package/dist/commands/branding.command.d.ts +0 -3
- package/dist/commands/branding.command.d.ts.map +0 -1
- package/dist/commands/branding.command.js +0 -42
- package/dist/commands/branding.command.js.map +0 -1
- package/dist/commands/event.command.d.ts +0 -3
- package/dist/commands/event.command.d.ts.map +0 -1
- package/dist/commands/event.command.js +0 -27
- package/dist/commands/event.command.js.map +0 -1
- package/dist/commands/flag-init.command.d.ts +0 -13
- package/dist/commands/flag-init.command.d.ts.map +0 -1
- package/dist/commands/flag-init.command.js +0 -463
- package/dist/commands/flag-init.command.js.map +0 -1
- package/dist/commands/guide.command.d.ts +0 -61
- package/dist/commands/guide.command.d.ts.map +0 -1
- package/dist/commands/guide.command.js +0 -655
- package/dist/commands/guide.command.js.map +0 -1
- package/dist/commands/info.command.d.ts +0 -3
- package/dist/commands/info.command.d.ts.map +0 -1
- package/dist/commands/info.command.js +0 -70
- package/dist/commands/info.command.js.map +0 -1
- package/dist/commands/integration.command.d.ts +0 -35
- package/dist/commands/integration.command.d.ts.map +0 -1
- package/dist/commands/integration.command.js +0 -290
- package/dist/commands/integration.command.js.map +0 -1
- package/dist/commands/journeys.d.ts +0 -43
- package/dist/commands/journeys.d.ts.map +0 -1
- package/dist/commands/journeys.js +0 -221
- package/dist/commands/journeys.js.map +0 -1
- package/dist/commands/ops.command.d.ts +0 -17
- package/dist/commands/ops.command.d.ts.map +0 -1
- package/dist/commands/ops.command.js +0 -129
- package/dist/commands/ops.command.js.map +0 -1
- package/dist/commands/privilege.command.d.ts +0 -16
- package/dist/commands/privilege.command.d.ts.map +0 -1
- package/dist/commands/privilege.command.js +0 -86
- package/dist/commands/privilege.command.js.map +0 -1
- package/dist/commands/role.command.d.ts +0 -3
- package/dist/commands/role.command.d.ts.map +0 -1
- package/dist/commands/role.command.js +0 -101
- package/dist/commands/role.command.js.map +0 -1
- package/dist/commands/runtime-dir.d.ts +0 -16
- package/dist/commands/runtime-dir.d.ts.map +0 -1
- package/dist/commands/runtime-dir.js +0 -18
- package/dist/commands/runtime-dir.js.map +0 -1
- package/dist/commands/setup.command.d.ts +0 -63
- package/dist/commands/setup.command.d.ts.map +0 -1
- package/dist/commands/setup.command.js +0 -148
- package/dist/commands/setup.command.js.map +0 -1
- package/dist/commands/stripe.command.d.ts +0 -29
- package/dist/commands/stripe.command.d.ts.map +0 -1
- package/dist/commands/stripe.command.js +0 -99
- package/dist/commands/stripe.command.js.map +0 -1
- package/dist/commands/tenant.command.d.ts +0 -3
- package/dist/commands/tenant.command.d.ts.map +0 -1
- package/dist/commands/tenant.command.js +0 -135
- package/dist/commands/tenant.command.js.map +0 -1
- package/dist/commands/token.command.d.ts +0 -3
- package/dist/commands/token.command.d.ts.map +0 -1
- package/dist/commands/token.command.js +0 -54
- package/dist/commands/token.command.js.map +0 -1
- package/dist/commands/user.command.d.ts +0 -3
- package/dist/commands/user.command.d.ts.map +0 -1
- package/dist/commands/user.command.js +0 -117
- package/dist/commands/user.command.js.map +0 -1
- package/dist/credentials.d.ts +0 -141
- package/dist/credentials.d.ts.map +0 -1
- package/dist/credentials.js +0 -348
- package/dist/credentials.js.map +0 -1
- package/dist/flag-coherence.d.ts +0 -42
- package/dist/flag-coherence.d.ts.map +0 -1
- package/dist/flag-coherence.js +0 -103
- package/dist/flag-coherence.js.map +0 -1
- package/dist/output.d.ts +0 -17
- package/dist/output.d.ts.map +0 -1
- package/dist/output.js +0 -107
- package/dist/output.js.map +0 -1
- package/dist/preview.d.ts +0 -9
- package/dist/preview.d.ts.map +0 -1
- package/dist/preview.js +0 -63
- package/dist/preview.js.map +0 -1
- package/dist/product-decisions.d.ts +0 -40
- package/dist/product-decisions.d.ts.map +0 -1
- package/dist/product-decisions.js +0 -52
- package/dist/product-decisions.js.map +0 -1
- package/dist/prompt-urls.d.ts +0 -31
- package/dist/prompt-urls.d.ts.map +0 -1
- package/dist/prompt-urls.js +0 -35
- package/dist/prompt-urls.js.map +0 -1
- package/dist/prompts/auth-master-integration-prompt.md +0 -255
- package/dist/prompts/billing/master.md +0 -332
- package/dist/prompts/decisions/feature-control.md +0 -131
- package/dist/prompts/decisions/going-live.md +0 -60
- package/dist/prompts/decisions/login.md +0 -71
- package/dist/prompts/decisions/look-and-feel.md +0 -68
- package/dist/prompts/decisions/payments.md +0 -97
- package/dist/prompts/decisions/roles.md +0 -78
- package/dist/prompts/decisions/teams.md +0 -61
- package/dist/prompts/fit-together.md +0 -97
- package/dist/prompts/flags/master.md +0 -220
- package/dist/prompts/guide-coverage.json +0 -17
- package/dist/prompts/integration-success.md +0 -106
- package/dist/prompts/mcp-tools.json +0 -90
- package/dist/prompts/mechanisms.md +0 -298
- package/dist/prompts/orientation.md +0 -42
- package/dist/prompts/product-decisions.json +0 -338
- package/dist/resolve.d.ts +0 -110
- package/dist/resolve.d.ts.map +0 -1
- package/dist/resolve.js +0 -260
- package/dist/resolve.js.map +0 -1
- package/dist/shape.d.ts +0 -25
- package/dist/shape.d.ts.map +0 -1
- package/dist/shape.js +0 -74
- package/dist/shape.js.map +0 -1
package/dist/config.js
CHANGED
|
@@ -1,376 +1,63 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Resolution order:
|
|
29
|
-
* 1. `--profile <label|id|name>` / `BRIDGE_PROFILE` — a stored credential,
|
|
30
|
-
* named for this one invocation. Never falls back: naming a profile and
|
|
31
|
-
* silently getting a different app is the exact failure TBP-628 exists to
|
|
32
|
-
* stop, so an unknown or expired profile is an error.
|
|
33
|
-
* 2. The ACTIVE credential in `~/.config/bridge/credentials.json` (or
|
|
34
|
-
* `$XDG_CONFIG_HOME/...`), written by `bridge auth login` and moved by
|
|
35
|
-
* `bridge auth use`.
|
|
36
|
-
* 3. `BRIDGE_API_KEY` env var (CI / service-account fallback). Used when no
|
|
37
|
-
* usable credentials file exists — the typical CI runner shape.
|
|
38
|
-
* 4. Throw `ConfigError("Not logged in. Run `bridge auth login`.")`.
|
|
39
|
-
*
|
|
40
|
-
* The credentials file still wins over `BRIDGE_API_KEY`, unchanged, so
|
|
41
|
-
* `bridge auth login` takes effect immediately and CI is unaffected. What HAS
|
|
42
|
-
* changed is that being ignored is now said out loud: `BRIDGE_API_KEY` and
|
|
43
|
-
* `BRIDGE_APP_ID` look like a way to retarget the CLI and are not, and reading
|
|
44
|
-
* that in the output beats discovering it from a write that went to the wrong
|
|
45
|
-
* app (TBP-628).
|
|
46
|
-
*
|
|
47
|
-
* Every resolution also prints one line to stderr naming the app that is about
|
|
48
|
-
* to answer. See `writeContextBanner`.
|
|
49
|
-
*/
|
|
50
|
-
export function getManagementClient() {
|
|
51
|
-
if (_client)
|
|
52
|
-
return _client;
|
|
53
|
-
const debug = process.env.BRIDGE_DEBUG === 'true';
|
|
54
|
-
const envBaseUrl = process.env.BRIDGE_BASE_URL?.trim();
|
|
55
|
-
const selected = resolveSelectedCredential();
|
|
56
|
-
const { creds, source, selector, baseUrl } = selected;
|
|
57
|
-
// TBP-769 — a workspace login acting on another app swaps in that app's
|
|
58
|
-
// short-lived token, fetched by `prepareAppContext()` before the action ran.
|
|
59
|
-
const apiKey = _appContext ? _appContext.apiKey : selected.apiKey;
|
|
60
|
-
writeContextBanner({ creds, source, baseUrl, selector, appContext: _appContext });
|
|
61
|
-
if (debug) {
|
|
62
|
-
const baseSource = envBaseUrl && envBaseUrl.length > 0
|
|
63
|
-
? 'env'
|
|
64
|
-
: source === 'env'
|
|
65
|
-
? 'default'
|
|
66
|
-
: 'credentials-file';
|
|
67
|
-
console.error(`[bridge-cli] apiKey=<redacted from ${source}> baseUrl=${baseUrl} (${baseSource})`);
|
|
68
|
-
}
|
|
69
|
-
_client = new BridgeManagement({ apiKey, baseUrl, debug });
|
|
70
|
-
_baseUrl = baseUrl;
|
|
71
|
-
_apiKey = apiKey;
|
|
72
|
-
return _client;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* WHICH login is in force, per the resolution order documented on
|
|
76
|
-
* `getManagementClient()`. Throws `ConfigError` exactly as it always has.
|
|
77
|
-
* Offline; prints nothing.
|
|
78
|
-
*/
|
|
79
|
-
export function resolveSelectedCredential() {
|
|
80
|
-
const envApiKey = process.env.BRIDGE_API_KEY?.trim();
|
|
81
|
-
const envBaseUrl = process.env.BRIDGE_BASE_URL?.trim();
|
|
82
|
-
const withBase = (fallback) => envBaseUrl && envBaseUrl.length > 0 ? envBaseUrl : fallback;
|
|
83
|
-
const selector = activeProfileSelector();
|
|
84
|
-
if (selector) {
|
|
85
|
-
// 1. Explicit profile. Resolve it or fail — no fallback of any kind.
|
|
86
|
-
let entry;
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { CliError } from './core/errors.js';
|
|
4
|
+
import { readPrivateFile, writePrivateFile } from './core/private-files.js';
|
|
5
|
+
import { normalizeIssuer } from './core/urls.js';
|
|
6
|
+
export function configDir(env, platform = process.platform) {
|
|
7
|
+
const given = env['BRIDGE_CONFIG_DIR']?.trim();
|
|
8
|
+
if (given)
|
|
9
|
+
return given;
|
|
10
|
+
if (platform === 'win32' && env['APPDATA'])
|
|
11
|
+
return join(env['APPDATA'], 'bridge', 'v1');
|
|
12
|
+
const xdg = env['XDG_CONFIG_HOME']?.trim();
|
|
13
|
+
if (xdg)
|
|
14
|
+
return join(xdg, 'bridge', 'v1');
|
|
15
|
+
const home = env['HOME']?.trim() || homedir();
|
|
16
|
+
return join(home, '.config', 'bridge', 'v1');
|
|
17
|
+
}
|
|
18
|
+
export class Config {
|
|
19
|
+
dir;
|
|
20
|
+
constructor(dir) {
|
|
21
|
+
this.dir = dir;
|
|
22
|
+
}
|
|
23
|
+
async read() {
|
|
24
|
+
const raw = await readPrivateFile(this.dir, FILE);
|
|
25
|
+
if (raw === null)
|
|
26
|
+
return {};
|
|
87
27
|
try {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
catch (err) {
|
|
91
|
-
if (err instanceof CredentialSelectorError)
|
|
92
|
-
throw new ConfigError(err.message);
|
|
93
|
-
throw err;
|
|
28
|
+
const parsed = JSON.parse(raw);
|
|
29
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : {};
|
|
94
30
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
`${entry.creds.expiresAt}. Run \`bridge auth login\` to re-authenticate it. ` +
|
|
98
|
-
'Refusing to fall back to another app.');
|
|
31
|
+
catch {
|
|
32
|
+
return {};
|
|
99
33
|
}
|
|
100
|
-
return {
|
|
101
|
-
key: entry.key,
|
|
102
|
-
creds: entry.creds,
|
|
103
|
-
apiKey: entry.creds.apiKey,
|
|
104
|
-
baseUrl: withBase(entry.creds.baseUrl),
|
|
105
|
-
source: 'profile',
|
|
106
|
-
selector,
|
|
107
|
-
};
|
|
108
34
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
key: active.app.id,
|
|
116
|
-
creds: active,
|
|
117
|
-
apiKey: active.apiKey,
|
|
118
|
-
baseUrl: withBase(active.baseUrl),
|
|
119
|
-
source: 'credentials-file',
|
|
120
|
-
selector: null,
|
|
121
|
-
};
|
|
35
|
+
async update(change) {
|
|
36
|
+
const settings = await this.read();
|
|
37
|
+
change(settings);
|
|
38
|
+
await writePrivateFile(this.dir, FILE, JSON.stringify(settings, null, 2) + '\n');
|
|
39
|
+
return settings;
|
|
122
40
|
}
|
|
123
|
-
if (envApiKey && envApiKey.length > 0) {
|
|
124
|
-
// 3. BRIDGE_API_KEY env var (CI / service-account fallback).
|
|
125
|
-
return {
|
|
126
|
-
key: null,
|
|
127
|
-
creds: null,
|
|
128
|
-
apiKey: envApiKey,
|
|
129
|
-
baseUrl: withBase(DEFAULT_BASE_URL),
|
|
130
|
-
source: 'env',
|
|
131
|
-
selector: null,
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
if (active && isExpired(active)) {
|
|
135
|
-
// 4a. Found a credentials file but token expired; no env fallback either.
|
|
136
|
-
throw new ConfigError('Token expired. Run `bridge auth login` to re-authenticate.');
|
|
137
|
-
}
|
|
138
|
-
// 4b. No credentials at all.
|
|
139
|
-
throw new ConfigError('Not logged in. Run `bridge auth login`.');
|
|
140
|
-
}
|
|
141
|
-
let _appFlag = null;
|
|
142
|
-
let _appContext = null;
|
|
143
|
-
/** Per-app tokens, in memory for this process only. Never written to disk. */
|
|
144
|
-
const _appTokenCache = new Map();
|
|
145
|
-
/** The global `--app` value for this invocation, set by the preAction hook. */
|
|
146
|
-
export function setAppOverride(app) {
|
|
147
|
-
_appFlag = app?.trim() || null;
|
|
148
|
-
}
|
|
149
|
-
/** The app the NEXT management client will act on (workspace logins only). */
|
|
150
|
-
export function getAppContext() {
|
|
151
|
-
return _appContext;
|
|
152
41
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
*
|
|
161
|
-
* Precedence: `--app` > the credential's `currentApp` (`bridge app use`) > home.
|
|
162
|
-
* A workspace login calls the token route for every target, the home app
|
|
163
|
-
* included, so the server re-checks access each time. Single-app logins and `BRIDGE_API_KEY` behave exactly as
|
|
164
|
-
* before; asking them for another app is an error that says how to fix it.
|
|
165
|
-
*/
|
|
166
|
-
export async function prepareAppContext(fetchImpl) {
|
|
167
|
-
_appContext = null;
|
|
168
|
-
_client = null;
|
|
169
|
-
_http = null;
|
|
170
|
-
let selected;
|
|
171
|
-
try {
|
|
172
|
-
selected = resolveSelectedCredential();
|
|
173
|
-
}
|
|
174
|
-
catch (err) {
|
|
175
|
-
// Without --app, leave "not logged in" etc. to the command, as before.
|
|
176
|
-
if (!_appFlag)
|
|
177
|
-
return;
|
|
178
|
-
throw err;
|
|
179
|
-
}
|
|
180
|
-
if (selected.source === 'env' || !selected.creds || !selected.key) {
|
|
181
|
-
if (_appFlag) {
|
|
182
|
-
throw new ConfigError('--app needs a workspace login from `bridge auth login`. ' +
|
|
183
|
-
'BRIDGE_API_KEY is bound to the one app it was issued for.');
|
|
184
|
-
}
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
const creds = selected.creds;
|
|
188
|
-
const target = _appFlag ?? creds.currentApp?.id ?? null;
|
|
189
|
-
if (creds.appAccess !== 'workspace') {
|
|
190
|
-
// Single-app login: unchanged, no extra call — its token IS its one app.
|
|
191
|
-
if (!target || isHomeSelector(target, creds.app))
|
|
192
|
-
return;
|
|
193
|
-
// A stray currentApp on a single-app login cannot be honoured; ignore it
|
|
194
|
-
// rather than fail every command. An explicit --app is a request: refuse.
|
|
195
|
-
if (!_appFlag)
|
|
196
|
-
return;
|
|
197
|
-
throw Object.assign(new ConfigError(`This login covers only the app ${creds.app.name} (${creds.app.id}), so --app ${_appFlag} is not available.`), {
|
|
198
|
-
hint: 'Run `bridge auth login` again and choose "Every app in <workspace>" on the consent ' +
|
|
199
|
-
'screen to work across apps with one login.',
|
|
42
|
+
const FILE = 'config.json';
|
|
43
|
+
/** The issuer: `--issuer`, else `BRIDGE_ISSUER`, else the one saved at sign-in. */
|
|
44
|
+
export function resolveIssuer(flag, env, settings) {
|
|
45
|
+
const given = flag ?? env['BRIDGE_ISSUER'] ?? settings.issuer;
|
|
46
|
+
if (given === undefined || given.trim() === '') {
|
|
47
|
+
throw new CliError('misconfigured', 'No issuer is set.', {
|
|
48
|
+
hint: 'Sign in with `bridge auth login --issuer <the Bridge App\'s issuer>`, or set BRIDGE_ISSUER.',
|
|
200
49
|
});
|
|
201
50
|
}
|
|
202
|
-
|
|
203
|
-
baseUrl: selected.baseUrl,
|
|
204
|
-
loginToken: creds.apiKey,
|
|
205
|
-
fetchImpl,
|
|
206
|
-
});
|
|
207
|
-
// A workspace login re-checks access on EVERY command, home app included
|
|
208
|
-
// (the server answers the home app with the login token itself, after the
|
|
209
|
-
// check) — same as the MCP server.
|
|
210
|
-
let targetId;
|
|
211
|
-
if (!target || isHomeSelector(target, creds.app)) {
|
|
212
|
-
targetId = creds.app.id;
|
|
213
|
-
}
|
|
214
|
-
else if (looksLikeAppId(target)) {
|
|
215
|
-
targetId = target;
|
|
216
|
-
}
|
|
217
|
-
else if (creds.currentApp && target.toLowerCase() === creds.currentApp.name.toLowerCase()) {
|
|
218
|
-
targetId = creds.currentApp.id;
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
const { apps } = await client.listApps();
|
|
222
|
-
targetId = resolveAppSelector(target, apps).id;
|
|
223
|
-
}
|
|
224
|
-
const cacheKey = `${selected.key}:${targetId}`;
|
|
225
|
-
const cached = _appTokenCache.get(cacheKey);
|
|
226
|
-
let token;
|
|
227
|
-
if (cached && cached.expiresAt - Date.now() > 15_000) {
|
|
228
|
-
token = cached;
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
const res = await client.appToken(targetId);
|
|
232
|
-
const exp = Date.parse(res.expiresAt);
|
|
233
|
-
_appTokenCache.set(cacheKey, {
|
|
234
|
-
apiKey: res.apiKey,
|
|
235
|
-
app: res.app,
|
|
236
|
-
expiresAt: Number.isNaN(exp) ? Date.now() + 60_000 : exp,
|
|
237
|
-
});
|
|
238
|
-
token = res;
|
|
239
|
-
}
|
|
240
|
-
_appContext = {
|
|
241
|
-
apiKey: token.apiKey,
|
|
242
|
-
app: token.app,
|
|
243
|
-
via: _appFlag ? `--app ${_appFlag}` : 'current app (bridge app use)',
|
|
244
|
-
home: targetId === creds.app.id,
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
/** For tests: forget --app, the chosen app and every cached per-app token. */
|
|
248
|
-
export function resetAppContext() {
|
|
249
|
-
_appFlag = null;
|
|
250
|
-
_appContext = null;
|
|
251
|
-
_appTokenCache.clear();
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* One line on stderr naming the app that is about to answer.
|
|
255
|
-
*
|
|
256
|
-
* On EVERY command, not only writes. The incident behind TBP-628 started with a
|
|
257
|
-
* read: `bridge role list` was believed to describe the local app and described
|
|
258
|
-
* production, and nothing in the output said otherwise. A banner that only
|
|
259
|
-
* appears on writes would not have prevented it, because the wrong belief was
|
|
260
|
-
* already formed by then.
|
|
261
|
-
*
|
|
262
|
-
* stderr, so stdout stays pure JSON for the agents and scripts that parse it.
|
|
263
|
-
* Suppress with `BRIDGE_NO_BANNER=true` — for the one caller who is already
|
|
264
|
-
* certain and is merging the two streams.
|
|
265
|
-
*/
|
|
266
|
-
function writeContextBanner(ctx) {
|
|
267
|
-
const { creds, source, baseUrl, selector, appContext } = ctx;
|
|
268
|
-
// TBP-769 — acting on an app other than the login's home app is said out
|
|
269
|
-
// loud even with BRIDGE_NO_BANNER: it is the one case where the credential
|
|
270
|
-
// on disk does not name the app that is about to answer.
|
|
271
|
-
if (appContext && !appContext.home) {
|
|
272
|
-
const home = creds ? `${creds.label ?? creds.app.name} (${creds.app.id})` : 'login';
|
|
273
|
-
process.stderr.write(`bridge: Acting on app ${appContext.app.name} (${appContext.app.id}) · ${baseUrl} · ` +
|
|
274
|
-
`via ${appContext.via}, workspace login ${home}\n`);
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
if (process.env.BRIDGE_NO_BANNER === 'true')
|
|
278
|
-
return;
|
|
279
|
-
const who = creds
|
|
280
|
-
? `${creds.label ?? creds.app.name} (${creds.app.id})`
|
|
281
|
-
: 'BRIDGE_API_KEY (app unknown — the key carries it)';
|
|
282
|
-
const via = source === 'profile'
|
|
283
|
-
? `--profile ${selector}`
|
|
284
|
-
: source === 'env'
|
|
285
|
-
? 'BRIDGE_API_KEY'
|
|
286
|
-
: 'saved default';
|
|
287
|
-
process.stderr.write(`bridge: ${who} · ${baseUrl} · via ${via}\n`);
|
|
288
|
-
// The two env vars that look like a way to retarget the CLI and are not.
|
|
289
|
-
// Saying so here, at the moment they are being ignored, is the whole point:
|
|
290
|
-
// the reported incident was a session that set them and believed them.
|
|
291
|
-
if (source !== 'env' && process.env.BRIDGE_API_KEY?.trim()) {
|
|
292
|
-
process.stderr.write('bridge: BRIDGE_API_KEY is set but IGNORED — the credentials file wins. ' +
|
|
293
|
-
'Use `--profile <label>` to pick a stored login, `--app` to pick an app within it, ' +
|
|
294
|
-
'or `bridge auth logout` to use the key.\n');
|
|
295
|
-
}
|
|
296
|
-
if (process.env.BRIDGE_APP_ID?.trim()) {
|
|
297
|
-
process.stderr.write('bridge: BRIDGE_APP_ID has no effect — the app is carried by the credential itself. ' +
|
|
298
|
-
'Use `--app <id|name>` (workspace login) or `--profile <label|app id>` to target another app.\n');
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* The Bridge API base URL the management client talks to, resolved exactly as
|
|
303
|
-
* `getManagementClient()` resolves it: `--profile`, then the active credential,
|
|
304
|
-
* then `BRIDGE_API_KEY`, with `BRIDGE_BASE_URL` overriding each.
|
|
305
|
-
*
|
|
306
|
-
* Anything the CLI writes into a project (`bridge flag init`) takes its base
|
|
307
|
-
* URL from here, so a project is wired to the environment the command just
|
|
308
|
-
* read the app from. Re-reading the credentials file instead ignored
|
|
309
|
-
* `--profile` and `BRIDGE_BASE_URL`, and wrote production into a project
|
|
310
|
-
* scaffolded against stage (TBP-708).
|
|
311
|
-
*/
|
|
312
|
-
export function getResolvedBaseUrl() {
|
|
313
|
-
getManagementClient();
|
|
314
|
-
return _baseUrl;
|
|
51
|
+
return normalizeIssuer(given);
|
|
315
52
|
}
|
|
316
|
-
/**
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
*/
|
|
324
|
-
export function getManagementHttp() {
|
|
325
|
-
if (_http)
|
|
326
|
-
return _http;
|
|
327
|
-
getManagementClient();
|
|
328
|
-
const debug = process.env.BRIDGE_DEBUG === 'true';
|
|
329
|
-
const quiet = () => undefined;
|
|
330
|
-
const logger = {
|
|
331
|
-
debug: debug ? (...a) => console.error('[bridge-cli]', ...a) : quiet,
|
|
332
|
-
warn: debug ? (...a) => console.error('[bridge-cli]', ...a) : quiet,
|
|
333
|
-
error: debug ? (...a) => console.error('[bridge-cli]', ...a) : quiet,
|
|
334
|
-
};
|
|
335
|
-
_http = new ManagementHttpClient(_baseUrl, _apiKey, logger);
|
|
336
|
-
return _http;
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* For tests and for `bridge auth logout` / `bridge auth status` — they need
|
|
340
|
-
* to reset the cached client between operations.
|
|
341
|
-
*/
|
|
342
|
-
export function resetManagementClient() {
|
|
343
|
-
_appContext = null;
|
|
344
|
-
_client = null;
|
|
345
|
-
_baseUrl = null;
|
|
346
|
-
_apiKey = null;
|
|
347
|
-
_http = null;
|
|
348
|
-
}
|
|
349
|
-
export function resolveTenantId(opts) {
|
|
350
|
-
const tenantId = opts.tenantId || process.env.BRIDGE_TENANT_ID;
|
|
351
|
-
if (!tenantId) {
|
|
352
|
-
throw new ConfigError('Tenant context required. Set BRIDGE_TENANT_ID environment variable or use --tenant-id flag.');
|
|
353
|
-
}
|
|
354
|
-
return tenantId;
|
|
355
|
-
}
|
|
356
|
-
export class ConfigError extends Error {
|
|
357
|
-
constructor(message) {
|
|
358
|
-
super(message);
|
|
359
|
-
this.name = 'ConfigError';
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* Wraps `readCredentials()` so a malformed file produces a `ConfigError` (caught
|
|
364
|
-
* by `outputError`) rather than a raw `Error` stack trace. Returns `null` if
|
|
365
|
-
* the file just doesn't exist (caller decides what to do).
|
|
366
|
-
*/
|
|
367
|
-
function safeReadCredentials() {
|
|
368
|
-
try {
|
|
369
|
-
return readCredentials();
|
|
370
|
-
}
|
|
371
|
-
catch (err) {
|
|
372
|
-
throw new ConfigError(`Could not read credentials file: ${err instanceof Error ? err.message : String(err)}\n` +
|
|
373
|
-
'Run `bridge auth login` to refresh, or delete the file manually.');
|
|
53
|
+
/** The app commands act on: `--app`, else `BRIDGE_APP`, else the one chosen with `bridge app use`. */
|
|
54
|
+
export function resolveApp(flag, env, settings, issuer) {
|
|
55
|
+
const given = flag ?? env['BRIDGE_APP'] ?? settings.apps?.[issuer];
|
|
56
|
+
if (given === undefined || given.trim() === '') {
|
|
57
|
+
throw new CliError('misconfigured', 'No app is chosen.', {
|
|
58
|
+
hint: 'Choose one with `bridge app use <id>`, pass `--app <id>`, or create one with `bridge app create --name <name>`.',
|
|
59
|
+
});
|
|
374
60
|
}
|
|
61
|
+
return given.trim();
|
|
375
62
|
}
|
|
376
63
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type Fetch } from './http.js';
|
|
2
|
+
import { type Service } from './routes.js';
|
|
3
|
+
/**
|
|
4
|
+
* Discovery: the issuer is the only address the CLI is given. Everything else
|
|
5
|
+
* comes from the issuer's metadata at `<issuer>/.well-known/openid-configuration`
|
|
6
|
+
* (RFC 8414), which lists each version's endpoints under `bridge_endpoints`.
|
|
7
|
+
* The CLI reads version 2 only, so a newer version never changes what it calls.
|
|
8
|
+
*/
|
|
9
|
+
export interface Discovery {
|
|
10
|
+
readonly issuer: string;
|
|
11
|
+
/** The app the issuer signs in to: the Bridge App, for the developer. */
|
|
12
|
+
readonly appId: string;
|
|
13
|
+
readonly signIn: string;
|
|
14
|
+
readonly token: string;
|
|
15
|
+
readonly revoke: string;
|
|
16
|
+
readonly signOut: string | null;
|
|
17
|
+
/** Bridge's own sign-in page for programs on this machine, when the issuer lists one. */
|
|
18
|
+
readonly signInPage: string | null;
|
|
19
|
+
/** Each microservice's base address at version 2. */
|
|
20
|
+
readonly bases: Readonly<Record<Service, string>>;
|
|
21
|
+
}
|
|
22
|
+
export declare function metadataUrl(issuer: string): string;
|
|
23
|
+
/** Reads the metadata document into the endpoints the CLI calls. Exposed for tests. */
|
|
24
|
+
export declare function readMetadata(issuer: string, document: unknown): Discovery;
|
|
25
|
+
/** Fetches and reads the issuer's metadata. */
|
|
26
|
+
export declare function discover(fetchFn: Fetch, issuer: string): Promise<Discovery>;
|
|
27
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/core/discovery.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAGxD;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,yFAAyF;IACzF,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAiCD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,SAAS,CA8CzE;AAED,+CAA+C;AAC/C,wBAAsB,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAWjF"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { CliError } from './errors.js';
|
|
2
|
+
import { call } from './http.js';
|
|
3
|
+
import { API_VERSION } from './routes.js';
|
|
4
|
+
import { secureUrl } from './urls.js';
|
|
5
|
+
/** The standard fields an issuer at version 2 may list instead of `bridge_endpoints["2"]`. */
|
|
6
|
+
const STANDARD_FIELDS = {
|
|
7
|
+
sign_in: 'authorization_challenge_endpoint',
|
|
8
|
+
token: 'token_endpoint',
|
|
9
|
+
revoke: 'revocation_endpoint',
|
|
10
|
+
};
|
|
11
|
+
function misconfigured(message) {
|
|
12
|
+
return new CliError('misconfigured', message, {
|
|
13
|
+
hint: 'Check the issuer: it is the Bridge App\'s issuer, as Bridge publishes it.',
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function listed(value, name) {
|
|
17
|
+
if (value === undefined || value === null)
|
|
18
|
+
return null;
|
|
19
|
+
const url = secureUrl(value);
|
|
20
|
+
if (url === null)
|
|
21
|
+
throw misconfigured(`The issuer's metadata lists "${name}" at an address that is not https: ${String(value)}`);
|
|
22
|
+
return url.toString().replace(/\/+$/, '');
|
|
23
|
+
}
|
|
24
|
+
function required(value, name) {
|
|
25
|
+
if (value === null)
|
|
26
|
+
throw misconfigured(`The issuer's metadata lists no "${name}" endpoint.`);
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
/** The address of a microservice's base, from a listed address under it: `<base>/<service>/…` gives `<base>/<service>`. */
|
|
30
|
+
function baseFrom(address, suffix) {
|
|
31
|
+
if (address === null || !address.endsWith(suffix))
|
|
32
|
+
return null;
|
|
33
|
+
return address.slice(0, -suffix.length);
|
|
34
|
+
}
|
|
35
|
+
export function metadataUrl(issuer) {
|
|
36
|
+
return `${issuer}/.well-known/openid-configuration`;
|
|
37
|
+
}
|
|
38
|
+
/** Reads the metadata document into the endpoints the CLI calls. Exposed for tests. */
|
|
39
|
+
export function readMetadata(issuer, document) {
|
|
40
|
+
if (typeof document !== 'object' || document === null || Array.isArray(document)) {
|
|
41
|
+
throw misconfigured('The issuer\'s metadata is not a JSON object.');
|
|
42
|
+
}
|
|
43
|
+
const meta = document;
|
|
44
|
+
if (meta['issuer'] !== issuer) {
|
|
45
|
+
throw misconfigured(`The metadata names another issuer (${String(meta['issuer'])}) than the one asked for (${issuer}).`);
|
|
46
|
+
}
|
|
47
|
+
const appId = meta['bridge_app'];
|
|
48
|
+
if (typeof appId !== 'string' || appId === '')
|
|
49
|
+
throw misconfigured('The issuer\'s metadata does not name its app (bridge_app).');
|
|
50
|
+
const all = meta['bridge_endpoints'];
|
|
51
|
+
const byVersion = typeof all === 'object' && all !== null ? all[String(API_VERSION)] : undefined;
|
|
52
|
+
const v2 = typeof byVersion === 'object' && byVersion !== null ? byVersion : null;
|
|
53
|
+
// Without version 2's own list, the standard fields are read only from an issuer that says it is at version 2.
|
|
54
|
+
if (v2 === null && meta['bridge_api_version'] !== API_VERSION) {
|
|
55
|
+
throw misconfigured(`The issuer does not offer version ${String(API_VERSION)} of Bridge's API, which this CLI uses.`);
|
|
56
|
+
}
|
|
57
|
+
const endpoint = (name) => required(listed(v2?.[name], name) ?? (meta['bridge_api_version'] === API_VERSION ? listed(meta[STANDARD_FIELDS[name]], STANDARD_FIELDS[name]) : null), name);
|
|
58
|
+
const accounts = listed(v2?.['accounts'], 'accounts');
|
|
59
|
+
const billing = listed(v2?.['billing'], 'billing');
|
|
60
|
+
const flags = listed(v2?.['flags'], 'flags');
|
|
61
|
+
const sessions = listed(v2?.['sessions'], 'sessions');
|
|
62
|
+
const signOut = listed(v2?.['sign_out'], 'sign_out');
|
|
63
|
+
// Listed by name when the issuer lists them; else found next to the ones it lists.
|
|
64
|
+
const identityAccess = listed(v2?.['identity_access'], 'identity_access') ?? baseFrom(sessions, '/sessions') ?? baseFrom(signOut, '/sign-out');
|
|
65
|
+
const appRegistry = listed(v2?.['app_registry'], 'app_registry') ?? (baseFrom(accounts, '/accounts') === null ? null : `${baseFrom(accounts, '/accounts')}/app-registry`);
|
|
66
|
+
return {
|
|
67
|
+
issuer,
|
|
68
|
+
appId,
|
|
69
|
+
signIn: endpoint('sign_in'),
|
|
70
|
+
token: endpoint('token'),
|
|
71
|
+
revoke: endpoint('revoke'),
|
|
72
|
+
signOut,
|
|
73
|
+
signInPage: listed(v2?.['sign_in_page'], 'sign_in_page') ?? listed(meta['authorization_endpoint'], 'authorization_endpoint'),
|
|
74
|
+
bases: {
|
|
75
|
+
'app-registry': required(appRegistry, 'app_registry'),
|
|
76
|
+
'identity-access': required(identityAccess, 'identity_access'),
|
|
77
|
+
billing: required(billing, 'billing'),
|
|
78
|
+
flags: required(flags, 'flags'),
|
|
79
|
+
accounts: required(accounts, 'accounts'),
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Fetches and reads the issuer's metadata. */
|
|
84
|
+
export async function discover(fetchFn, issuer) {
|
|
85
|
+
let body;
|
|
86
|
+
try {
|
|
87
|
+
({ body } = await call(fetchFn, { method: 'GET', url: metadataUrl(issuer) }));
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (error instanceof CliError && (error.kind === 'not-found' || error.kind === 'invalid')) {
|
|
91
|
+
throw misconfigured(`No Bridge issuer answers at ${issuer}.`);
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
return readMetadata(issuer, body);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/core/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one error type every command reports. `kind` says what went wrong in
|
|
3
|
+
* words a script can branch on; `hint` says what to do next.
|
|
4
|
+
*/
|
|
5
|
+
export type CliErrorKind = 'not-signed-in' | 'session-ended' | 'reauthenticate' | 'wrong-credentials' | 'flow-expired' | 'unsupported-step' | 'cancelled' | 'forbidden' | 'plan-required' | 'not-found' | 'conflict' | 'invalid' | 'rate-limited' | 'unavailable' | 'network' | 'not-offered' | 'misconfigured';
|
|
6
|
+
export interface CliErrorOptions {
|
|
7
|
+
readonly status?: number;
|
|
8
|
+
readonly hint?: string;
|
|
9
|
+
readonly details?: unknown;
|
|
10
|
+
}
|
|
11
|
+
export declare class CliError extends Error {
|
|
12
|
+
readonly kind: CliErrorKind;
|
|
13
|
+
readonly status: number | undefined;
|
|
14
|
+
readonly hint: string | undefined;
|
|
15
|
+
readonly details: unknown;
|
|
16
|
+
constructor(kind: CliErrorKind, message: string, options?: CliErrorOptions);
|
|
17
|
+
}
|
|
18
|
+
export declare function isCliError(value: unknown): value is CliError;
|
|
19
|
+
/**
|
|
20
|
+
* Exit codes: 1 for a refused or failed command, 2 when Bridge could not be
|
|
21
|
+
* reached or could not answer, 3 when the CLI is not set up (no issuer, not
|
|
22
|
+
* signed in, a setting that is wrong).
|
|
23
|
+
*/
|
|
24
|
+
export declare function exitCodeOf(error: unknown): number;
|
|
25
|
+
export declare const SIGN_IN_AGAIN = "Sign in again with `bridge auth login` (or `bridge auth login --password`).";
|
|
26
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,YAAY,GACpB,eAAe,GACf,eAAe,GACf,gBAAgB,GAChB,mBAAmB,GACnB,cAAc,GACd,kBAAkB,GAClB,WAAW,GACX,WAAW,GACX,eAAe,GACf,WAAW,GACX,UAAU,GACV,SAAS,GACT,cAAc,GACd,aAAa,GACb,SAAS,GACT,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;gBAEd,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;CAQ/E;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKjD;AAED,eAAO,MAAM,aAAa,gFAAgF,CAAC"}
|