metergraph-cli 0.2.0-preview.1 → 0.2.0-preview.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.
- package/README.md +19 -6
- package/package.json +1 -1
- package/src/auth-login.js +9 -6
- package/src/output.js +2 -2
- package/src/setup.js +3 -1
- package/src/trace-open.js +7 -2
- package/src/verify.js +4 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# metergraph-cli
|
|
2
2
|
|
|
3
|
-
The Metergraph command line tool. Version `0.2.0-preview.
|
|
3
|
+
The Metergraph command line tool. Version `0.2.0-preview.2` is published on the
|
|
4
4
|
`next` npm tag. The `latest` tag remains on `0.1.0`.
|
|
5
5
|
|
|
6
6
|
Install the released preview channel with npm or run it directly:
|
|
@@ -11,7 +11,7 @@ npx --yes metergraph-cli@next doctor --json
|
|
|
11
11
|
npm install -g metergraph-cli@next
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
The installed command is `metergraph`. Pin `metergraph-cli@0.2.0-preview.
|
|
14
|
+
The installed command is `metergraph`. Pin `metergraph-cli@0.2.0-preview.2`
|
|
15
15
|
when you need this exact preview rather than whichever version `next` names later.
|
|
16
16
|
|
|
17
17
|
**Availability:**
|
|
@@ -24,6 +24,10 @@ when you need this exact preview rather than whichever version `next` names late
|
|
|
24
24
|
`METERGRAPH_INGEST_URL` and repairs the full ingest endpoint that
|
|
25
25
|
`0.2.0-preview.0` wrote, after checking the saved key. It also keeps validated,
|
|
26
26
|
workspace-bound trace links in Metadata reads.
|
|
27
|
+
- `metergraph-cli@0.2.0-preview.2` makes `verify` exit 11 `verification_failed`
|
|
28
|
+
when its deadline expires after the service reported the trace as pending, lets
|
|
29
|
+
`login` and `setup` reruns that need no approval succeed with `--json
|
|
30
|
+
--no-browser`, and reports why `verify --open` did not launch a browser.
|
|
27
31
|
- Sign in needs a Metergraph service that offers Metadata-only CLI grants and grant
|
|
28
32
|
revocation. A service without them is reported as unsupported, and the CLI never
|
|
29
33
|
falls back to broader access.
|
|
@@ -100,7 +104,16 @@ sends a test event.
|
|
|
100
104
|
`--open` launches only a server-provided link carrying the exact trace and the
|
|
101
105
|
verified workspace ID. The dashboard must check that ID against its signed-in
|
|
102
106
|
workspace before displaying traces. Older links without a workspace remain a
|
|
103
|
-
manual handoff; a conflicting workspace or unsafe link is refused.
|
|
107
|
+
manual handoff; a conflicting workspace or unsafe link is refused. The result's
|
|
108
|
+
`browser` field is `launcher_started`, `launcher_unavailable`, `not_requested`
|
|
109
|
+
(no `--open`), or `suppressed_by_json` / `suppressed_by_no_browser` when `--open`
|
|
110
|
+
was given but that flag returned the link instead of launching it.
|
|
111
|
+
|
|
112
|
+
If `--timeout-ms` expires after the service has answered at least once with a
|
|
113
|
+
pending result, `verify` exits 11 `verification_failed` with reason
|
|
114
|
+
`verification_timeout`: the origin is reachable and the trace is not visible yet.
|
|
115
|
+
Exit 4 `connection_failed` with that reason means no valid answer arrived before
|
|
116
|
+
the deadline.
|
|
104
117
|
|
|
105
118
|
### doctor
|
|
106
119
|
|
|
@@ -225,7 +238,7 @@ metergraph logout
|
|
|
225
238
|
| `--config-dir DIR` | see below | Private per-user directory for the saved grant. |
|
|
226
239
|
| `--timeout-ms N` | `300000` | How long to wait for the browser, 1000 to 900000. |
|
|
227
240
|
| `--signup` | off | Start at the hosted sign up page, which returns to the same authorization request. Managed service only; other profiles exit 6. |
|
|
228
|
-
| `--no-browser` | off | Print the authorization URL on stderr for you to open on this machine, then wait.
|
|
241
|
+
| `--no-browser` | off | Print the authorization URL on stderr for you to open on this machine, then wait. With `--json`, a rerun that needs no approval succeeds; one that needs approval exits 6 `no_browser_requires_terminal`. |
|
|
229
242
|
| `--reconnect` | off | Allow replacing a binding to a different origin or workspace. |
|
|
230
243
|
| `--json` | off | Print exactly one JSON line on stdout and nothing on stderr. |
|
|
231
244
|
|
|
@@ -763,7 +776,7 @@ To try a packed artifact without publishing:
|
|
|
763
776
|
|
|
764
777
|
```sh
|
|
765
778
|
npm pack --pack-destination "$(mktemp -d)"
|
|
766
|
-
npx --yes --package=/path/to/metergraph-cli-0.2.0-preview.
|
|
779
|
+
npx --yes --package=/path/to/metergraph-cli-0.2.0-preview.2.tgz -- metergraph --version
|
|
767
780
|
```
|
|
768
781
|
|
|
769
782
|
Do not commit tarballs or other generated files.
|
|
@@ -772,7 +785,7 @@ Do not commit tarballs or other generated files.
|
|
|
772
785
|
|
|
773
786
|
The source of truth is the public repository
|
|
774
787
|
[github.com/metergraph/cli](https://github.com/metergraph/cli), licensed Apache-2.0.
|
|
775
|
-
`0.2.0-preview.
|
|
788
|
+
`0.2.0-preview.2` is published on the `next` npm tag; `latest` remains on
|
|
776
789
|
`0.1.0`. The hosted service supports sign in, Metadata reads and ingest bootstrap.
|
|
777
790
|
Subsequent releases must pass the checks below before publication.
|
|
778
791
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metergraph-cli",
|
|
3
|
-
"version": "0.2.0-preview.
|
|
3
|
+
"version": "0.2.0-preview.2",
|
|
4
4
|
"description": "Preview Metergraph command line tool with a read-only connection probe, a project skill installer, Metadata-only sign in and bounded workspace Metadata reads",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/auth-login.js
CHANGED
|
@@ -58,12 +58,13 @@ export async function runLogin(options, progress) {
|
|
|
58
58
|
if (options.runtime !== "local") return end("unsupported", "runtime_not_supported", GUIDE);
|
|
59
59
|
const remote = detectRemoteSession();
|
|
60
60
|
if (remote !== null) return end("unsupported", remote, GUIDE);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
61
|
+
// --json cannot show a person the --no-browser URL. A rerun with a saved,
|
|
62
|
+
// working grant needs no URL, so only refuse once approval is required.
|
|
63
|
+
const noBrowserHandoff = () => end("unsupported", "no_browser_requires_terminal", {
|
|
64
|
+
kind: "run_in_terminal",
|
|
65
|
+
message: "Run the same login command in a terminal without --json to see the sign in URL.",
|
|
66
|
+
});
|
|
67
|
+
const urlUnshowable = options.json && options.noBrowser;
|
|
67
68
|
|
|
68
69
|
const trap = trapSignals();
|
|
69
70
|
try {
|
|
@@ -71,6 +72,7 @@ export async function runLogin(options, progress) {
|
|
|
71
72
|
const configDir = resolveConfigDir(options.configDir);
|
|
72
73
|
const existing = readBinding(root);
|
|
73
74
|
const bound = existing?.binding ?? null;
|
|
75
|
+
if (urlUnshowable && (bound === null || options.reconnect)) return noBrowserHandoff();
|
|
74
76
|
// Setup pins a deployment model before sign in. A stale binding for a
|
|
75
77
|
// different profile must never be silently reused or reconnected.
|
|
76
78
|
if (options.expectedProfile && bound !== null && !options.reconnect &&
|
|
@@ -100,6 +102,7 @@ export async function runLogin(options, progress) {
|
|
|
100
102
|
}
|
|
101
103
|
if (session.outcome !== "login_required") return end(session.outcome, session.reason);
|
|
102
104
|
}
|
|
105
|
+
if (urlUnshowable) return noBrowserHandoff();
|
|
103
106
|
|
|
104
107
|
const flow = await authorize(options, ctx, trap.signal, progress);
|
|
105
108
|
if (!flow.ok) return end(flow.outcome, flow.reason, flow.next ?? null);
|
package/src/output.js
CHANGED
|
@@ -599,8 +599,8 @@ const AUTH_MESSAGES = {
|
|
|
599
599
|
ci_environment:
|
|
600
600
|
"This is a CI environment, where no person can approve sign in in a browser. Nothing was written.",
|
|
601
601
|
no_browser_requires_terminal:
|
|
602
|
-
"--no-browser prints
|
|
603
|
-
"Run
|
|
602
|
+
"Approval is needed, and --no-browser prints its URL for a person to open, which --json cannot do. " +
|
|
603
|
+
"Run the same command without --json in a terminal. Nothing was done.",
|
|
604
604
|
bound_to_other_origin:
|
|
605
605
|
"This project is bound to a different origin. Nothing was changed. Use --reconnect to switch it.",
|
|
606
606
|
bound_to_other_workspace:
|
package/src/setup.js
CHANGED
|
@@ -31,7 +31,6 @@ const fail = (outcome, reason, status = "not_ready", receipt = null) => ({ outco
|
|
|
31
31
|
// response can supply it. Every returned string is fixed and non-secret.
|
|
32
32
|
export async function runSetup(options, progress = () => {}) {
|
|
33
33
|
if (options.runtime !== "local" || detectRemoteSession() !== null) return fail("unsupported", "run_on_local_machine");
|
|
34
|
-
if (options.json && options.noBrowser) return fail("unsupported", "no_browser_requires_terminal");
|
|
35
34
|
const trap = trapSignals();
|
|
36
35
|
let receipt = null;
|
|
37
36
|
let loginVerified = false;
|
|
@@ -138,6 +137,9 @@ export async function runSetup(options, progress = () => {}) {
|
|
|
138
137
|
return stop("conflict", "repair_requires_saved_key");
|
|
139
138
|
}
|
|
140
139
|
|
|
140
|
+
// A verified rerun returned above without approval. From here a person
|
|
141
|
+
// must open an approval URL, which --json cannot show with --no-browser.
|
|
142
|
+
if (options.json && options.noBrowser) return stop("unsupported", "no_browser_requires_terminal");
|
|
141
143
|
const setup = await discoverSetup(origin, profile, trap.signal);
|
|
142
144
|
if (!setup.ok) return stop(setup.outcome, setup.reason);
|
|
143
145
|
|
package/src/trace-open.js
CHANGED
|
@@ -4,7 +4,8 @@ import { normalizeUuid } from "./auth-oauth.js";
|
|
|
4
4
|
import { parseOrigin } from "./origin.js";
|
|
5
5
|
|
|
6
6
|
// Operates only on an already verified, provenance-bound receipt. JSON and
|
|
7
|
-
// no-browser mode return its URL without starting a launcher
|
|
7
|
+
// no-browser mode return its URL without starting a launcher, and say which
|
|
8
|
+
// one suppressed an --open request. "opened" means
|
|
8
9
|
// the OS launcher started; it does not assert a browser rendered the page.
|
|
9
10
|
export async function openTrace(receipt, options = {}, launch = openBrowser) {
|
|
10
11
|
if (receipt?.readiness?.metadata_available !== true || receipt?.readiness?.processed !== true ||
|
|
@@ -20,7 +21,11 @@ export async function openTrace(receipt, options = {}, launch = openBrowser) {
|
|
|
20
21
|
if (link.workspaceBound !== true || receipt.link_workspace_bound !== true || receipt.link_status !== "available") {
|
|
21
22
|
return { outcome: "unsupported", reason: "link_workspace_binding_unavailable", data: { ...receipt, browser: "not_requested" } };
|
|
22
23
|
}
|
|
23
|
-
if (
|
|
24
|
+
if (!options.open) return { outcome: "ok", reason: null, data: { ...receipt, browser: "not_requested" } };
|
|
25
|
+
if (options.json || options.noBrowser) {
|
|
26
|
+
const browser = options.json ? "suppressed_by_json" : "suppressed_by_no_browser";
|
|
27
|
+
return { outcome: "ok", reason: null, data: { ...receipt, browser } };
|
|
28
|
+
}
|
|
24
29
|
if (options.signal?.aborted) return { outcome: "cancelled", reason: "cancelled", data: receipt };
|
|
25
30
|
const launched = await launchWithinSignal(link.value, launch, options.signal);
|
|
26
31
|
if (options.signal?.aborted) return { outcome: "cancelled", reason: "cancelled", data: receipt };
|
package/src/verify.js
CHANGED
|
@@ -33,7 +33,10 @@ export async function runVerify(options, dependencies = {}) {
|
|
|
33
33
|
if (holdsKnown(data, known)) return { outcome: "verification_failed", reason: "credential_in_metadata_response", data: null };
|
|
34
34
|
return { outcome, reason, data: data === null ? null : { ...data, attempts } };
|
|
35
35
|
};
|
|
36
|
-
|
|
36
|
+
// Once the origin has answered with a valid pending receipt, a deadline
|
|
37
|
+
// means the trace is not visible yet, not that the origin is unreachable.
|
|
38
|
+
const interrupted = () => !limit.timedOut() ? end("cancelled", "cancelled")
|
|
39
|
+
: end(receipt === null ? "connection_failed" : "verification_failed", "verification_timeout");
|
|
37
40
|
try {
|
|
38
41
|
const sessionResult = await (dependencies.session ?? verifiedSession)({ project: options.project, configDir: options.configDir, cancel: limit.signal });
|
|
39
42
|
if (limit.signal.aborted) return interrupted();
|