@hediet/linkrpc-cli 0.0.3-next.20261024.1 → 0.0.3-next.20261025.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 +1 -1
- package/dist/chunks/{cli-CXAAnZDA.js → cli-BZ-4lHyj.js} +46 -18
- package/dist/chunks/{cli-CXAAnZDA.js.map → cli-BZ-4lHyj.js.map} +1 -1
- package/dist/chunks/{runApprovalUi-BdPp7WNP.js → runApprovalUi-DTSdmhod.js} +3 -3
- package/dist/chunks/{runApprovalUi-BdPp7WNP.js.map → runApprovalUi-DTSdmhod.js.map} +1 -1
- package/dist/chunks/{runComplete-M-eKaNkI.js → runComplete-1DjMsU_0.js} +66 -39
- package/dist/chunks/runComplete-1DjMsU_0.js.map +1 -0
- package/dist/chunks/{runUi-Deeox_Ef.js → runUi-C8VfjCWT.js} +4 -4
- package/dist/chunks/{runUi-Deeox_Ef.js.map → runUi-C8VfjCWT.js.map} +1 -1
- package/dist/chunks/{scroll-CYhlBDSN.js → scroll-UHQjKgoj.js} +2 -2
- package/dist/chunks/{scroll-CYhlBDSN.js.map → scroll-UHQjKgoj.js.map} +1 -1
- package/dist/chunks/{src-yrqRWXzG.js → src-DPg65Jd1.js} +2 -2
- package/dist/chunks/{src-yrqRWXzG.js.map → src-DPg65Jd1.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/runComplete-M-eKaNkI.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as observableValue, l as approvalDetailLines } from "./cli-
|
|
2
|
-
import { n as useObservable, t as useScroll } from "./scroll-
|
|
1
|
+
import { f as observableValue, l as approvalDetailLines } from "./cli-BZ-4lHyj.js";
|
|
2
|
+
import { n as useObservable, t as useScroll } from "./scroll-UHQjKgoj.js";
|
|
3
3
|
import { jcsCanonicalize } from "@hediet/linkrpc";
|
|
4
4
|
import React from "react";
|
|
5
5
|
import { Box, Text, render, useApp, useInput, useStdout } from "ink";
|
|
@@ -712,4 +712,4 @@ function raceAbort(promise, signal) {
|
|
|
712
712
|
//#endregion
|
|
713
713
|
export { runApprovalUi };
|
|
714
714
|
|
|
715
|
-
//# sourceMappingURL=runApprovalUi-
|
|
715
|
+
//# sourceMappingURL=runApprovalUi-DTSdmhod.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runApprovalUi-BdPp7WNP.js","names":[],"sources":["../../src/approval-ui/ApprovalApp.tsx","../../src/approval-ui/ApprovalUiModel.ts","../../src/approval-ui/runApprovalUi.tsx"],"sourcesContent":["import React from 'react';\nimport { Box, Text, useApp, useInput, useStdout } from 'ink';\nimport TextInput from 'ink-text-input';\nimport type { PendingApprovalRequest } from '@hediet/linkrpc-infra/approval';\nimport {\n approvalDetailLines,\n type ApprovalPresentationLine as DetailLine,\n} from '../approvalPresentation';\nimport { useObservable } from '../ui/useObservable';\nimport { useScroll } from '../ui/scroll';\nimport { ApprovalUiModel, type ApprovalUiMessageKind } from './ApprovalUiModel';\n\nexport { approvalDetailLines } from '../approvalPresentation';\n\nexport interface ApprovalAppProps {\n readonly model: ApprovalUiModel;\n}\n\ninterface TerminalSize {\n readonly columns: number;\n readonly rows: number;\n}\n\nconst HEADER_HEIGHT = 2;\nconst FOOTER_HEIGHT = 2;\nconst PANE_CHROME_HEIGHT = 3;\nconst MIN_FULL_HEIGHT = 13;\nconst SPLIT_COLUMNS = 96;\n\nexport const ApprovalApp: React.FC<ApprovalAppProps> = ({ model }) => {\n const requests = useObservable(model.requests);\n const selectedId = useObservable(model.selectedRequestId);\n const connectionState = useObservable(model.connectionState);\n const mode = useObservable(model.mode);\n const busy = useObservable(model.busy);\n const message = useObservable(model.message);\n const denialReason = useObservable(model.denialReason);\n const detailOffset = useObservable(model.detailOffset);\n const preparedApproval = useObservable(model.preparedApproval);\n const size = useTerminalSize();\n const { exit } = useApp();\n\n const selectedIndex = requests.findIndex((item) => item.id === selectedId);\n const selected = selectedIndex >= 0 ? requests[selectedIndex] : undefined;\n const rawDetails = selected === undefined\n ? []\n : approvalDetailLines(selected, mode === 'approve' ? preparedApproval : undefined);\n const bodyHeight = Math.max(1, size.rows - HEADER_HEIGHT - FOOTER_HEIGHT);\n const sideBySide = size.columns >= SPLIT_COLUMNS;\n const listPaneHeight = sideBySide ? bodyHeight : Math.max(5, Math.floor(bodyHeight * 0.42));\n const detailPaneHeight = sideBySide ? bodyHeight : Math.max(1, bodyHeight - listPaneHeight);\n const detailViewport = Math.max(1, detailPaneHeight - PANE_CHROME_HEIGHT);\n const detailPaneWidth = sideBySide ? Math.floor(size.columns * 0.62) : size.columns;\n const details = wrapDetailLines(rawDetails, Math.max(1, detailPaneWidth - 6));\n const approvalReviewed = mode === 'approve'\n && preparedApproval !== undefined\n && details.length > 0\n && detailOffset + detailViewport >= details.length;\n\n useInput((input, key) => {\n const canReviewAuthority = size.rows >= MIN_FULL_HEIGHT;\n if (busy) return;\n if (mode === 'deny') {\n if (key.escape) model.cancelMode();\n return;\n }\n if (mode === 'approve') {\n if (key.escape) {\n model.cancelMode();\n } else if (key.pageUp) {\n model.scrollDetails(-detailViewport, details.length, detailViewport);\n } else if (key.pageDown) {\n model.scrollDetails(detailViewport, details.length, detailViewport);\n } else if (key.return && canReviewAuthority && approvalReviewed) {\n void model.confirmCurrentMode();\n }\n return;\n }\n if (mode === 'help') {\n if (key.escape || input === '?' || input === 'q') model.cancelMode();\n return;\n }\n if (input === 'q') {\n exit();\n } else if (input === '?' || key.f1) {\n model.showHelp();\n } else if (input === 'a' && canReviewAuthority) {\n void model.beginApprove();\n } else if (input === 'd' && canReviewAuthority) {\n model.beginDeny();\n } else if (input === 'r') {\n void model.refresh();\n } else if (key.upArrow || input === 'k') {\n model.selectBy(-1);\n } else if (key.downArrow || input === 'j') {\n model.selectBy(1);\n } else if (key.pageUp) {\n model.scrollDetails(-detailViewport, details.length, detailViewport);\n } else if (key.pageDown) {\n model.scrollDetails(detailViewport, details.length, detailViewport);\n }\n });\n\n if (size.rows < MIN_FULL_HEIGHT) {\n return (\n <CompactApprovalApp\n model={model}\n selected={selected}\n requestCount={requests.length}\n connectionState={connectionState}\n mode={mode}\n busy={busy}\n message={message}\n rows={size.rows}\n />\n );\n }\n\n return (\n <Box flexDirection=\"column\" height={size.rows} width={size.columns}>\n <Header\n principalId={model.principalId}\n state={connectionState}\n requestCount={requests.length}\n />\n {mode === 'help' ? (\n <Help height={bodyHeight} />\n ) : (\n <Box\n flexDirection={sideBySide ? 'row' : 'column'}\n height={bodyHeight}\n >\n <RequestList\n requests={requests}\n selectedIndex={selectedIndex}\n height={listPaneHeight}\n width={sideBySide ? '38%' : '100%'}\n />\n <RequestDetails\n selected={selected}\n lines={details}\n offset={detailOffset}\n height={detailPaneHeight}\n width={sideBySide ? '62%' : '100%'}\n />\n </Box>\n )}\n <Footer\n mode={mode}\n busy={busy}\n message={message}\n selected={selected}\n denialReason={denialReason}\n approvalReviewed={approvalReviewed}\n onReasonChange={(value) => model.setDenialReason(value)}\n onDeny={() => void model.confirmCurrentMode()}\n />\n </Box>\n );\n};\n\nconst Header: React.FC<{\n principalId: string;\n state: 'connecting' | 'live' | 'stale';\n requestCount: number;\n}> = ({ principalId, state, requestCount }) => (\n <Box flexDirection=\"column\" height={HEADER_HEIGHT}>\n <Box justifyContent=\"space-between\">\n <Text bold>Hub access approvals</Text>\n <Text color={state === 'live' ? 'green' : state === 'stale' ? 'yellow' : 'cyan'}>\n {state === 'live' ? '● live' : state === 'stale' ? '● reconnecting' : '○ connecting'}\n <Text color=\"white\"> {requestCount} pending</Text>\n </Text>\n </Box>\n <Text dimColor wrap=\"truncate-end\">approver: {safeTerminalText(principalId)}</Text>\n </Box>\n);\n\nconst RequestList: React.FC<{\n requests: readonly PendingApprovalRequest[];\n selectedIndex: number;\n height: number;\n width: number | `${number}%`;\n}> = ({ requests, selectedIndex, height, width }) => {\n const viewport = Math.max(1, height - PANE_CHROME_HEIGHT);\n const window = useScroll(requests.length, Math.max(0, selectedIndex), viewport);\n\n return (\n <Pane title=\"Requests\" height={height} width={width}>\n {requests.length === 0 ? (\n <Box flexDirection=\"column\">\n <Text color=\"green\">No pending access requests.</Text>\n <Text dimColor>Watching the Hub for new requests...</Text>\n </Box>\n ) : (\n <>\n <ScrollMarker direction=\"up\" count={window.above} />\n {requests.slice(window.start, window.end).map((item, index) => {\n const actualIndex = window.start + index;\n const selected = actualIndex === selectedIndex;\n const duration = item.request.duration ?? 'unspecified';\n return (\n <Text\n key={item.id}\n color={selected ? 'cyan' : undefined}\n bold={selected}\n inverse={selected}\n wrap=\"truncate-end\"\n >\n {selected ? '› ' : ' '}\n {safeTerminalText(item.request.consumer.name)}\n <Text dimColor>\n {' '}{safeTerminalText(item.request.kind)} / {safeTerminalText(duration)}\n </Text>\n </Text>\n );\n })}\n <ScrollMarker direction=\"down\" count={window.below} />\n </>\n )}\n </Pane>\n );\n};\n\nconst RequestDetails: React.FC<{\n selected: PendingApprovalRequest | undefined;\n lines: readonly DetailLine[];\n offset: number;\n height: number;\n width: number | `${number}%`;\n}> = ({ selected, lines, offset, height, width }) => {\n const viewport = Math.max(1, height - PANE_CHROME_HEIGHT);\n const safeOffset = Math.min(offset, Math.max(0, lines.length - viewport));\n const visible = lines.slice(safeOffset, safeOffset + viewport);\n const range = lines.length > viewport\n ? ` (${safeOffset + 1}-${safeOffset + visible.length} of ${lines.length})`\n : '';\n\n return (\n <Pane title={`Request details${range}`} height={height} width={width}>\n {selected === undefined ? (\n <Text dimColor>Select a request to inspect its exact authority.</Text>\n ) : (\n <>\n {visible.map((line, index) => (\n <Text\n key={`${safeOffset + index}:${line.label ?? ''}:${line.text}`}\n color={line.tone === 'warning' ? 'yellow' : undefined}\n dimColor={line.tone === 'muted'}\n wrap=\"truncate-end\"\n >\n {line.label !== undefined && <Text bold>{safeTerminalText(line.label)}: </Text>}\n {safeTerminalText(line.text) || '—'}\n </Text>\n ))}\n </>\n )}\n </Pane>\n );\n};\n\nconst Footer: React.FC<{\n mode: 'browse' | 'approve' | 'deny' | 'help';\n busy: boolean;\n message: { readonly kind: ApprovalUiMessageKind; readonly text: string } | undefined;\n selected: PendingApprovalRequest | undefined;\n denialReason: string;\n approvalReviewed: boolean;\n onReasonChange(value: string): void;\n onDeny(): void;\n}> = ({\n mode,\n busy,\n message,\n selected,\n denialReason,\n approvalReviewed,\n onReasonChange,\n onDeny,\n}) => {\n if (busy) {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text color=\"cyan\">Working... The manifest will be rechecked before the decision is applied.</Text>\n <Text dimColor>Please wait.</Text>\n </Box>\n );\n }\n if (mode === 'approve') {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text color=\"yellow\" wrap=\"truncate-end\">\n Approve all displayed authority for{' '}\n <Text bold>{safeTerminalText(selected?.request.consumer.name ?? '')}</Text>?\n </Text>\n {approvalReviewed ? (\n <Text><Text bold>Enter</Text> confirm <Text bold>Esc</Text> cancel</Text>\n ) : (\n <Text><Text bold>PgDn</Text> review all authority before confirming <Text bold>Esc</Text> cancel</Text>\n )}\n </Box>\n );\n }\n if (mode === 'deny') {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Box>\n <Text color=\"red\">Denial reason (optional): </Text>\n <TextInput value={denialReason} onChange={onReasonChange} onSubmit={onDeny} />\n </Box>\n <Text><Text bold>Enter</Text> deny <Text bold>Esc</Text> cancel</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text\n color={messageColor(message?.kind)}\n dimColor={message === undefined}\n wrap=\"truncate-end\"\n >\n {safeTerminalText(message?.text ?? 'Review the exact authority before approving.')}\n </Text>\n <Text dimColor wrap=\"truncate-end\">\n ↑/↓ or j/k select a approve d deny PgUp/PgDn details r refresh ? help q quit\n </Text>\n </Box>\n );\n};\n\nconst Help: React.FC<{ height: number }> = ({ height }) => (\n <Pane title=\"Keyboard help\" height={height} width=\"100%\">\n <Text><Text bold>↑/↓, j/k</Text> Move through pending requests</Text>\n <Text><Text bold>PgUp/PgDn</Text> Scroll long request details</Text>\n <Text><Text bold>a</Text> Review and confirm approval</Text>\n <Text><Text bold>d</Text> Deny with an optional reason</Text>\n <Text><Text bold>r</Text> Refresh the authoritative manifest snapshot</Text>\n <Text><Text bold>?, F1</Text> Toggle this help</Text>\n <Text><Text bold>q</Text> Quit without deciding remaining requests</Text>\n <Text dimColor>Press Esc, ?, or q to return.</Text>\n </Pane>\n);\n\nconst CompactApprovalApp: React.FC<{\n model: ApprovalUiModel;\n selected: PendingApprovalRequest | undefined;\n requestCount: number;\n connectionState: 'connecting' | 'live' | 'stale';\n mode: 'browse' | 'approve' | 'deny' | 'help';\n busy: boolean;\n message: { readonly kind: ApprovalUiMessageKind; readonly text: string } | undefined;\n rows: number;\n}> = ({\n model,\n selected,\n requestCount,\n connectionState,\n mode,\n busy,\n message,\n rows,\n}) => (\n <Box flexDirection=\"column\" height={Math.max(1, rows)}>\n <Text bold wrap=\"truncate-end\">Hub approvals {connectionState} {requestCount} pending</Text>\n <Text wrap=\"truncate-end\">\n {selected === undefined\n ? 'No pending access requests.'\n : safeTerminalText(\n `${selected.request.consumer.name} · ${selected.request.kind} · ${selected.request.duration ?? 'unspecified'}`,\n )}\n </Text>\n {rows >= 4 && (\n <Text color={messageColor(message?.kind)} wrap=\"truncate-end\">\n {safeTerminalText(busy ? 'Resolving request...' : message?.text ?? model.principalId)}\n </Text>\n )}\n {rows >= 5 && (\n <Text color=\"yellow\" wrap=\"truncate-end\">\n Enlarge to at least {MIN_FULL_HEIGHT} rows to review and decide. ↑/↓ select q quit\n </Text>\n )}\n </Box>\n);\n\nconst Pane: React.FC<{\n title: string;\n height: number;\n width: number | `${number}%`;\n children: React.ReactNode;\n}> = ({ title, height, width, children }) => (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor=\"gray\"\n height={height}\n width={width}\n paddingX={1}\n overflow=\"hidden\"\n >\n <Text bold>{title}</Text>\n {children}\n </Box>\n);\n\nconst ScrollMarker: React.FC<{ direction: 'up' | 'down'; count: number }> = ({ direction, count }) => {\n if (count === 0) return null;\n return <Text dimColor>{direction === 'up' ? '▲' : '▼'} {count} more</Text>;\n};\n\nfunction wrapDetailLines(lines: readonly DetailLine[], width: number): readonly DetailLine[] {\n return lines.flatMap((line) => {\n const text = safeTerminalText(`${line.label === undefined ? '' : `${line.label}: `}${line.text || '—'}`);\n return wrapTerminalText(text, width).map((chunk) => ({\n text: chunk,\n ...(line.tone === undefined ? {} : { tone: line.tone }),\n }));\n });\n}\n\nfunction wrapTerminalText(text: string, width: number): readonly string[] {\n const lines: string[] = [];\n let current = '';\n let currentWidth = 0;\n for (const character of text) {\n const characterWidth = terminalCharacterWidth(character);\n if (current.length > 0 && currentWidth + characterWidth > width) {\n lines.push(current);\n current = '';\n currentWidth = 0;\n }\n current += character;\n currentWidth += characterWidth;\n }\n if (current.length > 0 || lines.length === 0) lines.push(current);\n return lines;\n}\n\nfunction terminalCharacterWidth(character: string): number {\n if (/^\\p{Mark}$/u.test(character)) return 0;\n return character.codePointAt(0)! <= 0x7e ? 1 : 2;\n}\n\nexport function safeTerminalText(text: string): string {\n let result = '';\n for (const character of text) {\n result += /^[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}]$/u.test(character)\n ? `\\\\u{${character.codePointAt(0)!.toString(16).padStart(4, '0')}}`\n : character;\n }\n return result;\n}\n\nfunction messageColor(kind: ApprovalUiMessageKind | undefined): 'red' | 'green' | 'cyan' | undefined {\n if (kind === 'error') return 'red';\n if (kind === 'success') return 'green';\n if (kind === 'info') return 'cyan';\n return undefined;\n}\n\nfunction useTerminalSize(): TerminalSize {\n const { stdout } = useStdout();\n const [size, setSize] = React.useState<TerminalSize>({\n columns: stdout.columns ?? 100,\n rows: stdout.rows ?? 30,\n });\n React.useEffect(() => {\n const onResize = () => setSize({\n columns: stdout.columns ?? 100,\n rows: stdout.rows ?? 30,\n });\n stdout.on('resize', onResize);\n return () => stdout.off('resize', onResize);\n }, [stdout]);\n return size;\n}\n","import { jcsCanonicalize } from '@hediet/linkrpc';\nimport { observableValue, type IObservable, type ISettableObservable } from '@vscode/observables';\nimport type {\n ApprovalSnapshot,\n ApprovalDecisionOutcome,\n PendingApprovalRequest,\n PreparedApproval,\n} from '@hediet/linkrpc-infra/approval';\nimport type { ApprovalSubscription } from '../commands/approval';\n\nexport type ApprovalUiMode = 'browse' | 'approve' | 'deny' | 'help';\nexport type ApprovalUiMessageKind = 'info' | 'success' | 'error';\n\nexport interface ApprovalUiMessage {\n readonly kind: ApprovalUiMessageKind;\n readonly text: string;\n}\n\nexport interface ApprovalUiClient {\n readonly principalId: string;\n watch(listener: (snapshot: ApprovalSnapshot) => void): ApprovalSubscription;\n refresh(): Promise<void>;\n prepareApproval(requestId: string): Promise<PreparedApproval>;\n approvePrepared(prepared: PreparedApproval): Promise<ApprovalDecisionOutcome>;\n deny(\n requestId: string,\n reason?: string,\n expected?: PendingApprovalRequest,\n ): Promise<ApprovalDecisionOutcome>;\n}\n\nexport class ApprovalUiModel {\n private readonly _requests: ISettableObservable<readonly PendingApprovalRequest[]>;\n public readonly requests: IObservable<readonly PendingApprovalRequest[]>;\n private readonly _connectionState: ISettableObservable<ApprovalSnapshot['state']>;\n public readonly connectionState: IObservable<ApprovalSnapshot['state']>;\n private readonly _selectedRequestId: ISettableObservable<string | undefined>;\n public readonly selectedRequestId: IObservable<string | undefined>;\n private readonly _mode: ISettableObservable<ApprovalUiMode>;\n public readonly mode: IObservable<ApprovalUiMode>;\n private readonly _busy: ISettableObservable<boolean>;\n public readonly busy: IObservable<boolean>;\n private readonly _message: ISettableObservable<ApprovalUiMessage | undefined>;\n public readonly message: IObservable<ApprovalUiMessage | undefined>;\n private readonly _denialReason: ISettableObservable<string>;\n public readonly denialReason: IObservable<string>;\n private readonly _detailOffset: ISettableObservable<number>;\n public readonly detailOffset: IObservable<number>;\n private readonly _preparedApproval: ISettableObservable<PreparedApproval | undefined>;\n public readonly preparedApproval: IObservable<PreparedApproval | undefined>;\n\n private readonly _client: ApprovalUiClient;\n private readonly _subscription: ApprovalSubscription;\n private _disposed = false;\n\n constructor(client: ApprovalUiClient) {\n this._client = client;\n this._requests = observableValue(this, []);\n this.requests = this._requests;\n this._connectionState = observableValue(this, 'connecting');\n this.connectionState = this._connectionState;\n this._selectedRequestId = observableValue(this, undefined);\n this.selectedRequestId = this._selectedRequestId;\n this._mode = observableValue(this, 'browse');\n this.mode = this._mode;\n this._busy = observableValue(this, false);\n this.busy = this._busy;\n this._message = observableValue(this, undefined);\n this.message = this._message;\n this._denialReason = observableValue(this, '');\n this.denialReason = this._denialReason;\n this._detailOffset = observableValue(this, 0);\n this.detailOffset = this._detailOffset;\n this._preparedApproval = observableValue(this, undefined);\n this.preparedApproval = this._preparedApproval;\n this._subscription = client.watch((snapshot) => this._applySnapshot(snapshot));\n }\n\n public get principalId(): string {\n return this._client.principalId;\n }\n\n public get selectedRequest(): PendingApprovalRequest | undefined {\n const selectedId = this._selectedRequestId.get();\n return this._requests.get().find((item) => item.id === selectedId);\n }\n\n public selectBy(delta: number): void {\n if (this._busy.get() || this._mode.get() !== 'browse') return;\n const requests = this._requests.get();\n if (requests.length === 0) return;\n const currentIndex = Math.max(\n 0,\n requests.findIndex((item) => item.id === this._selectedRequestId.get()),\n );\n const nextIndex = Math.max(0, Math.min(requests.length - 1, currentIndex + delta));\n if (nextIndex === currentIndex) return;\n this._selectedRequestId.set(requests[nextIndex].id, undefined);\n this._detailOffset.set(0, undefined);\n }\n\n public showHelp(): void {\n if (this._busy.get()) return;\n this._mode.set('help', undefined);\n }\n\n public async beginApprove(): Promise<void> {\n if (!this._canDecide()) return;\n const selected = this.selectedRequest;\n if (selected === undefined) return;\n this._busy.set(true, undefined);\n this._message.set({ kind: 'info', text: 'Resolving exact authority...' }, undefined);\n try {\n const prepared = await this._client.prepareApproval(selected.id);\n if (\n this.selectedRequest?.id !== selected.id\n || jcsCanonicalize(this.selectedRequest.request)\n !== jcsCanonicalize(prepared.pending.request)\n ) {\n this._message.set({\n kind: 'info',\n text: 'The request changed while its authority was being resolved. Review it again.',\n }, undefined);\n return;\n }\n this._preparedApproval.set(prepared, undefined);\n this._detailOffset.set(0, undefined);\n this._mode.set('approve', undefined);\n this._message.set(undefined, undefined);\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n } finally {\n this._busy.set(false, undefined);\n }\n }\n\n public beginDeny(): void {\n if (!this._canDecide()) return;\n this._denialReason.set('', undefined);\n this._mode.set('deny', undefined);\n }\n\n public setDenialReason(reason: string): void {\n this._denialReason.set(reason, undefined);\n }\n\n public cancelMode(): void {\n if (this._busy.get()) return;\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n\n public async confirmCurrentMode(): Promise<void> {\n const mode = this._mode.get();\n const selected = this.selectedRequest;\n if (this._busy.get() || selected === undefined || (mode !== 'approve' && mode !== 'deny')) return;\n\n this._busy.set(true, undefined);\n this._message.set({\n kind: 'info',\n text: mode === 'approve' ? 'Approving request...' : 'Denying request...',\n }, undefined);\n try {\n let outcome: ApprovalDecisionOutcome;\n if (mode === 'approve') {\n const prepared = this._preparedApproval.get();\n if (prepared === undefined) {\n throw new Error('approval details are no longer available; review the request again');\n }\n outcome = await this._client.approvePrepared(prepared);\n } else {\n const reason = this._denialReason.get().trim();\n outcome = await this._client.deny(\n selected.id,\n reason.length > 0 ? reason : undefined,\n selected,\n );\n }\n this._message.set({\n kind: outcome === 'applied' ? 'success' : 'info',\n text: outcome === 'applied'\n ? `${mode === 'approve' ? 'Approved' : 'Denied'} ${selected.request.consumer.name}.`\n : `Decision accepted for ${selected.request.consumer.name}, `\n + 'but a matching request is still pending. The consumer may have retried.',\n }, undefined);\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n } finally {\n this._busy.set(false, undefined);\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n }\n\n public async refresh(): Promise<void> {\n if (this._busy.get()) return;\n this._message.set({ kind: 'info', text: 'Refreshing approval requests...' }, undefined);\n try {\n await this._client.refresh();\n if (this._connectionState.get() === 'live') {\n this._message.set({ kind: 'info', text: 'Approval requests are up to date.' }, undefined);\n }\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n }\n }\n\n public scrollDetails(delta: number, lineCount: number, viewportSize: number): void {\n const maxOffset = Math.max(0, lineCount - Math.max(1, viewportSize));\n const next = Math.max(0, Math.min(maxOffset, this._detailOffset.get() + delta));\n this._detailOffset.set(next, undefined);\n }\n\n public dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._subscription.dispose();\n }\n\n private _canDecide(): boolean {\n if (this._busy.get() || this.selectedRequest === undefined) return false;\n if (this._connectionState.get() !== 'live') {\n this._message.set({\n kind: 'error',\n text: 'Cannot decide requests while the approval connection is stale.',\n }, undefined);\n return false;\n }\n return true;\n }\n\n private _applySnapshot(snapshot: ApprovalSnapshot): void {\n const previous = this._requests.get();\n const selectedId = this._selectedRequestId.get();\n const previousSelected = previous.find((item) => item.id === selectedId);\n const previousIndex = Math.max(0, previous.findIndex((item) => item.id === selectedId));\n const selectedStillExists = snapshot.requests.some((item) => item.id === selectedId);\n const nextSelected = snapshot.requests.find((item) => item.id === selectedId);\n const selectedChanged = previousSelected !== undefined\n && nextSelected !== undefined\n && jcsCanonicalize(previousSelected.request) !== jcsCanonicalize(nextSelected.request);\n\n this._requests.set(snapshot.requests, undefined);\n this._connectionState.set(snapshot.state, undefined);\n\n if (snapshot.requests.length === 0) {\n this._selectedRequestId.set(undefined, undefined);\n this._detailOffset.set(0, undefined);\n } else if (!selectedStillExists) {\n const nextIndex = Math.min(previousIndex, snapshot.requests.length - 1);\n this._selectedRequestId.set(snapshot.requests[nextIndex].id, undefined);\n this._detailOffset.set(0, undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n\n if (\n ((!selectedStillExists && selectedId !== undefined) || selectedChanged)\n && this._mode.get() !== 'browse'\n ) {\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n this._message.set({\n kind: 'info',\n text: selectedChanged\n ? 'The selected request changed. Review it again before deciding.'\n : 'The selected request is no longer pending.',\n }, undefined);\n }\n if (snapshot.state === 'stale' && snapshot.error !== undefined) {\n this._message.set({ kind: 'error', text: snapshot.error }, undefined);\n }\n }\n}\n","import React from 'react';\nimport { render } from 'ink';\nimport type { ApprovalCommandClient } from '../commands/approval';\nimport { ApprovalApp } from './ApprovalApp';\nimport { ApprovalUiModel } from './ApprovalUiModel';\n\nexport interface RunApprovalUiOptions {\n readonly client: ApprovalCommandClient;\n readonly signal: AbortSignal;\n}\n\nexport async function runApprovalUi(options: RunApprovalUiOptions): Promise<void> {\n const model = new ApprovalUiModel(options.client);\n const instance = render(<ApprovalApp model={model} />);\n const onAbort = () => instance.unmount();\n options.signal.addEventListener('abort', onAbort, { once: true });\n if (options.signal.aborted) onAbort();\n try {\n await raceAbort(model.refresh(), options.signal);\n if (options.signal.aborted) return;\n await instance.waitUntilExit();\n } finally {\n options.signal.removeEventListener('abort', onAbort);\n instance.unmount();\n model.dispose();\n }\n}\n\nfunction raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T | undefined> {\n if (signal.aborted) return Promise.resolve(undefined);\n return new Promise<T | undefined>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener('abort', onAbort);\n resolve(undefined);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runApprovalUi-DTSdmhod.js","names":[],"sources":["../../src/approval-ui/ApprovalApp.tsx","../../src/approval-ui/ApprovalUiModel.ts","../../src/approval-ui/runApprovalUi.tsx"],"sourcesContent":["import React from 'react';\nimport { Box, Text, useApp, useInput, useStdout } from 'ink';\nimport TextInput from 'ink-text-input';\nimport type { PendingApprovalRequest } from '@hediet/linkrpc-infra/approval';\nimport {\n approvalDetailLines,\n type ApprovalPresentationLine as DetailLine,\n} from '../approvalPresentation';\nimport { useObservable } from '../ui/useObservable';\nimport { useScroll } from '../ui/scroll';\nimport { ApprovalUiModel, type ApprovalUiMessageKind } from './ApprovalUiModel';\n\nexport { approvalDetailLines } from '../approvalPresentation';\n\nexport interface ApprovalAppProps {\n readonly model: ApprovalUiModel;\n}\n\ninterface TerminalSize {\n readonly columns: number;\n readonly rows: number;\n}\n\nconst HEADER_HEIGHT = 2;\nconst FOOTER_HEIGHT = 2;\nconst PANE_CHROME_HEIGHT = 3;\nconst MIN_FULL_HEIGHT = 13;\nconst SPLIT_COLUMNS = 96;\n\nexport const ApprovalApp: React.FC<ApprovalAppProps> = ({ model }) => {\n const requests = useObservable(model.requests);\n const selectedId = useObservable(model.selectedRequestId);\n const connectionState = useObservable(model.connectionState);\n const mode = useObservable(model.mode);\n const busy = useObservable(model.busy);\n const message = useObservable(model.message);\n const denialReason = useObservable(model.denialReason);\n const detailOffset = useObservable(model.detailOffset);\n const preparedApproval = useObservable(model.preparedApproval);\n const size = useTerminalSize();\n const { exit } = useApp();\n\n const selectedIndex = requests.findIndex((item) => item.id === selectedId);\n const selected = selectedIndex >= 0 ? requests[selectedIndex] : undefined;\n const rawDetails = selected === undefined\n ? []\n : approvalDetailLines(selected, mode === 'approve' ? preparedApproval : undefined);\n const bodyHeight = Math.max(1, size.rows - HEADER_HEIGHT - FOOTER_HEIGHT);\n const sideBySide = size.columns >= SPLIT_COLUMNS;\n const listPaneHeight = sideBySide ? bodyHeight : Math.max(5, Math.floor(bodyHeight * 0.42));\n const detailPaneHeight = sideBySide ? bodyHeight : Math.max(1, bodyHeight - listPaneHeight);\n const detailViewport = Math.max(1, detailPaneHeight - PANE_CHROME_HEIGHT);\n const detailPaneWidth = sideBySide ? Math.floor(size.columns * 0.62) : size.columns;\n const details = wrapDetailLines(rawDetails, Math.max(1, detailPaneWidth - 6));\n const approvalReviewed = mode === 'approve'\n && preparedApproval !== undefined\n && details.length > 0\n && detailOffset + detailViewport >= details.length;\n\n useInput((input, key) => {\n const canReviewAuthority = size.rows >= MIN_FULL_HEIGHT;\n if (busy) return;\n if (mode === 'deny') {\n if (key.escape) model.cancelMode();\n return;\n }\n if (mode === 'approve') {\n if (key.escape) {\n model.cancelMode();\n } else if (key.pageUp) {\n model.scrollDetails(-detailViewport, details.length, detailViewport);\n } else if (key.pageDown) {\n model.scrollDetails(detailViewport, details.length, detailViewport);\n } else if (key.return && canReviewAuthority && approvalReviewed) {\n void model.confirmCurrentMode();\n }\n return;\n }\n if (mode === 'help') {\n if (key.escape || input === '?' || input === 'q') model.cancelMode();\n return;\n }\n if (input === 'q') {\n exit();\n } else if (input === '?' || key.f1) {\n model.showHelp();\n } else if (input === 'a' && canReviewAuthority) {\n void model.beginApprove();\n } else if (input === 'd' && canReviewAuthority) {\n model.beginDeny();\n } else if (input === 'r') {\n void model.refresh();\n } else if (key.upArrow || input === 'k') {\n model.selectBy(-1);\n } else if (key.downArrow || input === 'j') {\n model.selectBy(1);\n } else if (key.pageUp) {\n model.scrollDetails(-detailViewport, details.length, detailViewport);\n } else if (key.pageDown) {\n model.scrollDetails(detailViewport, details.length, detailViewport);\n }\n });\n\n if (size.rows < MIN_FULL_HEIGHT) {\n return (\n <CompactApprovalApp\n model={model}\n selected={selected}\n requestCount={requests.length}\n connectionState={connectionState}\n mode={mode}\n busy={busy}\n message={message}\n rows={size.rows}\n />\n );\n }\n\n return (\n <Box flexDirection=\"column\" height={size.rows} width={size.columns}>\n <Header\n principalId={model.principalId}\n state={connectionState}\n requestCount={requests.length}\n />\n {mode === 'help' ? (\n <Help height={bodyHeight} />\n ) : (\n <Box\n flexDirection={sideBySide ? 'row' : 'column'}\n height={bodyHeight}\n >\n <RequestList\n requests={requests}\n selectedIndex={selectedIndex}\n height={listPaneHeight}\n width={sideBySide ? '38%' : '100%'}\n />\n <RequestDetails\n selected={selected}\n lines={details}\n offset={detailOffset}\n height={detailPaneHeight}\n width={sideBySide ? '62%' : '100%'}\n />\n </Box>\n )}\n <Footer\n mode={mode}\n busy={busy}\n message={message}\n selected={selected}\n denialReason={denialReason}\n approvalReviewed={approvalReviewed}\n onReasonChange={(value) => model.setDenialReason(value)}\n onDeny={() => void model.confirmCurrentMode()}\n />\n </Box>\n );\n};\n\nconst Header: React.FC<{\n principalId: string;\n state: 'connecting' | 'live' | 'stale';\n requestCount: number;\n}> = ({ principalId, state, requestCount }) => (\n <Box flexDirection=\"column\" height={HEADER_HEIGHT}>\n <Box justifyContent=\"space-between\">\n <Text bold>Hub access approvals</Text>\n <Text color={state === 'live' ? 'green' : state === 'stale' ? 'yellow' : 'cyan'}>\n {state === 'live' ? '● live' : state === 'stale' ? '● reconnecting' : '○ connecting'}\n <Text color=\"white\"> {requestCount} pending</Text>\n </Text>\n </Box>\n <Text dimColor wrap=\"truncate-end\">approver: {safeTerminalText(principalId)}</Text>\n </Box>\n);\n\nconst RequestList: React.FC<{\n requests: readonly PendingApprovalRequest[];\n selectedIndex: number;\n height: number;\n width: number | `${number}%`;\n}> = ({ requests, selectedIndex, height, width }) => {\n const viewport = Math.max(1, height - PANE_CHROME_HEIGHT);\n const window = useScroll(requests.length, Math.max(0, selectedIndex), viewport);\n\n return (\n <Pane title=\"Requests\" height={height} width={width}>\n {requests.length === 0 ? (\n <Box flexDirection=\"column\">\n <Text color=\"green\">No pending access requests.</Text>\n <Text dimColor>Watching the Hub for new requests...</Text>\n </Box>\n ) : (\n <>\n <ScrollMarker direction=\"up\" count={window.above} />\n {requests.slice(window.start, window.end).map((item, index) => {\n const actualIndex = window.start + index;\n const selected = actualIndex === selectedIndex;\n const duration = item.request.duration ?? 'unspecified';\n return (\n <Text\n key={item.id}\n color={selected ? 'cyan' : undefined}\n bold={selected}\n inverse={selected}\n wrap=\"truncate-end\"\n >\n {selected ? '› ' : ' '}\n {safeTerminalText(item.request.consumer.name)}\n <Text dimColor>\n {' '}{safeTerminalText(item.request.kind)} / {safeTerminalText(duration)}\n </Text>\n </Text>\n );\n })}\n <ScrollMarker direction=\"down\" count={window.below} />\n </>\n )}\n </Pane>\n );\n};\n\nconst RequestDetails: React.FC<{\n selected: PendingApprovalRequest | undefined;\n lines: readonly DetailLine[];\n offset: number;\n height: number;\n width: number | `${number}%`;\n}> = ({ selected, lines, offset, height, width }) => {\n const viewport = Math.max(1, height - PANE_CHROME_HEIGHT);\n const safeOffset = Math.min(offset, Math.max(0, lines.length - viewport));\n const visible = lines.slice(safeOffset, safeOffset + viewport);\n const range = lines.length > viewport\n ? ` (${safeOffset + 1}-${safeOffset + visible.length} of ${lines.length})`\n : '';\n\n return (\n <Pane title={`Request details${range}`} height={height} width={width}>\n {selected === undefined ? (\n <Text dimColor>Select a request to inspect its exact authority.</Text>\n ) : (\n <>\n {visible.map((line, index) => (\n <Text\n key={`${safeOffset + index}:${line.label ?? ''}:${line.text}`}\n color={line.tone === 'warning' ? 'yellow' : undefined}\n dimColor={line.tone === 'muted'}\n wrap=\"truncate-end\"\n >\n {line.label !== undefined && <Text bold>{safeTerminalText(line.label)}: </Text>}\n {safeTerminalText(line.text) || '—'}\n </Text>\n ))}\n </>\n )}\n </Pane>\n );\n};\n\nconst Footer: React.FC<{\n mode: 'browse' | 'approve' | 'deny' | 'help';\n busy: boolean;\n message: { readonly kind: ApprovalUiMessageKind; readonly text: string } | undefined;\n selected: PendingApprovalRequest | undefined;\n denialReason: string;\n approvalReviewed: boolean;\n onReasonChange(value: string): void;\n onDeny(): void;\n}> = ({\n mode,\n busy,\n message,\n selected,\n denialReason,\n approvalReviewed,\n onReasonChange,\n onDeny,\n}) => {\n if (busy) {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text color=\"cyan\">Working... The manifest will be rechecked before the decision is applied.</Text>\n <Text dimColor>Please wait.</Text>\n </Box>\n );\n }\n if (mode === 'approve') {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text color=\"yellow\" wrap=\"truncate-end\">\n Approve all displayed authority for{' '}\n <Text bold>{safeTerminalText(selected?.request.consumer.name ?? '')}</Text>?\n </Text>\n {approvalReviewed ? (\n <Text><Text bold>Enter</Text> confirm <Text bold>Esc</Text> cancel</Text>\n ) : (\n <Text><Text bold>PgDn</Text> review all authority before confirming <Text bold>Esc</Text> cancel</Text>\n )}\n </Box>\n );\n }\n if (mode === 'deny') {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Box>\n <Text color=\"red\">Denial reason (optional): </Text>\n <TextInput value={denialReason} onChange={onReasonChange} onSubmit={onDeny} />\n </Box>\n <Text><Text bold>Enter</Text> deny <Text bold>Esc</Text> cancel</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text\n color={messageColor(message?.kind)}\n dimColor={message === undefined}\n wrap=\"truncate-end\"\n >\n {safeTerminalText(message?.text ?? 'Review the exact authority before approving.')}\n </Text>\n <Text dimColor wrap=\"truncate-end\">\n ↑/↓ or j/k select a approve d deny PgUp/PgDn details r refresh ? help q quit\n </Text>\n </Box>\n );\n};\n\nconst Help: React.FC<{ height: number }> = ({ height }) => (\n <Pane title=\"Keyboard help\" height={height} width=\"100%\">\n <Text><Text bold>↑/↓, j/k</Text> Move through pending requests</Text>\n <Text><Text bold>PgUp/PgDn</Text> Scroll long request details</Text>\n <Text><Text bold>a</Text> Review and confirm approval</Text>\n <Text><Text bold>d</Text> Deny with an optional reason</Text>\n <Text><Text bold>r</Text> Refresh the authoritative manifest snapshot</Text>\n <Text><Text bold>?, F1</Text> Toggle this help</Text>\n <Text><Text bold>q</Text> Quit without deciding remaining requests</Text>\n <Text dimColor>Press Esc, ?, or q to return.</Text>\n </Pane>\n);\n\nconst CompactApprovalApp: React.FC<{\n model: ApprovalUiModel;\n selected: PendingApprovalRequest | undefined;\n requestCount: number;\n connectionState: 'connecting' | 'live' | 'stale';\n mode: 'browse' | 'approve' | 'deny' | 'help';\n busy: boolean;\n message: { readonly kind: ApprovalUiMessageKind; readonly text: string } | undefined;\n rows: number;\n}> = ({\n model,\n selected,\n requestCount,\n connectionState,\n mode,\n busy,\n message,\n rows,\n}) => (\n <Box flexDirection=\"column\" height={Math.max(1, rows)}>\n <Text bold wrap=\"truncate-end\">Hub approvals {connectionState} {requestCount} pending</Text>\n <Text wrap=\"truncate-end\">\n {selected === undefined\n ? 'No pending access requests.'\n : safeTerminalText(\n `${selected.request.consumer.name} · ${selected.request.kind} · ${selected.request.duration ?? 'unspecified'}`,\n )}\n </Text>\n {rows >= 4 && (\n <Text color={messageColor(message?.kind)} wrap=\"truncate-end\">\n {safeTerminalText(busy ? 'Resolving request...' : message?.text ?? model.principalId)}\n </Text>\n )}\n {rows >= 5 && (\n <Text color=\"yellow\" wrap=\"truncate-end\">\n Enlarge to at least {MIN_FULL_HEIGHT} rows to review and decide. ↑/↓ select q quit\n </Text>\n )}\n </Box>\n);\n\nconst Pane: React.FC<{\n title: string;\n height: number;\n width: number | `${number}%`;\n children: React.ReactNode;\n}> = ({ title, height, width, children }) => (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor=\"gray\"\n height={height}\n width={width}\n paddingX={1}\n overflow=\"hidden\"\n >\n <Text bold>{title}</Text>\n {children}\n </Box>\n);\n\nconst ScrollMarker: React.FC<{ direction: 'up' | 'down'; count: number }> = ({ direction, count }) => {\n if (count === 0) return null;\n return <Text dimColor>{direction === 'up' ? '▲' : '▼'} {count} more</Text>;\n};\n\nfunction wrapDetailLines(lines: readonly DetailLine[], width: number): readonly DetailLine[] {\n return lines.flatMap((line) => {\n const text = safeTerminalText(`${line.label === undefined ? '' : `${line.label}: `}${line.text || '—'}`);\n return wrapTerminalText(text, width).map((chunk) => ({\n text: chunk,\n ...(line.tone === undefined ? {} : { tone: line.tone }),\n }));\n });\n}\n\nfunction wrapTerminalText(text: string, width: number): readonly string[] {\n const lines: string[] = [];\n let current = '';\n let currentWidth = 0;\n for (const character of text) {\n const characterWidth = terminalCharacterWidth(character);\n if (current.length > 0 && currentWidth + characterWidth > width) {\n lines.push(current);\n current = '';\n currentWidth = 0;\n }\n current += character;\n currentWidth += characterWidth;\n }\n if (current.length > 0 || lines.length === 0) lines.push(current);\n return lines;\n}\n\nfunction terminalCharacterWidth(character: string): number {\n if (/^\\p{Mark}$/u.test(character)) return 0;\n return character.codePointAt(0)! <= 0x7e ? 1 : 2;\n}\n\nexport function safeTerminalText(text: string): string {\n let result = '';\n for (const character of text) {\n result += /^[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}]$/u.test(character)\n ? `\\\\u{${character.codePointAt(0)!.toString(16).padStart(4, '0')}}`\n : character;\n }\n return result;\n}\n\nfunction messageColor(kind: ApprovalUiMessageKind | undefined): 'red' | 'green' | 'cyan' | undefined {\n if (kind === 'error') return 'red';\n if (kind === 'success') return 'green';\n if (kind === 'info') return 'cyan';\n return undefined;\n}\n\nfunction useTerminalSize(): TerminalSize {\n const { stdout } = useStdout();\n const [size, setSize] = React.useState<TerminalSize>({\n columns: stdout.columns ?? 100,\n rows: stdout.rows ?? 30,\n });\n React.useEffect(() => {\n const onResize = () => setSize({\n columns: stdout.columns ?? 100,\n rows: stdout.rows ?? 30,\n });\n stdout.on('resize', onResize);\n return () => stdout.off('resize', onResize);\n }, [stdout]);\n return size;\n}\n","import { jcsCanonicalize } from '@hediet/linkrpc';\nimport { observableValue, type IObservable, type ISettableObservable } from '@vscode/observables';\nimport type {\n ApprovalSnapshot,\n ApprovalDecisionOutcome,\n PendingApprovalRequest,\n PreparedApproval,\n} from '@hediet/linkrpc-infra/approval';\nimport type { ApprovalSubscription } from '../commands/approval';\n\nexport type ApprovalUiMode = 'browse' | 'approve' | 'deny' | 'help';\nexport type ApprovalUiMessageKind = 'info' | 'success' | 'error';\n\nexport interface ApprovalUiMessage {\n readonly kind: ApprovalUiMessageKind;\n readonly text: string;\n}\n\nexport interface ApprovalUiClient {\n readonly principalId: string;\n watch(listener: (snapshot: ApprovalSnapshot) => void): ApprovalSubscription;\n refresh(): Promise<void>;\n prepareApproval(requestId: string): Promise<PreparedApproval>;\n approvePrepared(prepared: PreparedApproval): Promise<ApprovalDecisionOutcome>;\n deny(\n requestId: string,\n reason?: string,\n expected?: PendingApprovalRequest,\n ): Promise<ApprovalDecisionOutcome>;\n}\n\nexport class ApprovalUiModel {\n private readonly _requests: ISettableObservable<readonly PendingApprovalRequest[]>;\n public readonly requests: IObservable<readonly PendingApprovalRequest[]>;\n private readonly _connectionState: ISettableObservable<ApprovalSnapshot['state']>;\n public readonly connectionState: IObservable<ApprovalSnapshot['state']>;\n private readonly _selectedRequestId: ISettableObservable<string | undefined>;\n public readonly selectedRequestId: IObservable<string | undefined>;\n private readonly _mode: ISettableObservable<ApprovalUiMode>;\n public readonly mode: IObservable<ApprovalUiMode>;\n private readonly _busy: ISettableObservable<boolean>;\n public readonly busy: IObservable<boolean>;\n private readonly _message: ISettableObservable<ApprovalUiMessage | undefined>;\n public readonly message: IObservable<ApprovalUiMessage | undefined>;\n private readonly _denialReason: ISettableObservable<string>;\n public readonly denialReason: IObservable<string>;\n private readonly _detailOffset: ISettableObservable<number>;\n public readonly detailOffset: IObservable<number>;\n private readonly _preparedApproval: ISettableObservable<PreparedApproval | undefined>;\n public readonly preparedApproval: IObservable<PreparedApproval | undefined>;\n\n private readonly _client: ApprovalUiClient;\n private readonly _subscription: ApprovalSubscription;\n private _disposed = false;\n\n constructor(client: ApprovalUiClient) {\n this._client = client;\n this._requests = observableValue(this, []);\n this.requests = this._requests;\n this._connectionState = observableValue(this, 'connecting');\n this.connectionState = this._connectionState;\n this._selectedRequestId = observableValue(this, undefined);\n this.selectedRequestId = this._selectedRequestId;\n this._mode = observableValue(this, 'browse');\n this.mode = this._mode;\n this._busy = observableValue(this, false);\n this.busy = this._busy;\n this._message = observableValue(this, undefined);\n this.message = this._message;\n this._denialReason = observableValue(this, '');\n this.denialReason = this._denialReason;\n this._detailOffset = observableValue(this, 0);\n this.detailOffset = this._detailOffset;\n this._preparedApproval = observableValue(this, undefined);\n this.preparedApproval = this._preparedApproval;\n this._subscription = client.watch((snapshot) => this._applySnapshot(snapshot));\n }\n\n public get principalId(): string {\n return this._client.principalId;\n }\n\n public get selectedRequest(): PendingApprovalRequest | undefined {\n const selectedId = this._selectedRequestId.get();\n return this._requests.get().find((item) => item.id === selectedId);\n }\n\n public selectBy(delta: number): void {\n if (this._busy.get() || this._mode.get() !== 'browse') return;\n const requests = this._requests.get();\n if (requests.length === 0) return;\n const currentIndex = Math.max(\n 0,\n requests.findIndex((item) => item.id === this._selectedRequestId.get()),\n );\n const nextIndex = Math.max(0, Math.min(requests.length - 1, currentIndex + delta));\n if (nextIndex === currentIndex) return;\n this._selectedRequestId.set(requests[nextIndex].id, undefined);\n this._detailOffset.set(0, undefined);\n }\n\n public showHelp(): void {\n if (this._busy.get()) return;\n this._mode.set('help', undefined);\n }\n\n public async beginApprove(): Promise<void> {\n if (!this._canDecide()) return;\n const selected = this.selectedRequest;\n if (selected === undefined) return;\n this._busy.set(true, undefined);\n this._message.set({ kind: 'info', text: 'Resolving exact authority...' }, undefined);\n try {\n const prepared = await this._client.prepareApproval(selected.id);\n if (\n this.selectedRequest?.id !== selected.id\n || jcsCanonicalize(this.selectedRequest.request)\n !== jcsCanonicalize(prepared.pending.request)\n ) {\n this._message.set({\n kind: 'info',\n text: 'The request changed while its authority was being resolved. Review it again.',\n }, undefined);\n return;\n }\n this._preparedApproval.set(prepared, undefined);\n this._detailOffset.set(0, undefined);\n this._mode.set('approve', undefined);\n this._message.set(undefined, undefined);\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n } finally {\n this._busy.set(false, undefined);\n }\n }\n\n public beginDeny(): void {\n if (!this._canDecide()) return;\n this._denialReason.set('', undefined);\n this._mode.set('deny', undefined);\n }\n\n public setDenialReason(reason: string): void {\n this._denialReason.set(reason, undefined);\n }\n\n public cancelMode(): void {\n if (this._busy.get()) return;\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n\n public async confirmCurrentMode(): Promise<void> {\n const mode = this._mode.get();\n const selected = this.selectedRequest;\n if (this._busy.get() || selected === undefined || (mode !== 'approve' && mode !== 'deny')) return;\n\n this._busy.set(true, undefined);\n this._message.set({\n kind: 'info',\n text: mode === 'approve' ? 'Approving request...' : 'Denying request...',\n }, undefined);\n try {\n let outcome: ApprovalDecisionOutcome;\n if (mode === 'approve') {\n const prepared = this._preparedApproval.get();\n if (prepared === undefined) {\n throw new Error('approval details are no longer available; review the request again');\n }\n outcome = await this._client.approvePrepared(prepared);\n } else {\n const reason = this._denialReason.get().trim();\n outcome = await this._client.deny(\n selected.id,\n reason.length > 0 ? reason : undefined,\n selected,\n );\n }\n this._message.set({\n kind: outcome === 'applied' ? 'success' : 'info',\n text: outcome === 'applied'\n ? `${mode === 'approve' ? 'Approved' : 'Denied'} ${selected.request.consumer.name}.`\n : `Decision accepted for ${selected.request.consumer.name}, `\n + 'but a matching request is still pending. The consumer may have retried.',\n }, undefined);\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n } finally {\n this._busy.set(false, undefined);\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n }\n\n public async refresh(): Promise<void> {\n if (this._busy.get()) return;\n this._message.set({ kind: 'info', text: 'Refreshing approval requests...' }, undefined);\n try {\n await this._client.refresh();\n if (this._connectionState.get() === 'live') {\n this._message.set({ kind: 'info', text: 'Approval requests are up to date.' }, undefined);\n }\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n }\n }\n\n public scrollDetails(delta: number, lineCount: number, viewportSize: number): void {\n const maxOffset = Math.max(0, lineCount - Math.max(1, viewportSize));\n const next = Math.max(0, Math.min(maxOffset, this._detailOffset.get() + delta));\n this._detailOffset.set(next, undefined);\n }\n\n public dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._subscription.dispose();\n }\n\n private _canDecide(): boolean {\n if (this._busy.get() || this.selectedRequest === undefined) return false;\n if (this._connectionState.get() !== 'live') {\n this._message.set({\n kind: 'error',\n text: 'Cannot decide requests while the approval connection is stale.',\n }, undefined);\n return false;\n }\n return true;\n }\n\n private _applySnapshot(snapshot: ApprovalSnapshot): void {\n const previous = this._requests.get();\n const selectedId = this._selectedRequestId.get();\n const previousSelected = previous.find((item) => item.id === selectedId);\n const previousIndex = Math.max(0, previous.findIndex((item) => item.id === selectedId));\n const selectedStillExists = snapshot.requests.some((item) => item.id === selectedId);\n const nextSelected = snapshot.requests.find((item) => item.id === selectedId);\n const selectedChanged = previousSelected !== undefined\n && nextSelected !== undefined\n && jcsCanonicalize(previousSelected.request) !== jcsCanonicalize(nextSelected.request);\n\n this._requests.set(snapshot.requests, undefined);\n this._connectionState.set(snapshot.state, undefined);\n\n if (snapshot.requests.length === 0) {\n this._selectedRequestId.set(undefined, undefined);\n this._detailOffset.set(0, undefined);\n } else if (!selectedStillExists) {\n const nextIndex = Math.min(previousIndex, snapshot.requests.length - 1);\n this._selectedRequestId.set(snapshot.requests[nextIndex].id, undefined);\n this._detailOffset.set(0, undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n\n if (\n ((!selectedStillExists && selectedId !== undefined) || selectedChanged)\n && this._mode.get() !== 'browse'\n ) {\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n this._message.set({\n kind: 'info',\n text: selectedChanged\n ? 'The selected request changed. Review it again before deciding.'\n : 'The selected request is no longer pending.',\n }, undefined);\n }\n if (snapshot.state === 'stale' && snapshot.error !== undefined) {\n this._message.set({ kind: 'error', text: snapshot.error }, undefined);\n }\n }\n}\n","import React from 'react';\nimport { render } from 'ink';\nimport type { ApprovalCommandClient } from '../commands/approval';\nimport { ApprovalApp } from './ApprovalApp';\nimport { ApprovalUiModel } from './ApprovalUiModel';\n\nexport interface RunApprovalUiOptions {\n readonly client: ApprovalCommandClient;\n readonly signal: AbortSignal;\n}\n\nexport async function runApprovalUi(options: RunApprovalUiOptions): Promise<void> {\n const model = new ApprovalUiModel(options.client);\n const instance = render(<ApprovalApp model={model} />);\n const onAbort = () => instance.unmount();\n options.signal.addEventListener('abort', onAbort, { once: true });\n if (options.signal.aborted) onAbort();\n try {\n await raceAbort(model.refresh(), options.signal);\n if (options.signal.aborted) return;\n await instance.waitUntilExit();\n } finally {\n options.signal.removeEventListener('abort', onAbort);\n instance.unmount();\n model.dispose();\n }\n}\n\nfunction raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T | undefined> {\n if (signal.aborted) return Promise.resolve(undefined);\n return new Promise<T | undefined>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener('abort', onAbort);\n resolve(undefined);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ErrorCode, InMemoryManagedIdentity, JsonRpcChannel, RpcError, SigningSender, TransportPair, capabilityFreshAt, defineInterface, isAssignable, issueCapability, parseStaticHubSchema, permissionMatchesTarget, permits, requestType, traceMessageTransport, withRpcTimeout } from "@hediet/linkrpc";
|
|
1
|
+
import { ErrorCode, InMemoryManagedIdentity, JsonRpcChannel, RpcError, SigningSender, TransportPair, base64UrlToBytes, capabilityFreshAt, defineInterface, isAssignable, issueCapability, parseStaticHubSchema, permissionMatchesTarget, permits, principalForPublicKey, requestType, traceMessageTransport, withRpcTimeout } from "@hediet/linkrpc";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { LINKRPC_ENDPOINT_VAR, LINKRPC_TOKEN_VAR, WebSocketTransport, connectNdjson, connectToHub, createManagedPrincipal, createSelfManagedPrincipal, createSelfManagedPrincipalFromFile, formatEndpointUri, isHubEndpoint, loadOrCreateIdentity, openWebSocket, parseEndpointUri, runInitializeHandshake } from "@hediet/linkrpc/node";
|
|
3
|
+
import { LINKRPC_ENDPOINT_VAR, LINKRPC_TOKEN_VAR, WebSocketTransport, connectNdjson, connectToHub, createManagedPrincipal, createSelfManagedPrincipal, createSelfManagedPrincipalFromFile, formatEndpointUri, identityFilePath, isHubEndpoint, loadOrCreateIdentity, openWebSocket, parseEndpointUri, runInitializeHandshake } from "@hediet/linkrpc/node";
|
|
4
4
|
import { RootOverlay, registerHubServices, registerIdentityServices } from "@hediet/linkrpc-hub/hub/server/client";
|
|
5
5
|
import { SocketServer } from "@hediet/linkrpc-hub/hub/server/node";
|
|
6
6
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
@@ -1125,30 +1125,33 @@ async function resolvePrincipal(spec, sender) {
|
|
|
1125
1125
|
source: { kind: "managed" }
|
|
1126
1126
|
};
|
|
1127
1127
|
} catch {
|
|
1128
|
-
return {
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
userId: MANAGED_FALLBACK_USER_ID
|
|
1133
|
-
}
|
|
1134
|
-
};
|
|
1128
|
+
return _local(identityFilePath({ id: MANAGED_FALLBACK_USER_ID }), () => createSelfManagedPrincipal(MANAGED_FALLBACK_USER_ID), {
|
|
1129
|
+
kind: "managed-fallback",
|
|
1130
|
+
userId: MANAGED_FALLBACK_USER_ID
|
|
1131
|
+
});
|
|
1135
1132
|
}
|
|
1136
|
-
case "user": return {
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
principal: await createSelfManagedPrincipalFromFile(spec.path),
|
|
1145
|
-
source: {
|
|
1146
|
-
kind: "file",
|
|
1147
|
-
path: spec.path
|
|
1148
|
-
}
|
|
1149
|
-
};
|
|
1133
|
+
case "user": return _local(identityFilePath({ id: spec.id }), () => createSelfManagedPrincipal(spec.id), {
|
|
1134
|
+
kind: "user",
|
|
1135
|
+
id: spec.id
|
|
1136
|
+
});
|
|
1137
|
+
case "file": return _local(spec.path, () => createSelfManagedPrincipalFromFile(spec.path), {
|
|
1138
|
+
kind: "file",
|
|
1139
|
+
path: spec.path
|
|
1140
|
+
});
|
|
1150
1141
|
}
|
|
1151
1142
|
}
|
|
1143
|
+
async function _local(file, create, source) {
|
|
1144
|
+
const existed = await fs.access(file).then(() => true, () => false);
|
|
1145
|
+
const principal = await create();
|
|
1146
|
+
return existed ? {
|
|
1147
|
+
principal,
|
|
1148
|
+
source
|
|
1149
|
+
} : {
|
|
1150
|
+
principal,
|
|
1151
|
+
source,
|
|
1152
|
+
createdFile: file
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1152
1155
|
/**
|
|
1153
1156
|
* Render a one-line, human-readable description of the identity used to sign
|
|
1154
1157
|
* calls, e.g. `managed (node abcd012345…)` or
|
|
@@ -1167,22 +1170,44 @@ function formatPrincipalSource(source, nodeId) {
|
|
|
1167
1170
|
//#endregion
|
|
1168
1171
|
//#region ../../packages-private/linkrpc-client-internal/src/identity.ts
|
|
1169
1172
|
/**
|
|
1170
|
-
*
|
|
1171
|
-
*
|
|
1172
|
-
* same keypair so persistent caps issued by the hub keep working across CLI
|
|
1173
|
-
* invocations.
|
|
1173
|
+
* The stored keypair `spec` uses, without reading or creating it. `managed`
|
|
1174
|
+
* identities are held by the peer, so `managed` names its local fallback slot.
|
|
1174
1175
|
*/
|
|
1176
|
+
function cliIdentityTarget(spec) {
|
|
1177
|
+
if (spec.kind === "file") return {
|
|
1178
|
+
label: `file:${spec.path}`,
|
|
1179
|
+
file: spec.path,
|
|
1180
|
+
capsFile: _capsFile(spec.path)
|
|
1181
|
+
};
|
|
1182
|
+
const id = spec.kind === "user" ? spec.id : MANAGED_FALLBACK_USER_ID;
|
|
1183
|
+
const file = identityFilePath({ id });
|
|
1184
|
+
return {
|
|
1185
|
+
label: `user:${id}`,
|
|
1186
|
+
file,
|
|
1187
|
+
capsFile: _capsFile(file)
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
/** The principal stored at `target`, or `undefined` when there is no stored keypair. */
|
|
1191
|
+
async function readCliIdentity(target) {
|
|
1192
|
+
let raw;
|
|
1193
|
+
try {
|
|
1194
|
+
raw = await fs.readFile(target.file, "utf8");
|
|
1195
|
+
} catch (e) {
|
|
1196
|
+
if (e.code === "ENOENT") return void 0;
|
|
1197
|
+
throw e;
|
|
1198
|
+
}
|
|
1199
|
+
const { publicKey } = JSON.parse(raw);
|
|
1200
|
+
if (typeof publicKey !== "string") throw new Error(`malformed identity file ${target.file}`);
|
|
1201
|
+
return principalForPublicKey(base64UrlToBytes(publicKey));
|
|
1202
|
+
}
|
|
1175
1203
|
/**
|
|
1176
|
-
* Delete the
|
|
1177
|
-
*
|
|
1178
|
-
*
|
|
1179
|
-
* stored state).
|
|
1204
|
+
* Delete the keypair and cached capabilities at `target`. The next command
|
|
1205
|
+
* signing with it mints a fresh keypair, which hubs that trusted the old key
|
|
1206
|
+
* do not accept. Returns the files that were removed.
|
|
1180
1207
|
*/
|
|
1181
|
-
async function
|
|
1182
|
-
const identity = await loadOrCreateIdentity({ id: MANAGED_FALLBACK_USER_ID });
|
|
1183
|
-
const capsFile = _capsFile(identity.file);
|
|
1208
|
+
async function deleteCliIdentity(target) {
|
|
1184
1209
|
const removed = [];
|
|
1185
|
-
for (const f of [
|
|
1210
|
+
for (const f of [target.file, target.capsFile]) try {
|
|
1186
1211
|
await fs.unlink(f);
|
|
1187
1212
|
removed.push(f);
|
|
1188
1213
|
} catch (e) {
|
|
@@ -1191,7 +1216,7 @@ async function logoutCliIdentity() {
|
|
|
1191
1216
|
return removed;
|
|
1192
1217
|
}
|
|
1193
1218
|
function _capsFile(identityFile) {
|
|
1194
|
-
return identityFile.replace(/\.json$/, ".caps.json")
|
|
1219
|
+
return identityFile.endsWith(".json") ? identityFile.replace(/\.json$/, ".caps.json") : `${identityFile}.caps.json`;
|
|
1195
1220
|
}
|
|
1196
1221
|
//#endregion
|
|
1197
1222
|
//#region ../../packages-private/linkrpc-client-internal/src/reflection.ts
|
|
@@ -1240,7 +1265,9 @@ const TOPOLOGY_INTERFACE_ID = "hubrpc.topology";
|
|
|
1240
1265
|
* {@link SigningSession.requestAccess}.
|
|
1241
1266
|
*/
|
|
1242
1267
|
async function setupSigning(channel, signing, principalSpec, opts) {
|
|
1243
|
-
const { principal, source: principalSource } = await resolvePrincipal(principalSpec, channel);
|
|
1268
|
+
const { principal, source: principalSource, createdFile } = await resolvePrincipal(principalSpec, channel);
|
|
1269
|
+
if (createdFile !== void 0) process.stderr.write(`linkrpc: warning: no stored keypair was found, so a new identity ${principal.id} was created at ${createdFile}. Hubs that trusted a previous key for this identity will not accept it until they trust or delegate to the new one.
|
|
1270
|
+
`);
|
|
1244
1271
|
signing.principal = principal;
|
|
1245
1272
|
signing.oneShotCaps = void 0;
|
|
1246
1273
|
signing.capProvider = void 0;
|
|
@@ -5105,6 +5132,6 @@ function _endpointCacheKey(endpoint, staticSchema) {
|
|
|
5105
5132
|
return staticSchema === void 0 ? endpointKey : `${endpointKey}|schema:${JSON.stringify(staticSchema)}`;
|
|
5106
5133
|
}
|
|
5107
5134
|
//#endregion
|
|
5108
|
-
export { requestTopologyAccess as $, CallRecordLevelSchema as A, proxyCommand as B, LogLineSchema as C, CallFilterSchema as D, hubDaemonManagementInterface as E, disconnectBroker as F, parseDuration as G, withStaticHubReflection as H, getBrokerStatus as I, resolveSlot as J, complete as K, readBrokerNotifications as L, readEndpointDiscovery as M, ContextStore as N, CallLogLevelSchema as O, formatContextReference as P, requestReflectionAccess as Q, stopConnectionBroker as R, DaemonStatusSchema as S,
|
|
5135
|
+
export { requestTopologyAccess as $, CallRecordLevelSchema as A, proxyCommand as B, LogLineSchema as C, MethodRefWithOptHash as Ct, CallFilterSchema as D, hubDaemonManagementInterface as E, disconnectBroker as F, parseDuration as G, withStaticHubReflection as H, getBrokerStatus as I, resolveSlot as J, complete as K, readBrokerNotifications as L, readEndpointDiscovery as M, ContextStore as N, CallLogLevelSchema as O, formatContextReference as P, requestReflectionAccess as Q, stopConnectionBroker as R, DaemonStatusSchema as S, parseParamOverride as St, ServiceStatusSchema as T, parseConnectionLimit as U, tunnelCommand as V, parseConnectionLimitMilliseconds as W, parseLine as X, COMMAND_TREE as Y, ChannelDirectorySource as Z, runParams as _, describeSchema as _t, resolveInvocationEndpoint as a, walkHubDetailed as at, LINKRPC_HUB_HOME_VAR as b, valueToConstSchema as bt, resolveLocalEndpoint as c, readCliIdentity as ct, endpointAddress as d, connect as dt, setupSigning as et, endpointDefinition as f, connectViaRootOverlay as ft, runEvent as g, describeObjectParams as gt, processSource as h, resolvedEndpointToConfig as ht, resolveInvocationContext as i, walkHub as it, CallRecordSchema as j, CallPeerSchema as k, connectToHubManagement as l, formatPrincipalSource as lt, managedEndpointsInterface as m, resolveTargetEndpoint as mt, loadStaticHubSchema as n, fetchSchema$1 as nt, resolveSigning as o, cliIdentityTarget as ot, endpointStatus as p, connectViaTransport as pt, resolveCliInvocation as q, resolveStaticHubSchemaSource as r, findMethodInSchema as rt, validationDefault as s, deleteCliIdentity as st, completeForLine as t, fetchDefaults as tt, consoleAddress as u, parsePrincipalSpec as ut, watchEvent as v, explainValidation as vt, ServiceStateSchema as w, mcpForwardInterface as wt, ConfigDocumentSchema as x, mergeParams as xt, HubHome as y, validateValueAgainstSchema as yt, ConnectionBroker as z };
|
|
5109
5136
|
|
|
5110
|
-
//# sourceMappingURL=runComplete-
|
|
5137
|
+
//# sourceMappingURL=runComplete-1DjMsU_0.js.map
|