@jaw.id/cli 0.1.26 → 0.2.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/dist/base-command.js +3 -1
- package/dist/base-command.js.map +1 -1
- package/dist/commands/config/set.js +140 -12
- package/dist/commands/config/set.js.map +1 -1
- package/dist/commands/config/show.js +3 -1
- package/dist/commands/config/show.js.map +1 -1
- package/dist/commands/config/write.js +6 -4
- package/dist/commands/config/write.js.map +1 -1
- package/dist/commands/disconnect.js +24 -10
- package/dist/commands/disconnect.js.map +1 -1
- package/dist/commands/mcp/index.js +2426 -94
- package/dist/commands/mcp/index.js.map +1 -1
- package/dist/commands/rpc/call.js +197 -45
- package/dist/commands/rpc/call.js.map +1 -1
- package/dist/commands/session/add.js +1547 -0
- package/dist/commands/session/add.js.map +1 -0
- package/dist/commands/session/revoke.js +181 -54
- package/dist/commands/session/revoke.js.map +1 -1
- package/dist/commands/session/setup.js +516 -65
- package/dist/commands/session/setup.js.map +1 -1
- package/dist/commands/session/status.js +315 -6
- package/dist/commands/session/status.js.map +1 -1
- package/dist/commands/version.js +3 -1
- package/dist/commands/version.js.map +1 -1
- package/dist/commands/x402/log.js +344 -0
- package/dist/commands/x402/log.js.map +1 -0
- package/dist/commands/x402/pay.js +2122 -0
- package/dist/commands/x402/pay.js.map +1 -0
- package/dist/commands/x402/status.js +1047 -0
- package/dist/commands/x402/status.js.map +1 -0
- package/dist/index.js +41 -14
- package/dist/index.js.map +1 -1
- package/dist/lib/bridge-singleton.js +41 -14
- package/dist/lib/bridge-singleton.js.map +1 -1
- package/dist/lib/config.js +26 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/keystore.js +13 -2
- package/dist/lib/keystore.js.map +1 -1
- package/dist/lib/paths.js +3 -1
- package/dist/lib/paths.js.map +1 -1
- package/dist/lib/payment-lock.js +121 -0
- package/dist/lib/payment-lock.js.map +1 -0
- package/dist/lib/session-bridge.js +148 -24
- package/dist/lib/session-bridge.js.map +1 -1
- package/dist/lib/session-config.js +78 -11
- package/dist/lib/session-config.js.map +1 -1
- package/dist/lib/terminal.js +22 -0
- package/dist/lib/terminal.js.map +1 -0
- package/dist/lib/validation.js +3 -3
- package/dist/lib/validation.js.map +1 -1
- package/dist/lib/ws-bridge.js +22 -10
- package/dist/lib/ws-bridge.js.map +1 -1
- package/dist/mcp/handlers/config.js +73 -6
- package/dist/mcp/handlers/config.js.map +1 -1
- package/dist/mcp/handlers/daemon.js +43 -12
- package/dist/mcp/handlers/daemon.js.map +1 -1
- package/dist/mcp/handlers/resources.js +119 -0
- package/dist/mcp/handlers/resources.js.map +1 -1
- package/dist/mcp/handlers/rpc.js +269 -60
- package/dist/mcp/handlers/rpc.js.map +1 -1
- package/dist/mcp/helpers.js +50 -3
- package/dist/mcp/helpers.js.map +1 -1
- package/dist/mcp/server.js +2426 -94
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.js +43 -3
- package/dist/mcp/tools.js.map +1 -1
- package/dist/x402/log-view.js +160 -0
- package/dist/x402/log-view.js.map +1 -0
- package/dist/x402/status-report.js +90 -0
- package/dist/x402/status-report.js.map +1 -0
- package/oclif.manifest.json +405 -11
- package/package.json +5 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import * as
|
|
2
|
+
import * as fs5 from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import * as os from 'os';
|
|
5
5
|
import * as crypto from 'crypto';
|
|
6
6
|
import WebSocket from 'ws';
|
|
7
7
|
|
|
8
|
-
// src/
|
|
8
|
+
// src/commands/session/revoke.ts
|
|
9
9
|
var JAW_DIR = path.join(os.homedir(), ".jaw");
|
|
10
10
|
var PATHS = {
|
|
11
11
|
root: JAW_DIR,
|
|
@@ -13,7 +13,9 @@ var PATHS = {
|
|
|
13
13
|
session: path.join(JAW_DIR, "session.json"),
|
|
14
14
|
relay: path.join(JAW_DIR, "relay.json"),
|
|
15
15
|
keystore: path.join(JAW_DIR, "keystore.json"),
|
|
16
|
-
sessionConfig: path.join(JAW_DIR, "session-config.json")
|
|
16
|
+
sessionConfig: path.join(JAW_DIR, "session-config.json"),
|
|
17
|
+
x402Log: path.join(JAW_DIR, "x402-log.jsonl"),
|
|
18
|
+
paymentLock: path.join(JAW_DIR, "x402-payment.lock")
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
// src/lib/validation.ts
|
|
@@ -41,8 +43,8 @@ function isValidRelayUrl(url) {
|
|
|
41
43
|
|
|
42
44
|
// src/lib/config.ts
|
|
43
45
|
function ensureDir(dir) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
fs5.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
47
|
+
fs5.chmodSync(dir, 448);
|
|
46
48
|
}
|
|
47
49
|
function migrateConfig(config) {
|
|
48
50
|
if (config.paymasterUrl && !config.paymasters) {
|
|
@@ -54,10 +56,10 @@ function migrateConfig(config) {
|
|
|
54
56
|
return config;
|
|
55
57
|
}
|
|
56
58
|
function loadConfig() {
|
|
57
|
-
if (!
|
|
59
|
+
if (!fs5.existsSync(PATHS.config)) {
|
|
58
60
|
return {};
|
|
59
61
|
}
|
|
60
|
-
const raw =
|
|
62
|
+
const raw = fs5.readFileSync(PATHS.config, "utf-8");
|
|
61
63
|
try {
|
|
62
64
|
const config = JSON.parse(raw);
|
|
63
65
|
return migrateConfig(config);
|
|
@@ -69,7 +71,7 @@ function loadConfig() {
|
|
|
69
71
|
}
|
|
70
72
|
function saveConfig(config) {
|
|
71
73
|
ensureDir(PATHS.root);
|
|
72
|
-
|
|
74
|
+
fs5.writeFileSync(PATHS.config, JSON.stringify(config, null, 2) + "\n", {
|
|
73
75
|
encoding: "utf-8",
|
|
74
76
|
mode: 384
|
|
75
77
|
});
|
|
@@ -223,7 +225,18 @@ function bufferToBase64(buf) {
|
|
|
223
225
|
}
|
|
224
226
|
|
|
225
227
|
// src/lib/ws-bridge.ts
|
|
228
|
+
function buildInitPayload(config) {
|
|
229
|
+
return {
|
|
230
|
+
type: "init",
|
|
231
|
+
apiKey: config.apiKey,
|
|
232
|
+
chainId: config.chainId,
|
|
233
|
+
ens: config.ens,
|
|
234
|
+
paymasterUrl: config.paymasterUrl,
|
|
235
|
+
...config.paymasterUrl && config.paymasterContext ? { paymasterContext: config.paymasterContext } : {}
|
|
236
|
+
};
|
|
237
|
+
}
|
|
226
238
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
239
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
|
|
227
240
|
var MAX_MESSAGE_BYTES = 5 * 1024 * 1024;
|
|
228
241
|
var BROWSER_REOPEN_COOLDOWN_MS = 5e3;
|
|
229
242
|
var MAX_RECONNECT_ATTEMPTS = 3;
|
|
@@ -232,6 +245,7 @@ var WSBridge = class {
|
|
|
232
245
|
relayUrl;
|
|
233
246
|
session;
|
|
234
247
|
timeout;
|
|
248
|
+
connectTimeout;
|
|
235
249
|
config;
|
|
236
250
|
privateKeyHex;
|
|
237
251
|
publicKeyHex;
|
|
@@ -253,6 +267,7 @@ var WSBridge = class {
|
|
|
253
267
|
this.relayUrl = options.relayUrl;
|
|
254
268
|
this.session = options.session;
|
|
255
269
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
270
|
+
this.connectTimeout = options.connectTimeout ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
256
271
|
this.config = options.config;
|
|
257
272
|
this.privateKeyHex = options.privateKeyHex;
|
|
258
273
|
this.publicKeyHex = options.publicKeyHex;
|
|
@@ -281,17 +296,16 @@ var WSBridge = class {
|
|
|
281
296
|
let expectingKeyExchange = !this.peerPublicKeyHex;
|
|
282
297
|
const timer = setTimeout(() => {
|
|
283
298
|
ws.close();
|
|
284
|
-
reject(
|
|
285
|
-
|
|
299
|
+
reject(
|
|
300
|
+
new Error(
|
|
301
|
+
`Browser did not connect within ${Math.round(this.connectTimeout / 1e3)}s.
|
|
302
|
+
Run \`jaw disconnect\` then try again, or raise JAW_BRIDGE_TIMEOUT_MS.`
|
|
303
|
+
)
|
|
304
|
+
);
|
|
305
|
+
}, this.connectTimeout);
|
|
286
306
|
const sendEncryptedInit = async () => {
|
|
287
307
|
if (!this.sharedSecret) return;
|
|
288
|
-
const envelope = await encryptMessage(this.sharedSecret,
|
|
289
|
-
type: "init",
|
|
290
|
-
apiKey: this.config.apiKey,
|
|
291
|
-
chainId: this.config.chainId,
|
|
292
|
-
ens: this.config.ens,
|
|
293
|
-
paymasterUrl: this.config.paymasterUrl
|
|
294
|
-
});
|
|
308
|
+
const envelope = await encryptMessage(this.sharedSecret, buildInitPayload(this.config));
|
|
295
309
|
this.sendRaw(ws, JSON.stringify({ type: "encrypted", ...envelope }));
|
|
296
310
|
};
|
|
297
311
|
const waitForReady = () => {
|
|
@@ -539,8 +553,8 @@ function safeParse(data) {
|
|
|
539
553
|
}
|
|
540
554
|
function loadRelaySession() {
|
|
541
555
|
try {
|
|
542
|
-
if (!
|
|
543
|
-
const raw =
|
|
556
|
+
if (!fs5.existsSync(PATHS.relay)) return null;
|
|
557
|
+
const raw = fs5.readFileSync(PATHS.relay, "utf-8");
|
|
544
558
|
const parsed = JSON.parse(raw);
|
|
545
559
|
if (!parsed.session || !parsed.relayUrl || !parsed.privateKey || !parsed.publicKey) {
|
|
546
560
|
return null;
|
|
@@ -552,14 +566,14 @@ function loadRelaySession() {
|
|
|
552
566
|
}
|
|
553
567
|
function saveRelaySession(info) {
|
|
554
568
|
ensureDir(PATHS.root);
|
|
555
|
-
|
|
569
|
+
fs5.writeFileSync(PATHS.relay, JSON.stringify(info, null, 2) + "\n", {
|
|
556
570
|
encoding: "utf-8",
|
|
557
571
|
mode: 384
|
|
558
572
|
});
|
|
559
573
|
}
|
|
560
574
|
function deleteRelaySession() {
|
|
561
575
|
try {
|
|
562
|
-
if (
|
|
576
|
+
if (fs5.existsSync(PATHS.relay)) fs5.unlinkSync(PATHS.relay);
|
|
563
577
|
} catch {
|
|
564
578
|
}
|
|
565
579
|
}
|
|
@@ -569,6 +583,10 @@ var DEFAULT_KEYS_URL = "https://keys.jaw.id";
|
|
|
569
583
|
var DEFAULT_RELAY_URL = "wss://relay.jaw.id";
|
|
570
584
|
async function getBridge(options) {
|
|
571
585
|
const config = loadConfig();
|
|
586
|
+
const envTimeout = Number(process.env["JAW_BRIDGE_TIMEOUT_MS"]);
|
|
587
|
+
const fromEnv = Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : void 0;
|
|
588
|
+
const timeout = options.timeout ?? fromEnv;
|
|
589
|
+
const connectTimeout = options.connectTimeout ?? fromEnv;
|
|
572
590
|
const keysUrl = options.keysUrl ?? config.keysUrl ?? DEFAULT_KEYS_URL;
|
|
573
591
|
const relayUrl = options.relayUrl ?? config.relayUrl ?? DEFAULT_RELAY_URL;
|
|
574
592
|
const chainId = options.chainId ?? config.defaultChain ?? 1;
|
|
@@ -581,7 +599,7 @@ async function getBridge(options) {
|
|
|
581
599
|
let relaySession = loadRelaySession();
|
|
582
600
|
if (relaySession && relaySession.relayUrl === relayUrl && relaySession.peerPublicKey) {
|
|
583
601
|
try {
|
|
584
|
-
return await connectBridge(
|
|
602
|
+
return await connectBridge({ ...options, timeout }, relaySession, chainId, keysUrl, relayUrl, false);
|
|
585
603
|
} catch {
|
|
586
604
|
deleteRelaySession();
|
|
587
605
|
relaySession = null;
|
|
@@ -591,7 +609,7 @@ async function getBridge(options) {
|
|
|
591
609
|
}
|
|
592
610
|
const session = await createNewSession(relayUrl);
|
|
593
611
|
saveRelaySession(session);
|
|
594
|
-
return await connectBridge(
|
|
612
|
+
return await connectBridge({ ...options, timeout, connectTimeout }, session, chainId, keysUrl, relayUrl, true);
|
|
595
613
|
}
|
|
596
614
|
async function createNewSession(relayUrl) {
|
|
597
615
|
const kp = await generateKeyPair();
|
|
@@ -606,17 +624,20 @@ async function createNewSession(relayUrl) {
|
|
|
606
624
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
607
625
|
};
|
|
608
626
|
}
|
|
609
|
-
async function connectBridge(
|
|
627
|
+
async function connectBridge(options, relaySession, chainId, keysUrl, relayUrl, openBrowser) {
|
|
610
628
|
const config = loadConfig();
|
|
629
|
+
const paymaster = config.paymasters?.[chainId];
|
|
611
630
|
const bridge = new WSBridge({
|
|
612
631
|
relayUrl,
|
|
613
632
|
session: relaySession.session,
|
|
614
633
|
timeout: options.timeout,
|
|
634
|
+
connectTimeout: options.connectTimeout,
|
|
615
635
|
config: {
|
|
616
636
|
apiKey: options.apiKey,
|
|
617
637
|
chainId,
|
|
618
638
|
ens: options.ens ?? config.ens,
|
|
619
|
-
paymasterUrl:
|
|
639
|
+
paymasterUrl: paymaster?.url,
|
|
640
|
+
paymasterContext: paymaster?.context
|
|
620
641
|
},
|
|
621
642
|
privateKeyHex: relaySession.privateKey,
|
|
622
643
|
publicKeyHex: relaySession.publicKey,
|
|
@@ -626,6 +647,12 @@ async function connectBridge(relaySession, options, chainId, keysUrl, relayUrl,
|
|
|
626
647
|
// onBrowserNeeded — only open a browser for new sessions
|
|
627
648
|
openBrowser ? async () => {
|
|
628
649
|
const bridgeUrl = buildBridgeUrl(keysUrl, relaySession.session, relayUrl, relaySession.publicKey);
|
|
650
|
+
if (process.env["JAW_NO_BROWSER"]) {
|
|
651
|
+
process.stderr.write(`Open this URL to approve:
|
|
652
|
+
${bridgeUrl}
|
|
653
|
+
`);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
629
656
|
const { default: open } = await import('open');
|
|
630
657
|
await open(bridgeUrl);
|
|
631
658
|
} : void 0,
|
|
@@ -645,35 +672,77 @@ function buildBridgeUrl(keysUrl, session, relayUrl, cliPublicKeyHex) {
|
|
|
645
672
|
return url.toString();
|
|
646
673
|
}
|
|
647
674
|
function deleteKeystore() {
|
|
648
|
-
if (
|
|
649
|
-
|
|
675
|
+
if (fs5.existsSync(PATHS.keystore)) {
|
|
676
|
+
fs5.unlinkSync(PATHS.keystore);
|
|
650
677
|
}
|
|
651
678
|
}
|
|
652
679
|
function keystoreExists() {
|
|
653
|
-
return
|
|
680
|
+
return fs5.existsSync(PATHS.keystore);
|
|
681
|
+
}
|
|
682
|
+
function liveOrphans(orphans, now = Date.now() / 1e3) {
|
|
683
|
+
return (orphans ?? []).filter((orphan) => orphan.expiry > now);
|
|
684
|
+
}
|
|
685
|
+
function writeSessionConfig(config) {
|
|
686
|
+
ensureDir(PATHS.root);
|
|
687
|
+
const temp = `${PATHS.sessionConfig}.${process.pid}.tmp`;
|
|
688
|
+
fs5.writeFileSync(temp, JSON.stringify(config, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
689
|
+
fs5.chmodSync(temp, 384);
|
|
690
|
+
fs5.renameSync(temp, PATHS.sessionConfig);
|
|
691
|
+
}
|
|
692
|
+
function saveRevokeProgress(config, progress) {
|
|
693
|
+
const next = { ...tryLoadSessionConfig() ?? config };
|
|
694
|
+
if (progress.orphans.length > 0) next.orphanedPermissions = progress.orphans;
|
|
695
|
+
else delete next.orphanedPermissions;
|
|
696
|
+
if (progress.ownPermissionRevoked) next.permissionRevoked = true;
|
|
697
|
+
writeSessionConfig(next);
|
|
654
698
|
}
|
|
655
699
|
function loadSessionConfig() {
|
|
656
|
-
if (!
|
|
700
|
+
if (!fs5.existsSync(PATHS.sessionConfig)) {
|
|
657
701
|
throw new Error("No session configured. Run `jaw session setup` first.");
|
|
658
702
|
}
|
|
659
|
-
const raw =
|
|
703
|
+
const raw = fs5.readFileSync(PATHS.sessionConfig, "utf-8");
|
|
660
704
|
try {
|
|
661
705
|
return JSON.parse(raw);
|
|
662
706
|
} catch {
|
|
663
707
|
throw new Error(`Session config at ${PATHS.sessionConfig} is corrupted. Run \`jaw session setup\` to recreate it.`);
|
|
664
708
|
}
|
|
665
709
|
}
|
|
710
|
+
function tryLoadSessionConfig() {
|
|
711
|
+
try {
|
|
712
|
+
return loadSessionConfig();
|
|
713
|
+
} catch {
|
|
714
|
+
return null;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
666
717
|
function deleteSessionConfig() {
|
|
667
|
-
if (
|
|
668
|
-
|
|
718
|
+
if (fs5.existsSync(PATHS.sessionConfig)) {
|
|
719
|
+
fs5.unlinkSync(PATHS.sessionConfig);
|
|
669
720
|
}
|
|
670
721
|
}
|
|
671
722
|
|
|
723
|
+
// src/lib/terminal.ts
|
|
724
|
+
var INVISIBLE_AND_BIDI = /[\u200B-\u200F\u2028\u2029\u202A-\u202E\u2066-\u2069\uFEFF]/g;
|
|
725
|
+
var LINE_CONTROLS = /[\u0000-\u001F\u007F-\u009F]/g;
|
|
726
|
+
var REPLACEMENT = "\uFFFD";
|
|
727
|
+
var DEFAULT_LINE_LENGTH = 200;
|
|
728
|
+
function bound(text, maxLength) {
|
|
729
|
+
if (text.length <= maxLength) return text;
|
|
730
|
+
return `${text.slice(0, maxLength)}\u2026 (${text.length - maxLength} more characters)`;
|
|
731
|
+
}
|
|
732
|
+
function sanitizeLine(value, maxLength = DEFAULT_LINE_LENGTH) {
|
|
733
|
+
const text = typeof value === "string" ? value : String(value);
|
|
734
|
+
return bound(text.replace(LINE_CONTROLS, REPLACEMENT).replace(INVISIBLE_AND_BIDI, REPLACEMENT), maxLength);
|
|
735
|
+
}
|
|
736
|
+
|
|
672
737
|
// src/commands/session/revoke.ts
|
|
673
738
|
var SessionRevoke = class _SessionRevoke extends BaseCommand {
|
|
674
739
|
static description = "Revoke on-chain permission and delete local session key.";
|
|
675
740
|
static flags = {
|
|
676
|
-
...BaseCommand.baseFlags
|
|
741
|
+
...BaseCommand.baseFlags,
|
|
742
|
+
force: Flags.boolean({
|
|
743
|
+
description: "Delete the local session even if some permissions could not be revoked. They stay live on chain until they expire, and their ids are printed because deleting the session is what loses them.",
|
|
744
|
+
default: false
|
|
745
|
+
})
|
|
677
746
|
};
|
|
678
747
|
async run() {
|
|
679
748
|
const { flags } = await this.parse(_SessionRevoke);
|
|
@@ -683,12 +752,20 @@ var SessionRevoke = class _SessionRevoke extends BaseCommand {
|
|
|
683
752
|
return;
|
|
684
753
|
}
|
|
685
754
|
const sessionConfig = loadSessionConfig();
|
|
686
|
-
const
|
|
687
|
-
|
|
755
|
+
const now = Date.now() / 1e3;
|
|
756
|
+
const orphans = liveOrphans(sessionConfig.orphanedPermissions, now);
|
|
757
|
+
const own = (
|
|
758
|
+
// `permissionRevoked` is set by an earlier run that got this far and then
|
|
759
|
+
// failed on something else. Revoking is not idempotent, so attempting it
|
|
760
|
+
// again spends a browser round trip that can only fail.
|
|
761
|
+
!sessionConfig.permissionRevoked && sessionConfig.expiry > now ? { id: sessionConfig.permissionId, chainId: sessionConfig.chainId, expiry: sessionConfig.expiry } : null
|
|
762
|
+
);
|
|
763
|
+
const total = orphans.length + (own ? 1 : 0);
|
|
764
|
+
if (total === 0) {
|
|
688
765
|
deleteKeystore();
|
|
689
766
|
deleteSessionConfig();
|
|
690
767
|
if (format === "json") {
|
|
691
|
-
this.outputResult({ revoked: true, skippedOnChain: true }, format);
|
|
768
|
+
this.outputResult({ revoked: true, skippedOnChain: true, revokedIds: [], failed: [] }, format);
|
|
692
769
|
} else {
|
|
693
770
|
this.log("Session already expired. Cleaned up local files.");
|
|
694
771
|
}
|
|
@@ -696,31 +773,81 @@ var SessionRevoke = class _SessionRevoke extends BaseCommand {
|
|
|
696
773
|
}
|
|
697
774
|
const config = loadConfig();
|
|
698
775
|
const apiKey = this.resolveApiKey(flags);
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
776
|
+
if (!flags.quiet && format !== "json") {
|
|
777
|
+
this.log(
|
|
778
|
+
total === 1 ? "Opening browser to revoke permission..." : `Opening browser to revoke ${total} permissions...`
|
|
779
|
+
);
|
|
702
780
|
}
|
|
703
|
-
const
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
781
|
+
const revokedIds = [];
|
|
782
|
+
const failed = [];
|
|
783
|
+
let remaining = orphans;
|
|
784
|
+
let ownRevoked = false;
|
|
785
|
+
const revokeOn = async (chainId, targets) => {
|
|
786
|
+
let bridge;
|
|
787
|
+
try {
|
|
788
|
+
bridge = await getBridge({ keysUrl: config.keysUrl, apiKey, chainId, ens: config.ens });
|
|
789
|
+
} catch (err) {
|
|
790
|
+
for (const target of targets) failed.push({ id: target.id, reason: describe(err) });
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
try {
|
|
794
|
+
for (const target of targets) {
|
|
795
|
+
try {
|
|
796
|
+
await bridge.request("wallet_revokePermissions", [{ id: target.id }]);
|
|
797
|
+
revokedIds.push(target.id);
|
|
798
|
+
if (target === own) ownRevoked = true;
|
|
799
|
+
else remaining = remaining.filter((orphan) => orphan.id !== target.id);
|
|
800
|
+
saveRevokeProgress(sessionConfig, { orphans: remaining, ownPermissionRevoked: ownRevoked });
|
|
801
|
+
} catch (err) {
|
|
802
|
+
failed.push({ id: target.id, reason: describe(err) });
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
} finally {
|
|
806
|
+
bridge.close();
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
for (const chainId of [...new Set(orphans.map((orphan) => orphan.chainId))]) {
|
|
810
|
+
await revokeOn(
|
|
811
|
+
chainId,
|
|
812
|
+
orphans.filter((orphan) => orphan.chainId === chainId)
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
if (own) await revokeOn(own.chainId, [own]);
|
|
816
|
+
const cleanedUp = failed.length === 0 || flags.force;
|
|
817
|
+
if (cleanedUp) {
|
|
818
|
+
deleteKeystore();
|
|
819
|
+
deleteSessionConfig();
|
|
714
820
|
}
|
|
715
|
-
deleteKeystore();
|
|
716
|
-
deleteSessionConfig();
|
|
717
821
|
if (format === "json") {
|
|
718
|
-
this.outputResult(
|
|
719
|
-
|
|
822
|
+
this.outputResult(
|
|
823
|
+
{ revoked: failed.length === 0, skippedOnChain: false, revokedIds, failed, localSessionDeleted: cleanedUp },
|
|
824
|
+
format
|
|
825
|
+
);
|
|
826
|
+
} else if (failed.length === 0) {
|
|
720
827
|
this.log("Session revoked. On-chain permission removed and local keys deleted.");
|
|
828
|
+
if (revokedIds.length > 1) {
|
|
829
|
+
this.log(`Revoked ${revokedIds.length} permissions this key was holding.`);
|
|
830
|
+
}
|
|
831
|
+
} else {
|
|
832
|
+
if (revokedIds.length > 0) this.log(`Revoked ${revokedIds.length} of ${total} permissions.`);
|
|
833
|
+
for (const failure of failed) {
|
|
834
|
+
this.log(` could not revoke ${failure.id}: ${failure.reason}`);
|
|
835
|
+
}
|
|
836
|
+
this.log(
|
|
837
|
+
flags.force ? "\nLocal session deleted anyway, as asked. Those permissions stay live until they expire, and the ids above are the only record left of them." : "\nLocal session files were kept so the rest can be retried. Run this again, or pass --force to delete the local session anyway if one of these was already revoked elsewhere."
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
if (failed.length > 0 && !flags.force) {
|
|
841
|
+
this.error(
|
|
842
|
+
`${failed.length} of ${total} permissions could not be revoked. One already revoked elsewhere will keep failing, since the record it is read from is gone.`,
|
|
843
|
+
{ exit: 1 }
|
|
844
|
+
);
|
|
721
845
|
}
|
|
722
846
|
}
|
|
723
847
|
};
|
|
848
|
+
function describe(err) {
|
|
849
|
+
return sanitizeLine(err instanceof Error ? err.message : String(err), 200);
|
|
850
|
+
}
|
|
724
851
|
|
|
725
852
|
export { SessionRevoke as default };
|
|
726
853
|
//# sourceMappingURL=revoke.js.map
|