@raster-app/cli 0.3.0 → 0.3.1
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 +2 -2
- package/dist/index.js +37 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,13 +16,13 @@ npx -p @raster-app/cli raster whoami
|
|
|
16
16
|
|
|
17
17
|
## Authenticate
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
**OAuth is the default** — an interactive login tied to your user account. For CI and automation, use an organization API key instead.
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
22
|
raster auth login
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
`raster auth login` signs you in over OAuth (no API key needed). When a browser is available — an interactive session with a display — it opens a **browser authorization-code flow** with a local loopback redirect; otherwise, over SSH or on a headless machine, it falls back to the **device authorization grant**, printing a short code and a URL you approve in a browser on any device. Pass `--browser` or `--device` to force either.
|
|
26
26
|
|
|
27
27
|
OAuth tokens (access + refresh) are stored in `~/.config/raster/config.json` with owner-only permissions. The CLI refreshes the access token automatically before it expires and rotates the refresh token; when the saved login can no longer be refreshed, it asks you to run `raster auth login` again.
|
|
28
28
|
|
package/dist/index.js
CHANGED
|
@@ -16337,7 +16337,7 @@ config(en_default());
|
|
|
16337
16337
|
// package.json
|
|
16338
16338
|
var package_default = {
|
|
16339
16339
|
name: "@raster-app/cli",
|
|
16340
|
-
version: "0.3.
|
|
16340
|
+
version: "0.3.1",
|
|
16341
16341
|
description: "Command-line client for the Raster API",
|
|
16342
16342
|
license: "Apache-2.0",
|
|
16343
16343
|
type: "module",
|
|
@@ -17420,6 +17420,16 @@ function resolveCredential(options) {
|
|
|
17420
17420
|
}
|
|
17421
17421
|
|
|
17422
17422
|
// src/lib/output.ts
|
|
17423
|
+
var ANSI = { reset: "\x1B[0m", bold: "\x1B[1m", dim: "\x1B[2m", cyan: "\x1B[36m" };
|
|
17424
|
+
function paint(text, code, enabled) {
|
|
17425
|
+
return enabled ? `${code}${text}${ANSI.reset}` : text;
|
|
17426
|
+
}
|
|
17427
|
+
function bold(text, enabled) {
|
|
17428
|
+
return paint(text, ANSI.bold, enabled);
|
|
17429
|
+
}
|
|
17430
|
+
function dim(text, enabled) {
|
|
17431
|
+
return paint(text, ANSI.dim, enabled);
|
|
17432
|
+
}
|
|
17423
17433
|
function printJson(output, payload) {
|
|
17424
17434
|
output.stdout(`${JSON.stringify(payload, null, 2)}
|
|
17425
17435
|
`);
|
|
@@ -17544,6 +17554,7 @@ async function createCommandContext(globals, overrides = {}) {
|
|
|
17544
17554
|
const output = {
|
|
17545
17555
|
json: globals.json === true,
|
|
17546
17556
|
verbose: globals.verbose === true,
|
|
17557
|
+
color: overrides.stderr === undefined && process.stderr.isTTY === true && env.NO_COLOR === undefined,
|
|
17547
17558
|
stdout: overrides.stdout ?? ((text) => void process.stdout.write(text)),
|
|
17548
17559
|
stderr: overrides.stderr ?? ((text) => void process.stderr.write(text))
|
|
17549
17560
|
};
|
|
@@ -17920,7 +17931,7 @@ async function removeAssetsCommand(context, assetIds, options) {
|
|
|
17920
17931
|
printJson(context, result);
|
|
17921
17932
|
return;
|
|
17922
17933
|
}
|
|
17923
|
-
note(context, `Moved ${assetIds.length} asset(s) to trash
|
|
17934
|
+
note(context, `Moved ${assetIds.length} asset(s) to trash.`);
|
|
17924
17935
|
}
|
|
17925
17936
|
var describeOptionsSchema = exports_external.object({
|
|
17926
17937
|
text: exports_external.string().min(1)
|
|
@@ -18001,14 +18012,14 @@ async function startLoopbackServer() {
|
|
|
18001
18012
|
const code = url2.searchParams.get("code");
|
|
18002
18013
|
const state = url2.searchParams.get("state");
|
|
18003
18014
|
if (code && state) {
|
|
18004
|
-
response.writeHead(200, { "Content-Type": "text/html" }).end(SUCCESS_PAGE);
|
|
18015
|
+
response.writeHead(200, { "Content-Type": "text/html", Connection: "close" }).end(SUCCESS_PAGE);
|
|
18005
18016
|
if (!settled) {
|
|
18006
18017
|
settled = true;
|
|
18007
18018
|
resolveCallback({ code, state });
|
|
18008
18019
|
}
|
|
18009
18020
|
return;
|
|
18010
18021
|
}
|
|
18011
|
-
response.writeHead(400, { "Content-Type": "text/html" }).end(FAILURE_PAGE);
|
|
18022
|
+
response.writeHead(400, { "Content-Type": "text/html", Connection: "close" }).end(FAILURE_PAGE);
|
|
18012
18023
|
if (!settled) {
|
|
18013
18024
|
settled = true;
|
|
18014
18025
|
const error51 = url2.searchParams.get("error");
|
|
@@ -18027,6 +18038,7 @@ async function startLoopbackServer() {
|
|
|
18027
18038
|
waitForCallback: () => callbackPromise,
|
|
18028
18039
|
close: () => {
|
|
18029
18040
|
server.close();
|
|
18041
|
+
server.closeAllConnections?.();
|
|
18030
18042
|
}
|
|
18031
18043
|
};
|
|
18032
18044
|
}
|
|
@@ -18088,6 +18100,7 @@ async function runBrowserLogin(options) {
|
|
|
18088
18100
|
challenge: pkce.challenge,
|
|
18089
18101
|
state
|
|
18090
18102
|
});
|
|
18103
|
+
options.onAuthorizeUrl?.(authorizeUrl);
|
|
18091
18104
|
await options.openBrowser(authorizeUrl);
|
|
18092
18105
|
const callback = await withDeadline(server.waitForCallback(), options.loginTimeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS);
|
|
18093
18106
|
if (callback.state !== state) {
|
|
@@ -18220,7 +18233,8 @@ async function runOAuthLogin(method, deps) {
|
|
|
18220
18233
|
clientId,
|
|
18221
18234
|
fetch: deps.fetch,
|
|
18222
18235
|
openBrowser: deps.openBrowser,
|
|
18223
|
-
now: deps.now
|
|
18236
|
+
now: deps.now,
|
|
18237
|
+
onAuthorizeUrl: deps.onAuthorizeUrl
|
|
18224
18238
|
});
|
|
18225
18239
|
}
|
|
18226
18240
|
const device = await requestDeviceCode({ metadata, clientId, fetch: deps.fetch });
|
|
@@ -18276,13 +18290,6 @@ async function loginCommand(context, options = {}) {
|
|
|
18276
18290
|
await apiKeyLogin(context, context.apiKey.key);
|
|
18277
18291
|
return;
|
|
18278
18292
|
}
|
|
18279
|
-
if (!options.device && !options.browser && context.isInteractive) {
|
|
18280
|
-
const promptedKey = await context.promptSecret("Paste your Raster API key (or press Enter to use OAuth)");
|
|
18281
|
-
if (promptedKey) {
|
|
18282
|
-
await apiKeyLogin(context, promptedKey);
|
|
18283
|
-
return;
|
|
18284
|
-
}
|
|
18285
|
-
}
|
|
18286
18293
|
if (context.env.RASTER_API_KEY && !context.isInteractive && !options.device && !options.browser) {
|
|
18287
18294
|
await apiKeyLogin(context, context.env.RASTER_API_KEY);
|
|
18288
18295
|
return;
|
|
@@ -18304,7 +18311,7 @@ async function apiKeyLogin(context, key) {
|
|
|
18304
18311
|
return;
|
|
18305
18312
|
}
|
|
18306
18313
|
const organizationLabel = viewer?.organizationName ?? viewer?.organizationId ?? "your organization";
|
|
18307
|
-
note(context, `Logged in to ${organizationLabel}
|
|
18314
|
+
note(context, `Logged in to ${organizationLabel}.`);
|
|
18308
18315
|
}
|
|
18309
18316
|
function chooseLoginMethod(context, options) {
|
|
18310
18317
|
if (options.device && options.browser) {
|
|
@@ -18330,11 +18337,17 @@ async function oauthLogin(context, options) {
|
|
|
18330
18337
|
now: context.now,
|
|
18331
18338
|
openBrowser: context.openBrowser,
|
|
18332
18339
|
onDevicePrompt: (prompt) => {
|
|
18333
|
-
|
|
18334
|
-
|
|
18335
|
-
|
|
18336
|
-
|
|
18337
|
-
note(context, "Waiting for
|
|
18340
|
+
const target = prompt.verificationUriComplete ? bold(prompt.verificationUriComplete, context.color) : `${bold(prompt.verificationUri, context.color)} and enter code ${bold(prompt.userCode, context.color)}`;
|
|
18341
|
+
note(context, "");
|
|
18342
|
+
note(context, `Visit ${target}`);
|
|
18343
|
+
note(context, "");
|
|
18344
|
+
note(context, dim("Waiting for authentication…", context.color));
|
|
18345
|
+
},
|
|
18346
|
+
onAuthorizeUrl: (url2) => {
|
|
18347
|
+
note(context, "");
|
|
18348
|
+
note(context, `Visit ${bold(url2, context.color)}`);
|
|
18349
|
+
note(context, "");
|
|
18350
|
+
note(context, dim("Waiting for authentication…", context.color));
|
|
18338
18351
|
}
|
|
18339
18352
|
});
|
|
18340
18353
|
await writeOAuthTokens(tokens, context.env);
|
|
@@ -18342,7 +18355,7 @@ async function oauthLogin(context, options) {
|
|
|
18342
18355
|
printJson(context, { issuer: tokens.issuer, scope: tokens.scope, resource: tokens.resource });
|
|
18343
18356
|
return;
|
|
18344
18357
|
}
|
|
18345
|
-
note(context,
|
|
18358
|
+
note(context, "Logged in.");
|
|
18346
18359
|
}
|
|
18347
18360
|
async function logoutCommand(context) {
|
|
18348
18361
|
const config2 = await readConfig(context.env);
|
|
@@ -18358,7 +18371,7 @@ async function logoutCommand(context) {
|
|
|
18358
18371
|
delete cleared.apiKey;
|
|
18359
18372
|
delete cleared.oauth;
|
|
18360
18373
|
await writeConfig(cleared, context.env);
|
|
18361
|
-
note(context, "Logged out.
|
|
18374
|
+
note(context, "Logged out.");
|
|
18362
18375
|
}
|
|
18363
18376
|
async function statusCommand(context) {
|
|
18364
18377
|
if (!context.credential) {
|
|
@@ -18366,7 +18379,7 @@ async function statusCommand(context) {
|
|
|
18366
18379
|
printJson(context, { authenticated: false });
|
|
18367
18380
|
return;
|
|
18368
18381
|
}
|
|
18369
|
-
note(context, "Not authenticated. Run `raster auth login
|
|
18382
|
+
note(context, "Not authenticated. Run `raster auth login`.");
|
|
18370
18383
|
return;
|
|
18371
18384
|
}
|
|
18372
18385
|
if (context.credential.kind === "oauth") {
|
|
@@ -18381,8 +18394,8 @@ function statusForOAuth(context, tokens) {
|
|
|
18381
18394
|
printJson(context, { authenticated: true, kind: "oauth", issuer: tokens.issuer, scope: tokens.scope, fresh });
|
|
18382
18395
|
return;
|
|
18383
18396
|
}
|
|
18384
|
-
note(context, `OAuth login on ${tokens.issuer}
|
|
18385
|
-
note(context, fresh ? "
|
|
18397
|
+
note(context, `OAuth login on ${tokens.issuer}, ${tokens.scope} scope.`);
|
|
18398
|
+
note(context, fresh ? "Token fresh." : "Token refreshes on next use.");
|
|
18386
18399
|
}
|
|
18387
18400
|
async function statusForApiKey(context, key, source) {
|
|
18388
18401
|
let viewer = null;
|
|
@@ -18396,7 +18409,7 @@ async function statusForApiKey(context, key, source) {
|
|
|
18396
18409
|
printJson(context, { authenticated: true, kind: "apiKey", source, keyPrefix: maskApiKey(key), organization: viewer ?? null });
|
|
18397
18410
|
return;
|
|
18398
18411
|
}
|
|
18399
|
-
note(context, `API key ${maskApiKey(key)}
|
|
18412
|
+
note(context, `API key ${maskApiKey(key)}, from ${source}.`);
|
|
18400
18413
|
if (viewer) {
|
|
18401
18414
|
note(context, `Organization: ${viewer.organizationName ?? viewer.organizationId ?? "unknown"} · plan: ${viewer.plan ?? "unknown"}`);
|
|
18402
18415
|
return;
|