@hediet/linkrpc-cli 0.0.3-next.20260926.7 → 0.0.3-next.20261006.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 +5 -1
- package/dist/chunks/{cli-IfKpF0E1.js → cli-yDtBqjCT.js} +16 -347
- package/dist/chunks/cli-yDtBqjCT.js.map +1 -0
- package/dist/chunks/{runApprovalUi-Kt6FnH9y.js → runApprovalUi-eLDf_5ZN.js} +2 -2
- package/dist/chunks/runApprovalUi-eLDf_5ZN.js.map +1 -0
- package/dist/chunks/{runComplete-F95L0neY.js → runComplete-CM1sMWnI.js} +36 -21
- package/dist/chunks/runComplete-CM1sMWnI.js.map +1 -0
- package/dist/chunks/{runUi-DD7DYroJ.js → runUi-DF_HTMk9.js} +3 -3
- package/dist/chunks/runUi-DF_HTMk9.js.map +1 -0
- 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 +6 -6
- package/dist/chunks/cli-IfKpF0E1.js.map +0 -1
- package/dist/chunks/runApprovalUi-Kt6FnH9y.js.map +0 -1
- package/dist/chunks/runComplete-F95L0neY.js.map +0 -1
- package/dist/chunks/runUi-DD7DYroJ.js.map +0 -1
package/README.md
CHANGED
|
@@ -439,7 +439,11 @@ hub --endpoint unix:/run/hub.sock json-rpc-stdio language-server
|
|
|
439
439
|
|
|
440
440
|
These commands resolve the same persistent identity selected by the global
|
|
441
441
|
`--principal` option and endpoint configuration. Approval commands discover and
|
|
442
|
-
validate Hub access manifests through the shared
|
|
442
|
+
validate Hub access manifests through the shared observable approval client in
|
|
443
|
+
`@hediet/linkrpc-infra/approval`. The CLI owns formatting and the terminal UI;
|
|
444
|
+
its interactive adapter supplies `createTerminalConsentPrompt` from
|
|
445
|
+
`@hediet/linkrpc-hub` when no prompt is provided. Generic infrastructure callers
|
|
446
|
+
must pass an explicit `ConsentPrompt` to `runInteractive(signal, prompt)`. The
|
|
443
447
|
resolved identity acts as the capability issuer/root: commands only show or
|
|
444
448
|
decide requests whose `acceptableRootIds` allow that root, while minted
|
|
445
449
|
capabilities retain the request consumer as their audience.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as connectViaRootOverlay, C as findMethodInSchema, D as formatPrincipalSource, E as logoutCliIdentity, F as describeSchema, H as mcpForwardInterface, I as explainValidation, L as validateValueAgainstSchema, M as resolveTargetEndpoint, N as resolvedEndpointToConfig, O as parsePrincipalSpec, P as describeObjectParams, S as fetchSchema$1, V as MethodRefWithOptHash, a as resolveStaticHubSchemaSource, b as setupSigning, c as resolveInvocationEndpoint, d as formatContextReference, i as loadStaticHubSchema, j as connectViaTransport, k as connect, l as validationDefault, n as StaticHubReflection, o as mutationReference, p as resolveCliInvocation, r as withStaticHubReflection, s as resolveInvocationContext, t as completeForLine, u as ContextStore, v as requestReflectionAccess, w as walkHub, x as fetchDefaults, y as requestTopologyAccess, z as mergeParams } from "./runComplete-
|
|
1
|
+
import { A as connectViaRootOverlay, C as findMethodInSchema, D as formatPrincipalSource, E as logoutCliIdentity, F as describeSchema, H as mcpForwardInterface, I as explainValidation, L as validateValueAgainstSchema, M as resolveTargetEndpoint, N as resolvedEndpointToConfig, O as parsePrincipalSpec, P as describeObjectParams, S as fetchSchema$1, V as MethodRefWithOptHash, a as resolveStaticHubSchemaSource, b as setupSigning, c as resolveInvocationEndpoint, d as formatContextReference, i as loadStaticHubSchema, j as connectViaTransport, k as connect, l as validationDefault, n as StaticHubReflection, o as mutationReference, p as resolveCliInvocation, r as withStaticHubReflection, s as resolveInvocationContext, t as completeForLine, u as ContextStore, v as requestReflectionAccess, w as walkHub, x as fetchDefaults, y as requestTopologyAccess, z as mergeParams } from "./runComplete-CM1sMWnI.js";
|
|
2
2
|
import { a as derived, i as autorun, r as observableValue } from "./dist-BOcSU4-O.js";
|
|
3
|
-
import { ErrorCode, INTERFACE_TEMPLATES_EXTENSION, LinkRpcConnection, RpcError,
|
|
3
|
+
import { ErrorCode, INTERFACE_TEMPLATES_EXTENSION, LinkRpcConnection, RpcError, computeInterfaceHash, connectTransports, createSchemaToZod, exportStaticHubSchema, generateTsContract, generateTsInterface, interfaceTemplateArgumentsEquivalent, interfaceTemplateMemberName, isAssignable, jcsCanonicalize } from "@hediet/linkrpc";
|
|
4
4
|
import { WebSocketTransport, connectNdjson, formatEndpointUri, isHubEndpoint, openWebSocket, parseEndpointUri, runInitializeHandshake, traceMessageTransport as traceMessageTransport$1 } from "@hediet/linkrpc/node";
|
|
5
5
|
import { SocketServer } from "@hediet/linkrpc-hub/hub/server/node";
|
|
6
6
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
@@ -11,19 +11,19 @@ import { spawnCommand } from "@hediet/linkrpc-hub/spawn";
|
|
|
11
11
|
import { tapTransport } from "@hediet/linkrpc-hub/hub/server/transit";
|
|
12
12
|
import * as net from "node:net";
|
|
13
13
|
import { mkdir, open, readFile, writeFile } from "node:fs/promises";
|
|
14
|
-
import { DEFAULT_WALK_DEPTH, HubDirectoryExplorer, fetchSchema,
|
|
14
|
+
import { DEFAULT_WALK_DEPTH, HubDirectoryExplorer, fetchSchema, hubGrantedServiceIdInterface, hubServiceIdRegistryInterface } from "@hediet/linkrpc/hub/common";
|
|
15
15
|
import { Command, InvalidArgumentError } from "commander";
|
|
16
|
+
import { bootstrapApprovalCapability, createHubApprovalClient } from "@hediet/linkrpc-infra/approval";
|
|
16
17
|
import { connectionTokenBinderInterface } from "@hediet/linkrpc-hub/hub/server/connection-token-binder";
|
|
17
18
|
import { spawn } from "node:child_process";
|
|
18
19
|
import { TopologyClient, TopologyNetworkClient, TrafficClient } from "@hediet/linkrpc-infra/inspection";
|
|
19
20
|
import { createInterface } from "node:readline/promises";
|
|
20
21
|
import { stdin, stdout } from "node:process";
|
|
21
|
-
import {
|
|
22
|
+
import { TrafficFlowAggregator, createTerminalConsentPrompt, formatFlowSummary } from "@hediet/linkrpc-hub";
|
|
22
23
|
import { loadHubConfig, printHubConfigSchema } from "@hediet/linkrpc-hub/config-file";
|
|
23
24
|
import * as readline from "node:readline";
|
|
24
25
|
import { emitKeypressEvents } from "node:readline";
|
|
25
26
|
import { connectJsonRpcTransports, connectRawJsonRpcTransport, createNdjsonJsonRpcTransport, jsonRpcConnectionInterface } from "@hediet/linkrpc-infra/json-rpc";
|
|
26
|
-
import { CapabilityProposalIssuer, candidatesForSlot, durationToExp } from "@hediet/linkrpc-hub/hub/server";
|
|
27
27
|
import { GRAPH_INTERFACE_TAG, IMMUTABLE_GRAPH_INTERFACE_ID, ROOT_WATCH_INTERFACE_ID, evaluateGraphPresentation, graphPresentationInterface, graphPresentationSchema, isGraphRef, standardGraphRuntimeOptions, validateGraphInterfaceSchema } from "@hediet/linkrpc-infra/graph";
|
|
28
28
|
import React from "react";
|
|
29
29
|
import { Box, Text, measureElement, render } from "ink";
|
|
@@ -2958,340 +2958,13 @@ function durationTone(duration) {
|
|
|
2958
2958
|
}
|
|
2959
2959
|
//#endregion
|
|
2960
2960
|
//#region src/commands/approval.ts
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
serviceId: { prefix: "" },
|
|
2968
|
-
interfaceId: { exact: "hubAccessManifest" },
|
|
2969
|
-
members: [{ prefix: "" }]
|
|
2970
|
-
},
|
|
2971
|
-
canInvoke: true
|
|
2972
|
-
}, {
|
|
2973
|
-
target: {
|
|
2974
|
-
serviceId: { prefix: "" },
|
|
2975
|
-
interfaceId: { exact: "hubrpc.directory" },
|
|
2976
|
-
members: [{ prefix: "" }]
|
|
2977
|
-
},
|
|
2978
|
-
canInvoke: true
|
|
2979
|
-
}];
|
|
2980
|
-
const approvalCommandPermissionsJson = jcsCanonicalize(approvalCommandPermissions);
|
|
2981
|
-
/**
|
|
2982
|
-
* Installs the root identity's narrowly scoped self-capability used by the
|
|
2983
|
-
* approval scanner. Reusing the non-expiring exact grant prevents repeated
|
|
2984
|
-
* commands from growing the principal's durable capability bag.
|
|
2985
|
-
*/
|
|
2986
|
-
async function bootstrapApprovalCommandCapability(principal) {
|
|
2987
|
-
const existing = principal.capBag.capabilities.find((capability) => capability.issuer === principal.id && capability.audience === principal.id && capability.expiresAtMs === void 0 && capability.parentHash === void 0 && jcsCanonicalize(capability.permissions) === approvalCommandPermissionsJson);
|
|
2988
|
-
if (existing) return existing;
|
|
2989
|
-
const capability = await new CapabilityProposalIssuer(principal.identity).mint({
|
|
2990
|
-
audience: principal.id,
|
|
2991
|
-
permissions: approvalCommandPermissions
|
|
2992
|
-
});
|
|
2993
|
-
await principal.capBag.add(capability);
|
|
2994
|
-
return capability;
|
|
2995
|
-
}
|
|
2996
|
-
const MANIFEST_INTERFACE_ID = hubAccessManifestInterface.info.id;
|
|
2997
|
-
const AGGREGATE_SERVICE_ID = "linkrpc-cli.approvals";
|
|
2998
|
-
const EXTERNAL_ID_PREFIX = "ar1_";
|
|
2999
|
-
/**
|
|
3000
|
-
* CLI-facing approval operations over the hub's shared manifest frontend.
|
|
3001
|
-
* The underlying {@link ApproveClient} remains authoritative for snapshots and
|
|
3002
|
-
* acknowledgement. One-shot commands mint before calling its acknowledged
|
|
3003
|
-
* decision path; {@link runManifestApprover} drives the interactive UI.
|
|
3004
|
-
*/
|
|
3005
|
-
var ApprovalCommandClient = class {
|
|
3006
|
-
_principalId;
|
|
3007
|
-
_manifest;
|
|
3008
|
-
_client;
|
|
3009
|
-
_issuer;
|
|
3010
|
-
_fetchDirectory;
|
|
3011
|
-
_log;
|
|
3012
|
-
_disposeExtra;
|
|
3013
|
-
_lastClientError;
|
|
3014
|
-
_disposed = false;
|
|
3015
|
-
constructor(options) {
|
|
3016
|
-
this._principalId = options.identity.publicSigningIdentity.principal;
|
|
3017
|
-
this._manifest = options.manifest;
|
|
3018
|
-
this._issuer = new CapabilityProposalIssuer(options.identity);
|
|
3019
|
-
this._fetchDirectory = options.fetchDirectory;
|
|
3020
|
-
this._log = options.log ?? (() => {});
|
|
3021
|
-
this._disposeExtra = options.dispose;
|
|
3022
|
-
this._client = new ApproveClient({
|
|
3023
|
-
manifest: this._manifest,
|
|
3024
|
-
ownPrincipalId: this._principalId,
|
|
3025
|
-
timeoutMs: options.timeoutMs,
|
|
3026
|
-
log: (line) => {
|
|
3027
|
-
this._lastClientError = line;
|
|
3028
|
-
this._log(line);
|
|
3029
|
-
}
|
|
3030
|
-
});
|
|
3031
|
-
}
|
|
3032
|
-
get principalId() {
|
|
3033
|
-
return this._principalId;
|
|
3034
|
-
}
|
|
3035
|
-
async requests() {
|
|
3036
|
-
return this._toPendingRequests(await this._currentRequests());
|
|
3037
|
-
}
|
|
3038
|
-
/**
|
|
3039
|
-
* Subscribe to the authoritative manifest snapshot. The callback is invoked
|
|
3040
|
-
* immediately and whenever the watch reconnects or the request set changes.
|
|
3041
|
-
*/
|
|
3042
|
-
watch(listener) {
|
|
3043
|
-
return autorun((reader) => {
|
|
3044
|
-
const state = this._client.state.read(reader);
|
|
3045
|
-
listener({
|
|
3046
|
-
state,
|
|
3047
|
-
requests: this._toPendingRequests(this._client.requests.read(reader)),
|
|
3048
|
-
...state === "stale" && this._lastClientError !== void 0 ? { error: this._lastClientError } : {}
|
|
3049
|
-
});
|
|
3050
|
-
});
|
|
3051
|
-
}
|
|
3052
|
-
/** Force an immediate manifest reconciliation. */
|
|
3053
|
-
async refresh() {
|
|
3054
|
-
await this._currentRequests();
|
|
3055
|
-
}
|
|
3056
|
-
async deny(externalId, reason, expected) {
|
|
3057
|
-
const internalId = decodeApprovalRequestId(externalId);
|
|
3058
|
-
const pending = await this._requirePending(internalId, externalId);
|
|
3059
|
-
if (expected !== void 0) this._requireUnchanged(pending, expected);
|
|
3060
|
-
const result = await this._client.decide(internalId, {
|
|
3061
|
-
status: "denied",
|
|
3062
|
-
...reason !== void 0 ? { reason } : {}
|
|
3063
|
-
});
|
|
3064
|
-
if (result === "gone") throw new Error(`approval request '${externalId}' is no longer pending`);
|
|
3065
|
-
return result;
|
|
3066
|
-
}
|
|
3067
|
-
async approve(externalId) {
|
|
3068
|
-
return this.approvePrepared(await this.prepareApproval(externalId));
|
|
3069
|
-
}
|
|
3070
|
-
/**
|
|
3071
|
-
* Resolve the exact authority that an approval will mint. Interactive
|
|
3072
|
-
* surfaces render this result before asking for confirmation.
|
|
3073
|
-
*/
|
|
3074
|
-
async prepareApproval(externalId) {
|
|
3075
|
-
const internalId = decodeApprovalRequestId(externalId);
|
|
3076
|
-
const pending = await this._requirePending(internalId, externalId);
|
|
3077
|
-
const resolved = await this._resolveRequest(pending.request);
|
|
3078
|
-
if ("denied" in resolved) throw new Error(`approval request '${externalId}' cannot be granted: ${resolved.denied}`);
|
|
3079
|
-
const sourceServiceId = approvalRequestSource(internalId);
|
|
3080
|
-
return {
|
|
3081
|
-
pending: {
|
|
3082
|
-
id: externalId,
|
|
3083
|
-
request: pending.request,
|
|
3084
|
-
revision: pending.revision,
|
|
3085
|
-
...sourceServiceId === void 0 ? {} : { sourceServiceId }
|
|
3086
|
-
},
|
|
3087
|
-
permissions: await toSignedPermissions(resolved.permissions, pending.request.consumer.principal, pending.request.duration),
|
|
3088
|
-
...resolved.resolvedSlot === void 0 ? {} : { resolvedSlot: resolved.resolvedSlot }
|
|
3089
|
-
};
|
|
3090
|
-
}
|
|
3091
|
-
/** Approve only if the request is still exactly the one that was reviewed. */
|
|
3092
|
-
async approvePrepared(prepared) {
|
|
3093
|
-
const externalId = prepared.pending.id;
|
|
3094
|
-
const internalId = decodeApprovalRequestId(externalId);
|
|
3095
|
-
const pending = await this._requirePending(internalId, externalId);
|
|
3096
|
-
this._requireUnchanged(pending, prepared.pending);
|
|
3097
|
-
const decision = await this._grantDecision(prepared);
|
|
3098
|
-
const result = await this._client.decide(internalId, decision);
|
|
3099
|
-
if (result === "gone") throw new Error(`approval request '${externalId}' is no longer pending`);
|
|
3100
|
-
if (decision.status !== "granted") throw new Error(`approval request '${externalId}' could not be granted` + (decision.reason !== void 0 ? `: ${decision.reason}` : ""));
|
|
3101
|
-
return result;
|
|
3102
|
-
}
|
|
3103
|
-
async runInteractive(signal, prompt) {
|
|
3104
|
-
await this._currentRequests();
|
|
3105
|
-
const approver = runManifestApprover({
|
|
3106
|
-
manifest: this._manifest,
|
|
3107
|
-
issuer: this._issuer,
|
|
3108
|
-
ownPrincipalId: this._principalId,
|
|
3109
|
-
...this._fetchDirectory !== void 0 ? { fetchDirectory: this._fetchDirectory } : {},
|
|
3110
|
-
...prompt !== void 0 ? { prompt } : {},
|
|
3111
|
-
log: this._log
|
|
3112
|
-
});
|
|
3113
|
-
try {
|
|
3114
|
-
await waitForAbort(signal);
|
|
3115
|
-
} finally {
|
|
3116
|
-
approver.dispose();
|
|
3117
|
-
}
|
|
3118
|
-
}
|
|
3119
|
-
dispose() {
|
|
3120
|
-
if (this._disposed) return;
|
|
3121
|
-
this._disposed = true;
|
|
3122
|
-
this._client.dispose();
|
|
3123
|
-
this._disposeExtra?.();
|
|
3124
|
-
}
|
|
3125
|
-
async _currentRequests() {
|
|
3126
|
-
await this._client.refresh();
|
|
3127
|
-
if (this._client.state.get() === "stale") throw new Error(this._lastClientError ?? "could not read pending approval requests");
|
|
3128
|
-
return this._client.requests.get();
|
|
3129
|
-
}
|
|
3130
|
-
_toPendingRequests(requests) {
|
|
3131
|
-
return requests.map(({ id, request, revision }) => {
|
|
3132
|
-
const sourceServiceId = approvalRequestSource(id);
|
|
3133
|
-
return {
|
|
3134
|
-
id: encodeApprovalRequestId(id),
|
|
3135
|
-
request,
|
|
3136
|
-
revision,
|
|
3137
|
-
...sourceServiceId === void 0 ? {} : { sourceServiceId }
|
|
3138
|
-
};
|
|
3139
|
-
}).sort((a, b) => a.id.localeCompare(b.id));
|
|
3140
|
-
}
|
|
3141
|
-
async _requirePending(internalId, externalId) {
|
|
3142
|
-
const pending = (await this._currentRequests()).find((request) => request.id === internalId);
|
|
3143
|
-
if (!pending) throw new Error(`approval request '${externalId}' is not pending for principal '${this._principalId}'`);
|
|
3144
|
-
return pending;
|
|
3145
|
-
}
|
|
3146
|
-
_requireUnchanged(actual, expected) {
|
|
3147
|
-
if (jcsCanonicalize(actual.request) !== jcsCanonicalize(expected.request)) throw new Error(`approval request '${expected.id}' changed after it was reviewed; review it again`);
|
|
3148
|
-
}
|
|
3149
|
-
async _resolveRequest(request) {
|
|
3150
|
-
let permissions;
|
|
3151
|
-
let resolvedSlot;
|
|
3152
|
-
if (request.kind === "direct") permissions = request.permissions;
|
|
3153
|
-
else {
|
|
3154
|
-
if (this._fetchDirectory === void 0) return { denied: "no directory available to resolve discover candidates" };
|
|
3155
|
-
const slot = {
|
|
3156
|
-
interfaces: request.interfaces.map((item) => ({
|
|
3157
|
-
id: item.id,
|
|
3158
|
-
required: item.required !== false,
|
|
3159
|
-
...item.hash !== void 0 ? { hash: item.hash } : {}
|
|
3160
|
-
})),
|
|
3161
|
-
members: request.members.map((item) => ({
|
|
3162
|
-
interfaceId: item.interfaceId,
|
|
3163
|
-
member: item.member,
|
|
3164
|
-
required: item.required !== false
|
|
3165
|
-
}))
|
|
3166
|
-
};
|
|
3167
|
-
const candidate = candidatesForSlot(slot, await this._fetchDirectory())[0];
|
|
3168
|
-
if (!candidate) return { denied: "no candidate service satisfies the requested interfaces" };
|
|
3169
|
-
const present = new Set(candidate.satisfiedInterfaces.map((item) => item.id));
|
|
3170
|
-
permissions = buildSlotPermissions(candidate.serviceId, slot.interfaces, slot.members, present);
|
|
3171
|
-
resolvedSlot = {
|
|
3172
|
-
serviceId: candidate.serviceId,
|
|
3173
|
-
satisfiedInterfaces: candidate.satisfiedInterfaces.map((item) => item.id)
|
|
3174
|
-
};
|
|
3175
|
-
}
|
|
3176
|
-
return {
|
|
3177
|
-
permissions,
|
|
3178
|
-
...resolvedSlot === void 0 ? {} : { resolvedSlot }
|
|
3179
|
-
};
|
|
3180
|
-
}
|
|
3181
|
-
async _grantDecision(prepared) {
|
|
3182
|
-
const request = prepared.pending.request;
|
|
3183
|
-
const capability = await this._issuer.mint({
|
|
3184
|
-
audience: request.consumer.principal,
|
|
3185
|
-
permissions: prepared.permissions,
|
|
3186
|
-
expiresAtMs: durationToExp(request.duration)
|
|
3187
|
-
});
|
|
3188
|
-
return {
|
|
3189
|
-
status: "granted",
|
|
3190
|
-
granted: prepared.resolvedSlot === void 0 ? {
|
|
3191
|
-
kind: "direct",
|
|
3192
|
-
capabilities: [capability]
|
|
3193
|
-
} : {
|
|
3194
|
-
kind: "discover",
|
|
3195
|
-
serviceId: prepared.resolvedSlot.serviceId,
|
|
3196
|
-
satisfiedInterfaces: [...prepared.resolvedSlot.satisfiedInterfaces],
|
|
3197
|
-
capabilities: [capability]
|
|
3198
|
-
}
|
|
3199
|
-
};
|
|
3200
|
-
}
|
|
3201
|
-
};
|
|
3202
|
-
/**
|
|
3203
|
-
* Discover every manifest in the connected hub and expose it through one
|
|
3204
|
-
* validated, namespaced aggregate. This is the same discovery/validation path
|
|
3205
|
-
* used by the hub's approval UI.
|
|
3206
|
-
*/
|
|
3207
|
-
function createHubApprovalCommandClient(connection, identity, log) {
|
|
3208
|
-
const explorer = new HubDirectoryExplorer(connection.channel);
|
|
3209
|
-
const sourceCache = /* @__PURE__ */ new Map();
|
|
3210
|
-
let directoryChanged;
|
|
3211
|
-
const watchStarted = explorer.watch(() => directoryChanged?.());
|
|
3212
|
-
const fetchDirectory = async () => {
|
|
3213
|
-
await watchStarted;
|
|
3214
|
-
return explorer.result.listings.map((entry) => ({
|
|
3215
|
-
serviceId: entry.serviceId,
|
|
3216
|
-
interfaceId: entry.interfaceId,
|
|
3217
|
-
hash: entry.hash,
|
|
3218
|
-
...entry.serviceDescription === void 0 ? {} : { serviceDescription: entry.serviceDescription },
|
|
3219
|
-
...entry.rootPrincipalSets === void 0 ? {} : { rootPrincipalSets: entry.rootPrincipalSets }
|
|
3220
|
-
}));
|
|
3221
|
-
};
|
|
3222
|
-
const resolveSources = async () => {
|
|
3223
|
-
const directory = await fetchDirectory();
|
|
3224
|
-
const serviceIds = [...new Set(directory.filter((entry) => entry.interfaceId === MANIFEST_INTERFACE_ID).map((entry) => entry.serviceId))].sort();
|
|
3225
|
-
log?.(`approval: discovered ${serviceIds.length} manifest source${serviceIds.length === 1 ? "" : "s"}${serviceIds.length > 0 ? `: ${serviceIds.join(", ")}` : ""}`);
|
|
3226
|
-
const active = new Set(serviceIds);
|
|
3227
|
-
for (const serviceId of sourceCache.keys()) if (!active.has(serviceId)) sourceCache.delete(serviceId);
|
|
3228
|
-
return serviceIds.map((serviceId) => {
|
|
3229
|
-
const cached = sourceCache.get(serviceId);
|
|
3230
|
-
if (cached !== void 0) return cached;
|
|
3231
|
-
const source = {
|
|
3232
|
-
tag: serviceId,
|
|
3233
|
-
manifest: withApprovalSourceLogging(serviceId === "" ? connection.get(hubAccessManifestInterface) : connection.service(serviceId).get(hubAccessManifestInterface), serviceId, log),
|
|
3234
|
-
preserveOrigin: false
|
|
3235
|
-
};
|
|
3236
|
-
sourceCache.set(serviceId, source);
|
|
3237
|
-
return source;
|
|
3238
|
-
});
|
|
3239
|
-
};
|
|
3240
|
-
const aggregate = new AggregatingHubAccessManifest({
|
|
3241
|
-
resolveSources,
|
|
3242
|
-
watchSources: (onChange) => {
|
|
3243
|
-
directoryChanged = onChange;
|
|
3244
|
-
return () => {
|
|
3245
|
-
if (directoryChanged === onChange) directoryChanged = void 0;
|
|
3246
|
-
};
|
|
3247
|
-
},
|
|
3248
|
-
log
|
|
2961
|
+
function createHubApprovalCommandClient(...args) {
|
|
2962
|
+
const client = createHubApprovalClient(...args);
|
|
2963
|
+
const runInteractive = client.runInteractive.bind(client);
|
|
2964
|
+
return Object.assign(client, {
|
|
2965
|
+
watch: (listener) => autorun((reader) => listener(client.snapshot.read(reader))),
|
|
2966
|
+
runInteractive: (signal, prompt = createTerminalConsentPrompt()) => runInteractive(signal, prompt)
|
|
3249
2967
|
});
|
|
3250
|
-
const pair = new TransportPair();
|
|
3251
|
-
const aggregateServer = LinkRpcConnection.fromTransport(pair.a);
|
|
3252
|
-
const aggregateClient = LinkRpcConnection.fromTransport(pair.b);
|
|
3253
|
-
registerAggregatingManifest(aggregateServer, aggregate, { serviceId: AGGREGATE_SERVICE_ID });
|
|
3254
|
-
return new ApprovalCommandClient({
|
|
3255
|
-
manifest: aggregateClient.service(AGGREGATE_SERVICE_ID).get(hubAccessManifestInterface),
|
|
3256
|
-
identity,
|
|
3257
|
-
fetchDirectory,
|
|
3258
|
-
log,
|
|
3259
|
-
dispose: () => {
|
|
3260
|
-
aggregate.dispose();
|
|
3261
|
-
watchStarted.then((stop) => stop(), () => void 0);
|
|
3262
|
-
explorer.dispose();
|
|
3263
|
-
aggregateClient.close();
|
|
3264
|
-
aggregateServer.close();
|
|
3265
|
-
}
|
|
3266
|
-
});
|
|
3267
|
-
}
|
|
3268
|
-
function withApprovalSourceLogging(manifest, serviceId, log) {
|
|
3269
|
-
if (!log) return manifest;
|
|
3270
|
-
const getDesired = manifest.getDesired.bind(manifest);
|
|
3271
|
-
return new Proxy(manifest, { get: (target, property, receiver) => {
|
|
3272
|
-
if (property !== "getDesired") return Reflect.get(target, property, receiver);
|
|
3273
|
-
return async (...args) => {
|
|
3274
|
-
const result = await getDesired(...args);
|
|
3275
|
-
const count = Object.keys(result.requested).length;
|
|
3276
|
-
log(`approval: source '${serviceId || "<root>"}' has ${count} pending request` + (count === 1 ? "" : "s"));
|
|
3277
|
-
return result;
|
|
3278
|
-
};
|
|
3279
|
-
} });
|
|
3280
|
-
}
|
|
3281
|
-
function encodeApprovalRequestId(internalId) {
|
|
3282
|
-
if (internalId.length === 0) throw new Error("cannot encode an empty approval request id");
|
|
3283
|
-
return `${EXTERNAL_ID_PREFIX}${Buffer.from(internalId, "utf8").toString("base64url")}`;
|
|
3284
|
-
}
|
|
3285
|
-
function decodeApprovalRequestId(externalId) {
|
|
3286
|
-
if (!new RegExp(`^${EXTERNAL_ID_PREFIX}[A-Za-z0-9_-]+$`).test(externalId)) throw new Error(`invalid approval request id '${externalId}'`);
|
|
3287
|
-
const encoded = externalId.slice(4);
|
|
3288
|
-
const decoded = Buffer.from(encoded, "base64url").toString("utf8");
|
|
3289
|
-
if (decoded.length === 0 || encodeApprovalRequestId(decoded) !== externalId) throw new Error(`invalid approval request id '${externalId}'`);
|
|
3290
|
-
return decoded;
|
|
3291
|
-
}
|
|
3292
|
-
function approvalRequestSource(internalId) {
|
|
3293
|
-
const separator = internalId.indexOf("\0");
|
|
3294
|
-
return separator < 0 ? void 0 : internalId.slice(0, separator);
|
|
3295
2968
|
}
|
|
3296
2969
|
function formatApprovalRequests(requests, principalId, json = false) {
|
|
3297
2970
|
if (json) return formatJson({
|
|
@@ -3321,10 +2994,6 @@ function formatApprovalDecision(action, id, principalId, json = false, outcome =
|
|
|
3321
2994
|
});
|
|
3322
2995
|
return outcome === "applied" ? `${action === "approved" ? "Approved" : "Denied"} ${id}.` : `${action === "approved" ? "Approval" : "Denial"} decision accepted for ${id}, but a matching request is still pending; the consumer may have retried.`;
|
|
3323
2996
|
}
|
|
3324
|
-
function waitForAbort(signal) {
|
|
3325
|
-
if (signal.aborted) return Promise.resolve();
|
|
3326
|
-
return new Promise((resolve) => signal.addEventListener("abort", () => resolve(), { once: true }));
|
|
3327
|
-
}
|
|
3328
2997
|
//#endregion
|
|
3329
2998
|
//#region src/commands/identity.ts
|
|
3330
2999
|
function cliIdentity(session) {
|
|
@@ -7250,7 +6919,7 @@ Batch options:
|
|
|
7250
6919
|
process.once("SIGINT", onSignal);
|
|
7251
6920
|
process.once("SIGTERM", onSignal);
|
|
7252
6921
|
try {
|
|
7253
|
-
const { runApprovalUi } = await import("./runApprovalUi-
|
|
6922
|
+
const { runApprovalUi } = await import("./runApprovalUi-eLDf_5ZN.js");
|
|
7254
6923
|
await runApprovalUi({
|
|
7255
6924
|
client,
|
|
7256
6925
|
signal: stop.signal
|
|
@@ -7265,7 +6934,7 @@ Batch options:
|
|
|
7265
6934
|
registerViewCommands(program, (action) => withChannel(endpoint, getPrincipalSpec(), action));
|
|
7266
6935
|
program.command("ui").description("Launch the terminal UI (form-based browser of services + methods).").action(async () => {
|
|
7267
6936
|
const acquired = await acquireConnection(endpoint);
|
|
7268
|
-
const { runUi } = await import("./runUi-
|
|
6937
|
+
const { runUi } = await import("./runUi-DF_HTMk9.js");
|
|
7269
6938
|
try {
|
|
7270
6939
|
await runUi({
|
|
7271
6940
|
endpoint: acquired.ep,
|
|
@@ -7531,8 +7200,8 @@ async function withResolvedSigning(endpoint, principalSpec, fn) {
|
|
|
7531
7200
|
async function withApprovalClient(endpoint, principalSpec, fn, log = (line) => process.stderr.write(`linkrpc: ${line}\n`)) {
|
|
7532
7201
|
await withResolvedSigning(endpoint, principalSpec, async (conn, session) => {
|
|
7533
7202
|
reportIdentity(session);
|
|
7534
|
-
await
|
|
7535
|
-
const client = createHubApprovalCommandClient(new LinkRpcConnection(conn.rpcChannel), session.principal.identity, log);
|
|
7203
|
+
await bootstrapApprovalCapability(session.principal);
|
|
7204
|
+
const client = createHubApprovalCommandClient(new LinkRpcConnection(conn.rpcChannel), session.principal.identity, log, () => session.principal.capBag.capabilities, () => bootstrapApprovalCapability(session.principal, log));
|
|
7536
7205
|
try {
|
|
7537
7206
|
await fn(client);
|
|
7538
7207
|
} finally {
|
|
@@ -7698,4 +7367,4 @@ function safeJson(value) {
|
|
|
7698
7367
|
//#endregion
|
|
7699
7368
|
export { formatCommandLegend as a, safeTerminalText as c, interfaceTarget as d, matchesTarget as f, dispatchHostKey as i, resolveViewTarget as l, approvalDetailLines as m, views as n, hostCommands as o, targetId as p, ViewFrame as r, matchesKey as s, runCli as t, formatCondition as u };
|
|
7700
7369
|
|
|
7701
|
-
//# sourceMappingURL=cli-
|
|
7370
|
+
//# sourceMappingURL=cli-yDtBqjCT.js.map
|