@hediet/linkrpc-cli 0.0.3-next.20261023.4 → 0.0.3-next.20261025.3
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 +55 -2
- package/dist/chunks/{cli-CYL6JUxF.js → cli-D_nbiyek.js} +153 -25
- package/dist/chunks/cli-D_nbiyek.js.map +1 -0
- package/dist/chunks/{runApprovalUi-CVymyDHh.js → runApprovalUi-Diol5P5a.js} +3 -3
- package/dist/chunks/{runApprovalUi-CVymyDHh.js.map → runApprovalUi-Diol5P5a.js.map} +1 -1
- package/dist/chunks/{runComplete-C9LMCMk7.js → runComplete-bFjlzR3Y.js} +90 -45
- package/dist/chunks/runComplete-bFjlzR3Y.js.map +1 -0
- package/dist/chunks/{runUi-ByL1VdAP.js → runUi-DDJrDeBg.js} +4 -4
- package/dist/chunks/{runUi-ByL1VdAP.js.map → runUi-DDJrDeBg.js.map} +1 -1
- package/dist/chunks/{scroll-C_qlfSXZ.js → scroll-mMFXvk6E.js} +2 -2
- package/dist/chunks/{scroll-C_qlfSXZ.js.map → scroll-mMFXvk6E.js.map} +1 -1
- package/dist/chunks/{src-CCyOTeN5.js → src-B71xYgEO.js} +2 -2
- package/dist/chunks/{src-CCyOTeN5.js.map → src-B71xYgEO.js.map} +1 -1
- package/dist/hub.js +1 -1
- package/dist/index.js +1 -1
- package/dist/linkrpc.js +1 -1
- package/dist/rpc.js +1 -1
- package/package.json +5 -5
- package/dist/chunks/cli-CYL6JUxF.js.map +0 -1
- package/dist/chunks/runComplete-C9LMCMk7.js.map +0 -1
package/README.md
CHANGED
|
@@ -581,7 +581,7 @@ it**. Pick one of:
|
|
|
581
581
|
| `--endpoint <uri>` | A strict endpoint URI (see below). |
|
|
582
582
|
| `--endpoint-cmd <command>` | Spawn a _server_, hand it a fresh socket + token via `LINKRPC_ENDPOINT`/`LINKRPC_TOKEN`, then connect to it. |
|
|
583
583
|
| `--endpoint-cmd-stdio <command>` | Spawn a child and talk linkrpc over its stdio. |
|
|
584
|
-
| `LINKRPC_ENDPOINT` (env) | A URI, or a legacy bare socket path / `ws://` URL. Token from `LINKRPC_TOKEN`; enabled by default in the Hub profile. |
|
|
584
|
+
| `LINKRPC_ENDPOINT` (env) | A URI, or a legacy bare socket path / `ws://` URL. Token from `LINKRPC_TOKEN`; enabled by default in the Hub profile and with `--use-env` in the RPC profile. |
|
|
585
585
|
|
|
586
586
|
Legacy `HUBRPC_ENDPOINT` and `HUBRPC_TOKEN` remain supported when the
|
|
587
587
|
corresponding `LINKRPC_*` variable is absent.
|
|
@@ -794,6 +794,7 @@ initial document:
|
|
|
794
794
|
| `connection destroy` | Stop the configured connection broker through its local overlay. |
|
|
795
795
|
| `json-rpc-stdio <serviceId> [--params <json>]` | In the Hub profile, expose `<serviceId>::jsonRpcConnection::connectRaw` as newline-delimited JSON-RPC on stdin/stdout. Diagnostics remain on stderr. |
|
|
796
796
|
| `json-rpc-export --target-endpoint <uri> --serviceId <id> --path <path> ...` | In the Hub profile, export multiple JSON-RPC factories through one authenticated raw WebSocket listener. |
|
|
797
|
+
| `http-export [--port <n>] [--host <address>]... [--base-domain <domain>]` | In the Hub profile, serve loopback ports of Hub compute nodes at `<port>.<service>.localhost` over HTTP and WebSocket. |
|
|
797
798
|
|
|
798
799
|
The inherited `--schema <path-or-url>` option also overlays static
|
|
799
800
|
`hubrpc.defaults`, `hubrpc.directory`, and `hubrpc.schemas` reflection for
|
|
@@ -834,6 +835,55 @@ Only `listen:ws://` TCP listeners are currently supported, not named pipes or TL
|
|
|
834
835
|
|
|
835
836
|
The command stays in the foreground until SIGINT/SIGTERM, then closes clients and the listener. Use the existing Hub daemon/service lifecycle to supervise it; this command neither installs a service nor starts remote AHP hosts. Diagnostics and the bound address (including an assigned port when using port 0) go to stderr.
|
|
836
837
|
|
|
838
|
+
### HTTP export
|
|
839
|
+
|
|
840
|
+
`http-export` serves loopback TCP ports of Hub compute nodes (services offering
|
|
841
|
+
`linkrpc.computeNode.tcpForward`) as `*.localhost` sites. `*.localhost` always
|
|
842
|
+
resolves to this machine, so no DNS setup is needed:
|
|
843
|
+
|
|
844
|
+
```sh
|
|
845
|
+
linkrpc hub http-export # listens on 127.0.0.1:80 and [::1]:80
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
| URL | Shows |
|
|
849
|
+
| --- | --- |
|
|
850
|
+
| `http://localhost/` | Services that can forward TCP (`?format=json` for JSON). |
|
|
851
|
+
| `http://hediet--tablet--compute.localhost/` | Listening ports of `hediet/tablet/compute` (needs `linkrpc.computeNode.ports`). |
|
|
852
|
+
| `http://3000.hediet--tablet--compute.localhost/` | Port 3000 of that compute node, including WebSocket upgrades. |
|
|
853
|
+
|
|
854
|
+
A service is always exactly one label directly below `localhost`, its
|
|
855
|
+
segments joined with `--`. Browsers treat `localhost` as a public suffix, so
|
|
856
|
+
each service is its own site: pages of one machine get no `SameSite` cookies
|
|
857
|
+
from another machine's apps and cannot set cookies for them, as with direct
|
|
858
|
+
access. The ports of one service share that site, as the ports of `localhost`
|
|
859
|
+
do on its machine. A service ID whose segments are not plain lowercase DNS
|
|
860
|
+
labels, or whose label would exceed 63 characters, is written as a hashed label
|
|
861
|
+
instead, `<slug>--h<hash>`, which the gateway resolves against the services it
|
|
862
|
+
can reach. The index pages link to the right form.
|
|
863
|
+
|
|
864
|
+
There is no gateway credential and no origin check of its own. Instead, the
|
|
865
|
+
gateway translates between a forwarded app's own origins
|
|
866
|
+
(`http://localhost:<port>` on its machine) and their exported names, so the
|
|
867
|
+
app's own Host, Origin, CORS, redirect, and cookie checks behave as they do for
|
|
868
|
+
a browser on its machine:
|
|
869
|
+
|
|
870
|
+
| Header | Translation |
|
|
871
|
+
| --- | --- |
|
|
872
|
+
| `Host` | Always `localhost:<port>`. The gateway itself only accepts `*.localhost` names, so DNS rebinding cannot reach it. |
|
|
873
|
+
| `Origin`, `Referer` | Exported names of the same service map to `http://localhost:<port>`. Other services' exported names and foreign sites pass unchanged. This machine's own loopback origins have no counterpart on the target: `Origin` becomes `null` and `Referer` is dropped. |
|
|
874
|
+
| `Location`, `Access-Control-Allow-Origin` | URLs naming the target machine's loopback map to their exported names. |
|
|
875
|
+
| `Set-Cookie` | Host-only and `Domain=localhost` cookies get the service's domain (e.g. `Domain=hediet--tablet--compute.localhost`), which reaches that machine's exported ports, as such cookies reach all of its ports there. Cookies for other domains are dropped, as a browser there would reject them. `__Host-` cookies stay host-only, so they reach only one exported port. |
|
|
876
|
+
|
|
877
|
+
WebSocket upgrades are translated the same way in both directions. No
|
|
878
|
+
`X-Forwarded-*` headers are added. Absolute loopback URLs inside response
|
|
879
|
+
bodies are not rewritten, so they fail rather than reach this machine. Bind
|
|
880
|
+
loopback only: anyone who can reach the listener can use the export process's
|
|
881
|
+
Hub identity to reach every forwarded port.
|
|
882
|
+
|
|
883
|
+
Each service and port shares one `tcpForward.multiplex` session (up to 10
|
|
884
|
+
logical connections, 8 of them for pooled HTTP keep-alive), closed after five
|
|
885
|
+
idle minutes.
|
|
886
|
+
|
|
837
887
|
### Participant proxy
|
|
838
888
|
|
|
839
889
|
`proxy` stands in for a participant on the hub: the participant is either this
|
|
@@ -940,7 +990,7 @@ Value-taking options support both `--option=value` and `--option value`.
|
|
|
940
990
|
Parameter assignment itself still uses `key=value`, e.g.
|
|
941
991
|
`--param path=/docs/a` or `--param=path=/docs/a`. Use the equals form for
|
|
942
992
|
dash-prefixed values. Quote JSON and strings containing spaces.
|
|
943
|
-
`--cap:request
|
|
993
|
+
`--cap:request`, `--cap:allow-any`, and `--cap:delegate` are switches with no value.
|
|
944
994
|
The older `--request-cap`, `--allow-param`, and `--duration` spellings have
|
|
945
995
|
been replaced by the `--cap:` options.
|
|
946
996
|
|
|
@@ -950,6 +1000,9 @@ Schema validation is mandatory for explicit requests: `--no-validate` and
|
|
|
950
1000
|
the permission; signed calls include that hash in their signed metadata.
|
|
951
1001
|
The default requested duration is `persistent`; `--cap:duration shortLived` and
|
|
952
1002
|
`--cap:duration longLived` are also supported. The Hub still decides what to grant.
|
|
1003
|
+
`--cap:delegate` also requests `canDelegate`, so the identity can issue narrower
|
|
1004
|
+
capabilities for that scope to other identities, e.g. a service it runs; a
|
|
1005
|
+
stored grant without delegation does not satisfy such a request.
|
|
953
1006
|
One-shot approval cannot satisfy a reusable scope and is rejected.
|
|
954
1007
|
|
|
955
1008
|
Fresh durable grants for the selected principal are reused when they cover
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as requestTopologyAccess, B as proxyCommand, F as disconnectBroker, G as parseDuration, H as withStaticHubReflection, I as getBrokerStatus, L as readBrokerNotifications, M as readEndpointDiscovery, N as ContextStore, P as formatContextReference, Q as requestReflectionAccess, R as stopConnectionBroker, St as
|
|
1
|
+
import { $ as requestTopologyAccess, B as proxyCommand, Ct as MethodRefWithOptHash, F as disconnectBroker, G as parseDuration, H as withStaticHubReflection, I as getBrokerStatus, L as readBrokerNotifications, M as readEndpointDiscovery, N as ContextStore, P as formatContextReference, Q as requestReflectionAccess, R as stopConnectionBroker, St as parseParamOverride, U as parseConnectionLimit, V as tunnelCommand, W as parseConnectionLimitMilliseconds, _t as describeSchema, a as resolveInvocationEndpoint, c as resolveLocalEndpoint, ct as readCliIdentity, dt as connect, et as setupSigning, ft as connectViaRootOverlay, gt as describeObjectParams, ht as resolvedEndpointToConfig, i as resolveInvocationContext, it as walkHub, lt as formatPrincipalSource, m as managedEndpointsInterface, mt as resolveTargetEndpoint, n as loadStaticHubSchema, nt as fetchSchema$1, o as resolveSigning, ot as cliIdentityTarget, pt as connectViaTransport, q as resolveCliInvocation, r as resolveStaticHubSchemaSource, rt as findMethodInSchema, s as validationDefault, st as deleteCliIdentity, t as completeForLine, tt as fetchDefaults, ut as parsePrincipalSpec, vt as explainValidation, wt as mcpForwardInterface, xt as mergeParams, y as HubHome, yt as validateValueAgainstSchema, z as ConnectionBroker } from "./runComplete-bFjlzR3Y.js";
|
|
2
2
|
import { ErrorCode, INTERFACE_TEMPLATES_EXTENSION, LinkRpcConnection, RpcError, computeInterfaceHash, connectTransports, createSchemaToZod, directoryInterface, exportStaticHubSchema, generateTsContract, generateTsInterface, interfaceTemplateArgumentsEquivalent, interfaceTemplateMemberName, interfaceTemplatesEqual, isAssignable, jcsCanonicalize, matchParams, schemaToZod, validateInterfaceTemplates } from "@hediet/linkrpc";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { WebSocketTransport, connectNdjson, connectToHub, formatEndpointUri, isHubEndpoint, openWebSocket, parseEndpointUri, runInitializeHandshake, traceMessageTransport as traceMessageTransport$1 } from "@hediet/linkrpc/node";
|
|
@@ -13,20 +13,22 @@ import * as net from "node:net";
|
|
|
13
13
|
import { mkdir, open, readFile, writeFile } from "node:fs/promises";
|
|
14
14
|
import { DEFAULT_WALK_DEPTH, HubDirectoryExplorer, fetchSchema, findCoveringCapabilities, hubGrantedServiceIdInterface } from "@hediet/linkrpc/hub/common";
|
|
15
15
|
import { CONSOLE_INTERFACE_TAG, ConsoleTemplate, consoleAttachResultSchema, consoleServerMessageSchema, decodeConsoleData, encodeConsoleData } from "@hediet/linkrpc-infra/console";
|
|
16
|
+
import { createInterface } from "node:readline/promises";
|
|
16
17
|
import { Command, InvalidArgumentError, Option } from "commander";
|
|
17
18
|
import * as readline from "node:readline";
|
|
18
|
-
import { createInterface, emitKeypressEvents } from "node:readline";
|
|
19
|
+
import { createInterface as createInterface$1, emitKeypressEvents } from "node:readline";
|
|
19
20
|
import { parse, unknown } from "zod/mini";
|
|
20
21
|
import { bootstrapApprovalCapability, createHubApprovalClient } from "@hediet/linkrpc-infra/approval";
|
|
21
22
|
import { connectionTokenBinderInterface } from "@hediet/linkrpc-hub/hub/server/connection-token-binder";
|
|
22
23
|
import { spawn } from "node:child_process";
|
|
23
24
|
import { TopologyClient, TopologyNetworkClient, TrafficClient } from "@hediet/linkrpc-infra/inspection";
|
|
24
|
-
import { createInterface as createInterface$1 } from "node:readline/promises";
|
|
25
25
|
import { stdin, stdout } from "node:process";
|
|
26
26
|
import { TrafficFlowAggregator, createTerminalConsentPrompt, formatFlowSummary } from "@hediet/linkrpc-hub";
|
|
27
27
|
import { loadHubConfig, printHubConfigSchema } from "@hediet/linkrpc-hub/config-file";
|
|
28
28
|
import { connectJsonRpcTransports, connectRawJsonRpcTransport, createNdjsonJsonRpcTransport, jsonRpcConnectionInterface } from "@hediet/linkrpc-infra/json-rpc";
|
|
29
29
|
import { startJsonRpcWebSocketExport, validateJsonRpcExport } from "@hediet/linkrpc-infra/json-rpc/node";
|
|
30
|
+
import { computeNodePortsInterface, computeNodeTcpForwardInterface } from "@hediet/linkrpc-infra/compute-node";
|
|
31
|
+
import { startHttpExport } from "@hediet/linkrpc-infra/http-export/node";
|
|
30
32
|
import { GRAPH_INTERFACE_TAG, IMMUTABLE_GRAPH_INTERFACE_ID, ROOT_WATCH_INTERFACE_ID, evaluateGraphPresentation, graphPresentationInterface, graphPresentationSchema, isGraphRef, standardGraphRuntimeOptions, validateGraphInterfaceSchema } from "@hediet/linkrpc-infra/graph";
|
|
31
33
|
import React from "react";
|
|
32
34
|
import { Box, Text, measureElement, render } from "ink";
|
|
@@ -49,7 +51,7 @@ var ServiceConsoleInput = class {
|
|
|
49
51
|
this._close = _close;
|
|
50
52
|
this._wasRaw = _input.isRaw ?? false;
|
|
51
53
|
if (_input.isTTY) {
|
|
52
|
-
this._readline = createInterface({
|
|
54
|
+
this._readline = createInterface$1({
|
|
53
55
|
input: _input,
|
|
54
56
|
output,
|
|
55
57
|
terminal: true,
|
|
@@ -407,7 +409,7 @@ function contextNamespace(reference) {
|
|
|
407
409
|
async function useLocalManagement(start, action) {
|
|
408
410
|
const home = HubHome.resolve();
|
|
409
411
|
if (start) {
|
|
410
|
-
const { startDaemon, nodeDaemonLaunch } = await import("./src-
|
|
412
|
+
const { startDaemon, nodeDaemonLaunch } = await import("./src-B71xYgEO.js");
|
|
411
413
|
if (await startDaemon({
|
|
412
414
|
home,
|
|
413
415
|
launch: nodeDaemonLaunch(home)
|
|
@@ -427,7 +429,7 @@ async function useLocalManagement(start, action) {
|
|
|
427
429
|
}
|
|
428
430
|
}
|
|
429
431
|
async function restartLocalDaemon() {
|
|
430
|
-
const { startDaemon, stopDaemon, nodeDaemonLaunch } = await import("./src-
|
|
432
|
+
const { startDaemon, stopDaemon, nodeDaemonLaunch } = await import("./src-B71xYgEO.js");
|
|
431
433
|
const home = HubHome.resolve();
|
|
432
434
|
process.stderr.write("Restarting the local Hub daemon: clients will disconnect and managed workloads will stop. OS autostart settings are unchanged.\n");
|
|
433
435
|
await stopDaemon(home);
|
|
@@ -947,6 +949,7 @@ async function requestCallCapability(channel, session, ref, params, schema, opts
|
|
|
947
949
|
...ref.hash !== void 0 ? { interfaceHash: ref.hash } : {}
|
|
948
950
|
},
|
|
949
951
|
canInvoke: true,
|
|
952
|
+
...opts.delegate === true ? { canDelegate: true } : {},
|
|
950
953
|
params: matchers
|
|
951
954
|
};
|
|
952
955
|
const coverageOptions = {
|
|
@@ -3040,7 +3043,7 @@ function selectParticipant(participants, nodeId) {
|
|
|
3040
3043
|
return participants.length === 1 ? participants[0] : void 0;
|
|
3041
3044
|
}
|
|
3042
3045
|
async function promptForParticipant(participants, search) {
|
|
3043
|
-
const readline = createInterface
|
|
3046
|
+
const readline = createInterface({
|
|
3044
3047
|
input: stdin,
|
|
3045
3048
|
output: stdout
|
|
3046
3049
|
});
|
|
@@ -3541,6 +3544,72 @@ async function jsonRpcExportCommand(options) {
|
|
|
3541
3544
|
});
|
|
3542
3545
|
}
|
|
3543
3546
|
//#endregion
|
|
3547
|
+
//#region src/commands/httpExport.ts
|
|
3548
|
+
const SERVICE_LIST_TTL_MS = 3e4;
|
|
3549
|
+
const SERVICE_LIST_TIMEOUT_MS = 2e4;
|
|
3550
|
+
async function httpExportCommand(options) {
|
|
3551
|
+
const connection = new LinkRpcConnection(options.local.rpcChannel);
|
|
3552
|
+
const services = new ForwardableServices(options.local.channel, options.requestDirectoryAccess, options.onError);
|
|
3553
|
+
return startHttpExport({
|
|
3554
|
+
listen: options.hosts.map((host) => ({
|
|
3555
|
+
host,
|
|
3556
|
+
port: options.port
|
|
3557
|
+
})),
|
|
3558
|
+
baseDomain: options.baseDomain,
|
|
3559
|
+
getTcpForward: (serviceId) => connection.service(serviceId).get(computeNodeTcpForwardInterface),
|
|
3560
|
+
listServices: () => services.get(),
|
|
3561
|
+
listPorts: async (serviceId) => (await connection.service(serviceId).get(computeNodePortsInterface).listListening({})).ports,
|
|
3562
|
+
onError: options.onError
|
|
3563
|
+
});
|
|
3564
|
+
}
|
|
3565
|
+
/** Caches the services that implement `tcpForward`; a slow or partial walk returns what it found. */
|
|
3566
|
+
var ForwardableServices = class {
|
|
3567
|
+
_channel;
|
|
3568
|
+
_requestDirectoryAccess;
|
|
3569
|
+
_onError;
|
|
3570
|
+
_cached;
|
|
3571
|
+
_pending;
|
|
3572
|
+
constructor(_channel, _requestDirectoryAccess, _onError) {
|
|
3573
|
+
this._channel = _channel;
|
|
3574
|
+
this._requestDirectoryAccess = _requestDirectoryAccess;
|
|
3575
|
+
this._onError = _onError;
|
|
3576
|
+
}
|
|
3577
|
+
get() {
|
|
3578
|
+
if (this._cached && Date.now() - this._cached.at < SERVICE_LIST_TTL_MS) return Promise.resolve(this._cached.value);
|
|
3579
|
+
this._pending ??= this._load().finally(() => {
|
|
3580
|
+
this._pending = void 0;
|
|
3581
|
+
});
|
|
3582
|
+
return this._pending;
|
|
3583
|
+
}
|
|
3584
|
+
async _load() {
|
|
3585
|
+
const explorer = new HubDirectoryExplorer(this._channel, {
|
|
3586
|
+
interfaceId: computeNodeTcpForwardInterface.info.id,
|
|
3587
|
+
timeoutMs: 5e3,
|
|
3588
|
+
unlockGatedDirectory: this._requestDirectoryAccess,
|
|
3589
|
+
log: (message) => this._onError(new Error(message))
|
|
3590
|
+
});
|
|
3591
|
+
let timer;
|
|
3592
|
+
try {
|
|
3593
|
+
const walked = await Promise.race([explorer.explore(), new Promise((resolve) => {
|
|
3594
|
+
timer = setTimeout(() => resolve(void 0), SERVICE_LIST_TIMEOUT_MS);
|
|
3595
|
+
})]);
|
|
3596
|
+
const listings = (walked?.listings ?? explorer.result.listings).filter((listing) => listing.serviceId !== "");
|
|
3597
|
+
const value = {
|
|
3598
|
+
serviceIds: [...new Set(listings.map((listing) => listing.serviceId))],
|
|
3599
|
+
complete: walked !== void 0 && walked.inaccessible.length === 0
|
|
3600
|
+
};
|
|
3601
|
+
this._cached = {
|
|
3602
|
+
value,
|
|
3603
|
+
at: Date.now()
|
|
3604
|
+
};
|
|
3605
|
+
return value;
|
|
3606
|
+
} finally {
|
|
3607
|
+
clearTimeout(timer);
|
|
3608
|
+
explorer.dispose();
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
};
|
|
3612
|
+
//#endregion
|
|
3544
3613
|
//#region ../../node_modules/.pnpm/@vscode+observables@0.1.1-0/node_modules/@vscode/observables/dist/observableInternal/logging/logging.js
|
|
3545
3614
|
let globalObservableLogger;
|
|
3546
3615
|
function addLogger(logger) {
|
|
@@ -8734,7 +8803,8 @@ async function main(rawArgv, executableName = "linkrpc") {
|
|
|
8734
8803
|
return;
|
|
8735
8804
|
}
|
|
8736
8805
|
if (endpoint === void 0) {
|
|
8737
|
-
|
|
8806
|
+
const ignoredEnvironmentHint = ignoredEndpointEnvironmentHint();
|
|
8807
|
+
process.stdout.write(`\n(No endpoint configured: pass ${endpointOptionsDescription()}.\n` + (ignoredEnvironmentHint === void 0 ? "" : `${ignoredEnvironmentHint}.\n`) + "To see method-specific --p:<name> flags here.)\n");
|
|
8738
8808
|
return;
|
|
8739
8809
|
}
|
|
8740
8810
|
let ref;
|
|
@@ -8778,7 +8848,7 @@ async function main(rawArgv, executableName = "linkrpc") {
|
|
|
8778
8848
|
"shortLived",
|
|
8779
8849
|
"longLived",
|
|
8780
8850
|
"persistent"
|
|
8781
|
-
]).default("persistent"));
|
|
8851
|
+
]).default("persistent")).option("--cap:delegate", "also request the right to delegate this authority (canDelegate) to other identities");
|
|
8782
8852
|
const configureCall = (cmd, capabilityOnly) => {
|
|
8783
8853
|
cmd.description((capabilityOnly ? "Request a capability without executing a call. " : "Invoke a request. ") + "`<methodRef>` is `[svc::][iface::]method[@hash]`. Use `--p:<name> <value>` (or `--p:<name>=<value>`) as a shortcut for `--param <name>=<value>`. Run `hub call <methodRef> --help` to see the method-specific `--p:` flags derived from the live schema.").option("--params <json>", "inline params JSON, or \"-\" to read stdin").option("--param <kv...>", "param override, key=value (JSON or string)").option("--no-validate", "skip schema-based param validation").helpOption(false).option("-h, --help", "show help (includes method params when reachable)").action(async (methodRef, opts, cmd) => {
|
|
8784
8854
|
if (opts.help) {
|
|
@@ -8794,6 +8864,7 @@ async function main(rawArgv, executableName = "linkrpc") {
|
|
|
8794
8864
|
const allowParams = opts["cap:allowParam"];
|
|
8795
8865
|
if (!capabilityOnly && allowParams !== void 0 && !requestCap) throw new Error("--cap:allow-param requires --cap:request.");
|
|
8796
8866
|
if (!capabilityOnly && cmd.getOptionValueSource("cap:duration") === "cli" && !requestCap) throw new Error("--cap:duration requires --cap:request.");
|
|
8867
|
+
if (!capabilityOnly && opts["cap:delegate"] === true && !requestCap) throw new Error("--cap:delegate requires --cap:request.");
|
|
8797
8868
|
resolveSigning(profile, g_invocation?.values ?? {}, capabilityOnly || requestCap);
|
|
8798
8869
|
const validation = opts.validate === false ? "off" : effectiveValidation(profile);
|
|
8799
8870
|
if ((capabilityOnly || requestCap) && validation === "off") throw new Error("Capability requests require schema validation; remove --no-validate/--validation off.");
|
|
@@ -8807,7 +8878,8 @@ async function main(rawArgv, executableName = "linkrpc") {
|
|
|
8807
8878
|
requestCap,
|
|
8808
8879
|
capabilityOnly,
|
|
8809
8880
|
signingSession: session,
|
|
8810
|
-
duration: opts["cap:duration"]
|
|
8881
|
+
duration: opts["cap:duration"],
|
|
8882
|
+
delegate: opts["cap:delegate"] === true
|
|
8811
8883
|
});
|
|
8812
8884
|
process.stdout.write(out + "\n");
|
|
8813
8885
|
}, {
|
|
@@ -9018,6 +9090,30 @@ Batch options:
|
|
|
9018
9090
|
local.close();
|
|
9019
9091
|
}
|
|
9020
9092
|
});
|
|
9093
|
+
program.command("http-export").description("Serve loopback ports of Hub compute nodes at <port>.<service>.localhost over HTTP and WebSocket.").option("--port <n>", "Local port to listen on", (value) => parsePositiveInteger(value, "--port"), 80).option("--host <address>", "Local address to bind (repeatable; default 127.0.0.1 and ::1)", collectOption).option("--base-domain <domain>", "Base domain of exported hostnames", "localhost").action(async (opts) => {
|
|
9094
|
+
const localEp = needEndpoint(endpoint);
|
|
9095
|
+
const local = await connect(localEp, wireLog("hub"));
|
|
9096
|
+
try {
|
|
9097
|
+
const session = await setupSigning(local.channel, local.signing, getPrincipalSpec(), { negotiateHubCaps: isHubEndpoint(localEp) });
|
|
9098
|
+
reportIdentity(session);
|
|
9099
|
+
const server = await httpExportCommand({
|
|
9100
|
+
local,
|
|
9101
|
+
requestDirectoryAccess: (serviceId) => requestDirectoryAccess(session, serviceId, {}),
|
|
9102
|
+
port: opts.port,
|
|
9103
|
+
hosts: opts.host ?? ["127.0.0.1", "::1"],
|
|
9104
|
+
baseDomain: opts.baseDomain,
|
|
9105
|
+
onError: (error) => process.stderr.write(`linkrpc: ${error.message}\n`)
|
|
9106
|
+
});
|
|
9107
|
+
try {
|
|
9108
|
+
process.stderr.write(`linkrpc: HTTP export listening at ${server.urls.join(", ")}\n`);
|
|
9109
|
+
await _untilSignalled();
|
|
9110
|
+
} finally {
|
|
9111
|
+
await server.close();
|
|
9112
|
+
}
|
|
9113
|
+
} finally {
|
|
9114
|
+
local.close();
|
|
9115
|
+
}
|
|
9116
|
+
});
|
|
9021
9117
|
program.command("json-rpc-stdio <serviceId>").description("Expose <serviceId>::jsonRpcConnection::connectRaw as a newline-delimited JSON-RPC endpoint on this process's stdin/stdout.").option("--params <json>", "JSON value passed to the remote transport factory").action(async (serviceId, opts) => {
|
|
9022
9118
|
const localEp = needEndpoint(endpoint);
|
|
9023
9119
|
let params;
|
|
@@ -9082,11 +9178,16 @@ Batch options:
|
|
|
9082
9178
|
const remote = await connectTargetEndpoint(targetEp, serviceId);
|
|
9083
9179
|
try {
|
|
9084
9180
|
reportIdentity(await setupSigning(local.channel, local.signing, getPrincipalSpec(), { negotiateHubCaps: isHubEndpoint(localEp) }));
|
|
9181
|
+
const lost = Promise.race([local.closed.then(() => "source"), remote.closed.then(() => "target")]).then((side) => {
|
|
9182
|
+
process.stderr.write(`linkrpc: tunnel: the ${side} connection closed\n`);
|
|
9183
|
+
process.exitCode = 1;
|
|
9184
|
+
});
|
|
9085
9185
|
await tunnelCommand({
|
|
9086
9186
|
serviceId,
|
|
9087
9187
|
local,
|
|
9088
9188
|
remote,
|
|
9089
|
-
bidi: cmdOpts.bidi
|
|
9189
|
+
bidi: cmdOpts.bidi,
|
|
9190
|
+
stop: Promise.race([lost, _untilSignalled()])
|
|
9090
9191
|
});
|
|
9091
9192
|
} finally {
|
|
9092
9193
|
remote.close();
|
|
@@ -9113,10 +9214,10 @@ Batch options:
|
|
|
9113
9214
|
const principal = typeof cmdOpts.signAs === "string" ? parsePrincipalSpec(cmdOpts.signAs) : getPrincipalSpec();
|
|
9114
9215
|
reportIdentity(await setupSigning(hub.channel, hub.signing, principal, { negotiateHubCaps: isHubEndpoint(localEp) }));
|
|
9115
9216
|
}
|
|
9116
|
-
const participant = targetEp === void 0 ? await connectStdioParticipant() : {
|
|
9117
|
-
connection
|
|
9118
|
-
closed:
|
|
9119
|
-
};
|
|
9217
|
+
const participant = targetEp === void 0 ? await connectStdioParticipant() : await connectTargetEndpoint(targetEp, cmdOpts.claim ?? "").then((connection) => ({
|
|
9218
|
+
connection,
|
|
9219
|
+
closed: connection.closed
|
|
9220
|
+
}));
|
|
9120
9221
|
try {
|
|
9121
9222
|
await proxyCommand({
|
|
9122
9223
|
hub,
|
|
@@ -9251,7 +9352,7 @@ Batch options:
|
|
|
9251
9352
|
process.once("SIGINT", onSignal);
|
|
9252
9353
|
process.once("SIGTERM", onSignal);
|
|
9253
9354
|
try {
|
|
9254
|
-
const { runApprovalUi } = await import("./runApprovalUi-
|
|
9355
|
+
const { runApprovalUi } = await import("./runApprovalUi-Diol5P5a.js");
|
|
9255
9356
|
await runApprovalUi({
|
|
9256
9357
|
client,
|
|
9257
9358
|
signal: stop.signal
|
|
@@ -9266,7 +9367,7 @@ Batch options:
|
|
|
9266
9367
|
registerViewCommands(program, (action) => withChannel(endpoint, getPrincipalSpec(), action));
|
|
9267
9368
|
program.command("ui").description("Launch the terminal UI (form-based browser of services + methods).").action(async () => {
|
|
9268
9369
|
const acquired = await acquireConnection(endpoint);
|
|
9269
|
-
const { runUi } = await import("./runUi-
|
|
9370
|
+
const { runUi } = await import("./runUi-DDJrDeBg.js");
|
|
9270
9371
|
try {
|
|
9271
9372
|
await runUi({
|
|
9272
9373
|
endpoint: acquired.ep,
|
|
@@ -9278,13 +9379,27 @@ Batch options:
|
|
|
9278
9379
|
acquired.running?.dispose();
|
|
9279
9380
|
}
|
|
9280
9381
|
});
|
|
9281
|
-
if (profile === "hub") program.command("logout").description("Delete the stored
|
|
9282
|
-
const
|
|
9283
|
-
|
|
9284
|
-
|
|
9382
|
+
if (profile === "hub") program.command("logout").description("Delete the stored keypair and cached capabilities of the identity selected by --principal (default: the user:hubrpc-cli fallback). Asks for confirmation unless --yes is given. The next call mints a fresh keypair, which hubs that trusted the old key do not accept.").option("-y, --yes", "delete without asking for confirmation").action(async (opts) => {
|
|
9383
|
+
const target = cliIdentityTarget(getPrincipalSpec());
|
|
9384
|
+
const principal = await readCliIdentity(target);
|
|
9385
|
+
if (principal === void 0) {
|
|
9386
|
+
process.stdout.write(`linkrpc: no stored identity for ${target.label} (${target.file}).\n`);
|
|
9285
9387
|
return;
|
|
9286
9388
|
}
|
|
9287
|
-
|
|
9389
|
+
const description = `identity ${target.label} (${principal}) at ${target.file}`;
|
|
9390
|
+
if (opts.yes !== true) {
|
|
9391
|
+
if (process.stdin.isTTY !== true || process.stderr.isTTY !== true) throw new Error(`Refusing to delete ${description} without confirmation; pass --yes.`);
|
|
9392
|
+
const readline = createInterface({
|
|
9393
|
+
input: process.stdin,
|
|
9394
|
+
output: process.stderr
|
|
9395
|
+
});
|
|
9396
|
+
const answer = await readline.question(`Delete ${description} and its cached capabilities? This cannot be undone. [y/N] `).finally(() => readline.close());
|
|
9397
|
+
if (!/^y(es)?$/i.test(answer.trim())) {
|
|
9398
|
+
process.stderr.write("linkrpc: logout cancelled.\n");
|
|
9399
|
+
return;
|
|
9400
|
+
}
|
|
9401
|
+
}
|
|
9402
|
+
for (const f of await deleteCliIdentity(target)) process.stdout.write(`removed ${f}\n`);
|
|
9288
9403
|
});
|
|
9289
9404
|
program.command("completions <shell>").description("Print a shell completion script. Supported: powershell. Install with `hub completions powershell | Out-String | Invoke-Expression` (one-shot) or append to $PROFILE.").action((shell) => {
|
|
9290
9405
|
try {
|
|
@@ -9634,7 +9749,8 @@ async function acquireConnection(endpoint) {
|
|
|
9634
9749
|
if (endpoint === void 0 && g_invocation?.profile === "hub") try {
|
|
9635
9750
|
return { ep: resolveLocalEndpoint() };
|
|
9636
9751
|
} catch {
|
|
9637
|
-
|
|
9752
|
+
const ignoredEnvironmentHint = ignoredEndpointEnvironmentHint();
|
|
9753
|
+
throw new Error(`No endpoint configured through flags, environment, or context, and the local Hub daemon is not running. Pass ${endpointOptionsDescription()}, or start the daemon (any \`hub services run\` starts it).` + (ignoredEnvironmentHint === void 0 ? "" : ` ${ignoredEnvironmentHint}.`));
|
|
9638
9754
|
}
|
|
9639
9755
|
return { ep: needEndpoint(endpoint) };
|
|
9640
9756
|
}
|
|
@@ -9644,11 +9760,23 @@ function reportIdentity(session) {
|
|
|
9644
9760
|
}
|
|
9645
9761
|
function needEndpoint(endpoint) {
|
|
9646
9762
|
if (!endpoint) {
|
|
9647
|
-
|
|
9763
|
+
const ignoredEnvironmentHint = ignoredEndpointEnvironmentHint();
|
|
9764
|
+
process.stderr.write(`linkrpc: this command requires ${endpointOptionsDescription()}.\n` + (ignoredEnvironmentHint === void 0 ? "" : `linkrpc: ${ignoredEnvironmentHint}.\n`));
|
|
9648
9765
|
process.exit(2);
|
|
9649
9766
|
}
|
|
9650
9767
|
return endpoint;
|
|
9651
9768
|
}
|
|
9769
|
+
function endpointOptionsDescription() {
|
|
9770
|
+
const options = "--endpoint / --endpoint-cmd / --endpoint-cmd-stdio or a configured context";
|
|
9771
|
+
return g_invocation?.profile === "hub" && g_invocation.environmentApplied ? `${options} or LINKRPC_ENDPOINT` : options;
|
|
9772
|
+
}
|
|
9773
|
+
function ignoredEndpointEnvironmentHint() {
|
|
9774
|
+
const invocation = g_invocation;
|
|
9775
|
+
if (invocation === void 0 || invocation.environmentApplied) return void 0;
|
|
9776
|
+
const variable = process.env.LINKRPC_ENDPOINT !== void 0 ? "LINKRPC_ENDPOINT" : process.env.HUBRPC_ENDPOINT !== void 0 ? "HUBRPC_ENDPOINT" : void 0;
|
|
9777
|
+
if (variable === void 0) return void 0;
|
|
9778
|
+
return invocation.profile === "rpc" ? `${variable} is set but only used by hub commands: run \`linkrpc hub <command>\` (or pass --use-env)` : `${variable} is set but ignored because environment overrides are disabled; pass --use-env to apply it`;
|
|
9779
|
+
}
|
|
9652
9780
|
/** The `--target-endpoint*` options shared by `tunnel` and `proxy`. */
|
|
9653
9781
|
function addTargetEndpointOptions(command) {
|
|
9654
9782
|
return command.option("--target-endpoint <uri>", "target endpoint URI (unix:/path?token=…, npipe://./pipe/…, ws[s]://host?token=…, cmd:?command=… or cmd-stdio:?command=…)").option("--target-endpoint-cmd <command>", "spawn the target as a server, connect via an injected env socket; the child sees the claimed service id as grantedServiceIdNamespace via hubGrantedServiceId::get").option("--target-endpoint-cmd-stdio <command>", "spawn the target and talk linkrpc over its stdio").option("--target-endpoint-cmd-env <key=value>", "env var for the --target-endpoint-cmd / --target-endpoint-cmd-stdio child (repeatable)", (val, acc) => {
|
|
@@ -9802,4 +9930,4 @@ function safeJson(value) {
|
|
|
9802
9930
|
//#endregion
|
|
9803
9931
|
export { formatCondition as _, formatCommandLegend as a, targetId as b, safeTerminalText as c, ObservablePromise as d, observableValue as f, resolveViewTarget as g, Disposable as h, dispatchHostKey as i, approvalDetailLines as l, derived as m, views as n, hostCommands as o, autorun as p, ViewFrame as r, matchesKey as s, runCli as t, ObservableLazyPromise as u, interfaceTarget as v, matchesTarget as y };
|
|
9804
9932
|
|
|
9805
|
-
//# sourceMappingURL=cli-
|
|
9933
|
+
//# sourceMappingURL=cli-D_nbiyek.js.map
|