chainlesschain 0.161.12 → 0.162.0
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/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-B1dwBvzW.js → AIOps-Dn8q-Cu4.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DfR4oLvh.js → ActionButton-BePEVs4O.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D3ZYGXjr.js → Analytics-CKp-5Gi0.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-CsmOoh-7.js → AppLayout-BSudqld0.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-B4gwDm63.js → Audit-iefpSeRG.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-T42uSArV.js → Backup-Ce43ZIhD.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CFi52nMs.js → BaseInput-BvGiwRav.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-D7Vvok1V.js → Chat-BAaQg-Oc.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Dwaflpww.js → Checkbox-Dvn8uxKO.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BIqx3G0b.js → Codegen-CTcZCayj.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DzIUYUNu.js → Col-CBFpGgb5.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DKePtzhk.js → Community-DmCYaV9M.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CirVV9Wq.js → Compact-DnOD5uMF.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CrXOr0sy.js → Compliance-u53e9lg-.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BEBP6Tht.js → Cowork-CL5ohuXH.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-k7nNUuqh.js → Cron-DubcmRgt.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-CBnX0Dhq.js → Crosschain-BWXcUXc3.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B48FszWS.js → DID-Cw0i8WjE.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-Pb3qfFpp.js → Dashboard-BbofvIWH.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-pUHy4CQ2.js → Dropdown-DN6ur5xV.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CT0Qs-kR.js → Federation-CA-rIdkY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CbJJp5BR.js → FormItemContext-D_HGU4aA.js} +1 -1
- package/src/assets/web-panel/assets/{Git-B3mGNLQe.js → Git-CBWFs6Uk.js} +1 -1
- package/src/assets/web-panel/assets/{Governance-BKf4733q.js → Governance-Cx6PTC43.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DZjU541G.js → Inference-Ubk1VstS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C8L-7Dd1.js → KnowledgeGraph-DTB10MYO.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CwDwOiKv.js → Logs-Tfk4FBVC.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-C2YWWU0M.js → Marketplace-BAsztG4O.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-dIbkOypF.js → McpTools-DliPfvuK.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-7eF8WzcY.js → Memory-hkw6Xwyv.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-C74GHLbX.js → MobileBridge-eeNMFGj6.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CSEDo5Fo.js → Mtc-BP3Riowm.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-DiJXxOrB.js → MtcAudit-DvD7pE7V.js} +1 -1
- package/src/assets/web-panel/assets/Multisig-CPtc-fVL.js +7 -0
- package/src/assets/web-panel/assets/Multisig-kwPDnXnl.css +1 -0
- package/src/assets/web-panel/assets/{NLProgramming-DjF-gIUw.js → NLProgramming-1y__Epjg.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BUE5CvMO.js → Notes-CEvJqMP8.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-Dfbrobje.js → NotificationSettings-wmCYm99r.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-C6YvqjQB.js → Organization-CSoz8gGr.js} +1 -1
- package/src/assets/web-panel/assets/{Overflow-BvHNhdMR.js → Overflow-kf1mnFrM.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BO0hQHFS.js → P2P-C4GfXJ8Z.js} +1 -1
- package/src/assets/web-panel/assets/{Permissions-CCPlrJeP.js → Permissions-CW1Mn95X.js} +1 -1
- package/src/assets/web-panel/assets/{Pipeline-DTCL3FjJ.js → Pipeline-CM1ppddn.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-08DYgOe_.js → Privacy-DuAY5fEm.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B7j-Z8sa.js → ProjectInit-C72779b6.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-CFqLhV1w.js → ProjectSettings-CAilXWam.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-BPlpx2UN.js → Projects-DTIlVTkF.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BCBPbVbF.js → Providers-Cf6Yv8bu.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-C8Job6zl.js → QuickAsk-CK1_VVzw.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DOV_Aje-.js → Recommend-QBC7KgvR.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DOgK_dIK.js → Reputation-ju6lWzMM.js} +1 -1
- package/src/assets/web-panel/assets/{Row-8jdU1xYg.js → Row-DQwipGEm.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B289OgNZ.js → RssFeed-DkLGmeLW.js} +1 -1
- package/src/assets/web-panel/assets/{Search-cr0AndFE.js → Search-YYhitzkt.js} +1 -1
- package/src/assets/web-panel/assets/{Security-w4diykaE.js → Security-DEllaBqe.js} +1 -1
- package/src/assets/web-panel/assets/{Services-dTxAI5cG.js → Services-BgPHBq9S.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-B3FiUiRo.js → Skeleton-DHEyJI7c.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DgtBTAFC.js → Skills-c212vgf3.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-B4Y6bvbL.js → Sla-COqhw_no.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-C8FEvArc.js → SpeechSettings-Bmds06su.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CHvV5L0m.js → SyncSettings-Bx1_A34Y.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-B4Py5ORS.js → Tasks-B0Lo_9aN.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-MeTyXM5u.js → Templates-D0RcpfuW.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Doiz7wyQ.js → Tenant-G0yVctLy.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DSEAdwWN.js → Terminal-DqgLtK3c.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BBrtaEKt.js → Tokens-Cdt0aqCc.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-nPvjho27.js → Trigger-DFbfZFuJ.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BFwPyS_6.js → Trust-BQXsWPz6.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DFsHoY1J.js → UkeySign-DBem5Xkj.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-FkSKqHE9.js → VideoEditing-B1yipKKv.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-AXo-_4-w.js → Wallet-iPJtU5QZ.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-DoScnQ-4.js → WebAuthn-HLb9srUL.js} +1 -1
- package/src/assets/web-panel/assets/{WorkflowEditor-IEMfIax-.js → WorkflowEditor-BSqXL8GD.js} +1 -1
- package/src/assets/web-panel/assets/{chat-pc1ciH6T.js → chat-D_J-ZVBh.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CjkIkB0e.js → colors-B126JcB4.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CQZnkP5p.js → compact-item-Bw5EEKw4.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-B1McGnV-.js → createContext-xLJXI46O.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-CbkA6peP.js → hasIn-K8QCNlyy.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChCCGHwz.js → index-85lab9HJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYAWIXFt.js → index-B9ztiTnX.js} +1 -1
- package/src/assets/web-panel/assets/index-BEYypR_d.js +1 -0
- package/src/assets/web-panel/assets/{index-wwQ_ZkWN.js → index-BQ_NIMQS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNLeseG1.js → index-BSgvvXgq.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcSe5y5O.js → index-BWUG9yVI.js} +1 -1
- package/src/assets/web-panel/assets/{index-uWvLy_3T.js → index-B_PqXUkT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJr12ypE.js → index-BaXXyyT0.js} +1 -1
- package/src/assets/web-panel/assets/{index-NRWBOo4F.js → index-Bptjq-wQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dzfj71tf.js → index-BsbKjK1o.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMjPzhsp.js → index-Bv9odL87.js} +1 -1
- package/src/assets/web-panel/assets/{index-5c4JzwY3.js → index-C2CgD7TN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzZ3LxPK.js → index-COCq6xuZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dn7SHV2e.js → index-CVeuzjxG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGb36exe.js → index-CWBajOcE.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5mpCgak.js → index-CvAey6iD.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKledOCh.js → index-DFPVNSby.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8r6OBuk.js → index-DFwF_JeQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjxVsyn_.js → index-DLZZi1Km.js} +1 -1
- package/src/assets/web-panel/assets/{index-DPzT5L14.js → index-DY5Oc3z6.js} +3 -3
- package/src/assets/web-panel/assets/index-DZWfmuM2.js +1 -0
- package/src/assets/web-panel/assets/{index-CFCQl1hk.js → index-DZcij18m.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4rhVRSV.js → index-Da7bZewp.js} +1 -1
- package/src/assets/web-panel/assets/{index-C052wi94.js → index-DdMzLeDn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTyhXFDW.js → index-Dj8BNg-z.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHtiecyM.js → index-DlX09aXr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjM0jsm1.js → index-DrfiELFa.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGke5qZp.js → index-Dt0Tp8TS.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKwkP66s.js → index-DvNCyE3A.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWq64zmv.js → index-LZYGhjVr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di5tuS0d.js → index-fMwtau_-.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEENN81t.js → index-mqHxeING.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHpwwlmv.js → index-mzNWO8Yy.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJWYN-AT.js → index-p3d5_s7V.js} +1 -1
- package/src/assets/web-panel/assets/{index-C0Lj7Yl0.js → index-qJbfToeQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-fqI1KnP_.js → index-sAfwWh0R.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsChgzu2.js → index-xJkPbv0L.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJbqE5Sw.js → index-yhA-qP4Y.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bs-romIz.js → index-zEr6BW9X.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BTloFqyf.js → initDefaultProps-CacwmJft.js} +1 -1
- package/src/assets/web-panel/assets/{motion-44iMBc1o.js → motion-BWrP7Lz6.js} +1 -1
- package/src/assets/web-panel/assets/{move-CyWQI5eW.js → move-imnbiy1n.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CXfJtuFy.js → omit-BlaOv91I.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-ANFpSZes.js → pickAttrs-DUGKp0ro.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CigX-url.js → placementArrow-P0ZA4yAK.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Ch48RA0m.js → responsiveObserve-CZz-M9cI.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BEz3LORF.js → slide-BEnICwoX.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-D9EniG8V.js → statusUtils-DdYKRSiH.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-C1IvuY3L.js → styleChecker-DgUxvOQt.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C92oHeXB.js → useFlexGapSupport-BUEmeWdR.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CJhvFpgB.js → useFs-BXsj6Z5e.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BPkyunN_.js → vnode-B3Pp583L.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B6Ipb64r.js → zoom-D-LYfiQh.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/crosschain.js +403 -1
- package/src/commands/pair.js +291 -0
- package/src/index.js +2 -0
- package/src/lib/cross-chain-mtc.js +275 -6
- package/src/lib/cross-chain.js +48 -2
- package/src/lib/lan-pairing-preflight.js +425 -0
- package/src/lib/lan-pairing-tokens.js +264 -0
- package/src/assets/web-panel/assets/Multisig-D-IuEDLa.css +0 -1
- package/src/assets/web-panel/assets/Multisig-FZTU5ri6.js +0 -1
- package/src/assets/web-panel/assets/index-BXfePRef.js +0 -1
- package/src/assets/web-panel/assets/index-Dc4fj_Ys.js +0 -1
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #21 A.1 PR2 — Pairing token issuer + persistent store.
|
|
3
|
+
*
|
|
4
|
+
* Pre-generates pairing tokens compatible with the existing Electron
|
|
5
|
+
* `device-pairing-handler.js` QR data format. Use case: SSH-only Linux
|
|
6
|
+
* dev box / CI runner where the user wants to:
|
|
7
|
+
*
|
|
8
|
+
* 1. SSH into the box and run `cc pair token generate --did did:cc:foo`
|
|
9
|
+
* 2. Copy/paste the 6-digit code or scan ASCII QR
|
|
10
|
+
* 3. Use it on mobile / Electron client to complete pairing
|
|
11
|
+
*
|
|
12
|
+
* PR2 ships only token issuance + management. The actual signaling
|
|
13
|
+
* server that listens for mobile→PC confirmation stays in Electron's
|
|
14
|
+
* path (or future PR3 for a headless signaling server).
|
|
15
|
+
*
|
|
16
|
+
* Storage: `~/.chainlesschain/pairing-tokens.json` — simple JSON list of
|
|
17
|
+
* `{ code, did, expiresAtMs, createdAtMs, deviceInfo, status }`.
|
|
18
|
+
* Status: "pending" / "consumed" / "revoked" / "expired".
|
|
19
|
+
*
|
|
20
|
+
* Compatibility: token QR shape matches what `device-pairing-handler.js`
|
|
21
|
+
* `handleQRCodeScan()` expects:
|
|
22
|
+
* { type: "device-pairing", code: "######",
|
|
23
|
+
* did: "did:cc:...", deviceInfo: { ... }, timestamp: <ms> }
|
|
24
|
+
*
|
|
25
|
+
* Spike doc: docs/design/A1_Linux_Native_Pairing_spike.md §2 PR2
|
|
26
|
+
*
|
|
27
|
+
* @module lib/lan-pairing-tokens
|
|
28
|
+
* @version 0.1.0 (#21 A.1 PR2)
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import fs from "node:fs";
|
|
32
|
+
import path from "node:path";
|
|
33
|
+
import os from "node:os";
|
|
34
|
+
import crypto from "node:crypto";
|
|
35
|
+
import { getHomeDir } from "./paths.js";
|
|
36
|
+
|
|
37
|
+
/** Token lifetime — mirrors device-pairing-handler.js pairingTimeout (5 min). */
|
|
38
|
+
const DEFAULT_TTL_MS = 5 * 60 * 1000;
|
|
39
|
+
|
|
40
|
+
/** Token QR type — must match device-pairing-handler.js validation. */
|
|
41
|
+
const QR_TYPE = "device-pairing";
|
|
42
|
+
|
|
43
|
+
const STATUS = Object.freeze({
|
|
44
|
+
PENDING: "pending",
|
|
45
|
+
CONSUMED: "consumed",
|
|
46
|
+
REVOKED: "revoked",
|
|
47
|
+
EXPIRED: "expired",
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Path to the token store file. Caller may override for tests.
|
|
52
|
+
*/
|
|
53
|
+
export function defaultTokenStorePath() {
|
|
54
|
+
return path.join(getHomeDir(), "pairing-tokens.json");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Generate a 6-digit pairing code. Uses crypto.randomInt for unbiased
|
|
59
|
+
* uniform distribution (Math.random would be acceptable too but crypto
|
|
60
|
+
* is cheap on this size).
|
|
61
|
+
*/
|
|
62
|
+
export function generatePairingCode() {
|
|
63
|
+
// 100000 inclusive, 1000000 exclusive → always 6 digits no leading zero loss.
|
|
64
|
+
return String(crypto.randomInt(100000, 1000000));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Build a token's QR data payload that matches the Electron handler's
|
|
69
|
+
* expected shape (handleQRCodeScan in device-pairing-handler.js).
|
|
70
|
+
*
|
|
71
|
+
* @param {{ did: string, deviceInfo?: object }} input
|
|
72
|
+
* @returns {{ code, qrData, expiresAtMs, createdAtMs, status }}
|
|
73
|
+
*/
|
|
74
|
+
export function buildToken({ did, deviceInfo } = {}) {
|
|
75
|
+
if (typeof did !== "string" || !did) {
|
|
76
|
+
const e = new Error("buildToken: did required");
|
|
77
|
+
e.code = "INVALID_ARGS";
|
|
78
|
+
throw e;
|
|
79
|
+
}
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
const code = generatePairingCode();
|
|
82
|
+
const qrData = {
|
|
83
|
+
type: QR_TYPE,
|
|
84
|
+
code,
|
|
85
|
+
did,
|
|
86
|
+
deviceInfo: deviceInfo || {
|
|
87
|
+
deviceId: `cli-${os.hostname() || "unknown"}-${now}`,
|
|
88
|
+
name: os.hostname() || "ChainlessChain CLI",
|
|
89
|
+
platform: os.platform(),
|
|
90
|
+
version: process.env.npm_package_version || "0.1.0",
|
|
91
|
+
},
|
|
92
|
+
timestamp: now,
|
|
93
|
+
};
|
|
94
|
+
return {
|
|
95
|
+
code,
|
|
96
|
+
qrData,
|
|
97
|
+
expiresAtMs: now + DEFAULT_TTL_MS,
|
|
98
|
+
createdAtMs: now,
|
|
99
|
+
status: STATUS.PENDING,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Read the token store. Returns `{ schema, tokens: [...] }`. Creates
|
|
105
|
+
* an empty store if file doesn't exist. Tolerates malformed JSON by
|
|
106
|
+
* returning an empty store + caller can choose to log.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} [filePath]
|
|
109
|
+
* @returns {{ schema: string, tokens: Array }}
|
|
110
|
+
*/
|
|
111
|
+
export function readTokens(filePath = defaultTokenStorePath()) {
|
|
112
|
+
if (!fs.existsSync(filePath)) {
|
|
113
|
+
return { schema: "cc-pairing-tokens/v1", tokens: [] };
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
117
|
+
const parsed = JSON.parse(raw);
|
|
118
|
+
if (parsed && typeof parsed === "object" && Array.isArray(parsed.tokens)) {
|
|
119
|
+
return {
|
|
120
|
+
schema: parsed.schema || "cc-pairing-tokens/v1",
|
|
121
|
+
tokens: parsed.tokens,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return { schema: "cc-pairing-tokens/v1", tokens: [] };
|
|
125
|
+
} catch (_err) {
|
|
126
|
+
// Malformed → return empty (don't crash CLI; user can `revoke --all`).
|
|
127
|
+
return { schema: "cc-pairing-tokens/v1", tokens: [] };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Atomically write the token store. Creates parent dir if missing.
|
|
133
|
+
*
|
|
134
|
+
* @param {{ schema?: string, tokens: Array }} state
|
|
135
|
+
* @param {string} [filePath]
|
|
136
|
+
*/
|
|
137
|
+
export function writeTokens(state, filePath = defaultTokenStorePath()) {
|
|
138
|
+
const dir = path.dirname(filePath);
|
|
139
|
+
if (!fs.existsSync(dir)) {
|
|
140
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
141
|
+
}
|
|
142
|
+
const toWrite = {
|
|
143
|
+
schema: state.schema || "cc-pairing-tokens/v1",
|
|
144
|
+
tokens: state.tokens || [],
|
|
145
|
+
};
|
|
146
|
+
// Write to temp + rename for atomicity (avoid partial reads).
|
|
147
|
+
const tmp = filePath + ".tmp";
|
|
148
|
+
fs.writeFileSync(tmp, JSON.stringify(toWrite, null, 2), "utf-8");
|
|
149
|
+
fs.renameSync(tmp, filePath);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Append a new token to the store. Mark prior pending tokens for the
|
|
154
|
+
* same DID as REVOKED (one-active-token-per-DID invariant — prevents
|
|
155
|
+
* stale codes leaking into mobile scans).
|
|
156
|
+
*
|
|
157
|
+
* @param {{ did, deviceInfo? }} input
|
|
158
|
+
* @param {string} [filePath]
|
|
159
|
+
* @returns {object} the newly-stored token (with status PENDING)
|
|
160
|
+
*/
|
|
161
|
+
export function addToken(input, filePath = defaultTokenStorePath()) {
|
|
162
|
+
const token = buildToken(input);
|
|
163
|
+
const state = readTokens(filePath);
|
|
164
|
+
// Invalidate prior pending tokens for the same DID.
|
|
165
|
+
state.tokens = state.tokens.map((t) => {
|
|
166
|
+
if (t.qrData?.did === input.did && t.status === STATUS.PENDING) {
|
|
167
|
+
return { ...t, status: STATUS.REVOKED, revokedAtMs: Date.now() };
|
|
168
|
+
}
|
|
169
|
+
return t;
|
|
170
|
+
});
|
|
171
|
+
state.tokens.push(token);
|
|
172
|
+
writeTokens(state, filePath);
|
|
173
|
+
return token;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Mark expired tokens. Returns the count touched. Caller can run this
|
|
178
|
+
* before `list` to keep status accurate.
|
|
179
|
+
*/
|
|
180
|
+
export function sweepExpired(filePath = defaultTokenStorePath()) {
|
|
181
|
+
const state = readTokens(filePath);
|
|
182
|
+
const now = Date.now();
|
|
183
|
+
let touched = 0;
|
|
184
|
+
state.tokens = state.tokens.map((t) => {
|
|
185
|
+
if (t.status === STATUS.PENDING && t.expiresAtMs <= now) {
|
|
186
|
+
touched += 1;
|
|
187
|
+
return { ...t, status: STATUS.EXPIRED, expiredAtMs: now };
|
|
188
|
+
}
|
|
189
|
+
return t;
|
|
190
|
+
});
|
|
191
|
+
if (touched > 0) writeTokens(state, filePath);
|
|
192
|
+
return touched;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* List tokens. Optional filter by status. Tokens returned newest-first.
|
|
197
|
+
*/
|
|
198
|
+
export function listTokens(
|
|
199
|
+
{ status, did } = {},
|
|
200
|
+
filePath = defaultTokenStorePath(),
|
|
201
|
+
) {
|
|
202
|
+
sweepExpired(filePath);
|
|
203
|
+
const state = readTokens(filePath);
|
|
204
|
+
let tokens = state.tokens;
|
|
205
|
+
if (status) tokens = tokens.filter((t) => t.status === status);
|
|
206
|
+
if (did) tokens = tokens.filter((t) => t.qrData?.did === did);
|
|
207
|
+
return tokens
|
|
208
|
+
.slice()
|
|
209
|
+
.sort((a, b) => (b.createdAtMs || 0) - (a.createdAtMs || 0));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Look up a token by 6-digit code. Returns null when not found.
|
|
214
|
+
*/
|
|
215
|
+
export function findToken(code, filePath = defaultTokenStorePath()) {
|
|
216
|
+
if (typeof code !== "string" || !code) return null;
|
|
217
|
+
sweepExpired(filePath);
|
|
218
|
+
const state = readTokens(filePath);
|
|
219
|
+
return state.tokens.find((t) => t.code === code) || null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Revoke a token by code. Idempotent — returns `{revoked: false}` when
|
|
224
|
+
* not found or already non-pending.
|
|
225
|
+
*/
|
|
226
|
+
export function revokeToken(code, filePath = defaultTokenStorePath()) {
|
|
227
|
+
const state = readTokens(filePath);
|
|
228
|
+
const i = state.tokens.findIndex((t) => t.code === code);
|
|
229
|
+
if (i < 0) return { revoked: false, reason: "not_found" };
|
|
230
|
+
const t = state.tokens[i];
|
|
231
|
+
if (t.status !== STATUS.PENDING) {
|
|
232
|
+
return { revoked: false, reason: `not_pending(${t.status})` };
|
|
233
|
+
}
|
|
234
|
+
state.tokens[i] = {
|
|
235
|
+
...t,
|
|
236
|
+
status: STATUS.REVOKED,
|
|
237
|
+
revokedAtMs: Date.now(),
|
|
238
|
+
};
|
|
239
|
+
writeTokens(state, filePath);
|
|
240
|
+
return { revoked: true, token: state.tokens[i] };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Mark a token as consumed. Caller (e.g. signaling listener in PR3) calls
|
|
245
|
+
* this after the mobile successfully connects.
|
|
246
|
+
*/
|
|
247
|
+
export function markConsumed(code, filePath = defaultTokenStorePath()) {
|
|
248
|
+
const state = readTokens(filePath);
|
|
249
|
+
const i = state.tokens.findIndex((t) => t.code === code);
|
|
250
|
+
if (i < 0) return { consumed: false, reason: "not_found" };
|
|
251
|
+
const t = state.tokens[i];
|
|
252
|
+
if (t.status !== STATUS.PENDING) {
|
|
253
|
+
return { consumed: false, reason: `not_pending(${t.status})` };
|
|
254
|
+
}
|
|
255
|
+
state.tokens[i] = {
|
|
256
|
+
...t,
|
|
257
|
+
status: STATUS.CONSUMED,
|
|
258
|
+
consumedAtMs: Date.now(),
|
|
259
|
+
};
|
|
260
|
+
writeTokens(state, filePath);
|
|
261
|
+
return { consumed: true, token: state.tokens[i] };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export { STATUS, QR_TYPE, DEFAULT_TTL_MS };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.page-title[data-v-14541f7e]{font-size:22px;font-weight:600;margin:0;color:var(--text-primary)}.page-sub[data-v-14541f7e]{font-size:13px;color:var(--text-secondary);margin:4px 0 0}.filter-bar[data-v-14541f7e]{display:flex;align-items:center;margin-bottom:16px}.multisig-row[data-v-14541f7e]{cursor:pointer}.multisig-row[data-v-14541f7e]:hover{background:var(--bg-hover, rgba(22, 119, 255, .05))}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o as _e,M as O,R as y,c as a,N as t,K as i,r as k,L as p,O as s,u as b,P as r,Q as c,_ as ye,a1 as F,S as x,F as ve,Y as ge,f as Y}from"./vendor-M5lGV-wr.js";import{_ as be,u as ke,d as m}from"./index-DPzT5L14.js";import{u as xe}from"./useShellMode-CgR0wCYM.js";import{R as we,x as G,l as he,aE as Ce,f as X,d as ze,c as Me}from"./icons-NT6gy8Ee.js";import Se from"./index-CEENN81t.js";import"./KeyCode-D63Tfrq7.js";import"./omit-CXfJtuFy.js";import"./pickAttrs-ANFpSZes.js";import"./initDefaultProps-BTloFqyf.js";import"./motion-44iMBc1o.js";import"./raf-Deuc0E8-.js";import"./index-DcSe5y5O.js";import"./index-BTyhXFDW.js";import"./isVisible-C7tPsqfj.js";import"./useState-CSzR8F8O.js";import"./devWarning-CNIS3FrJ.js";import"./warning-Pq00owYb.js";import"./compact-item-CQZnkP5p.js";import"./createContext-B1McGnV-.js";import"./Compact-CirVV9Wq.js";import"./_getTag-BVc6NQ_K.js";import"./styleChecker-C1IvuY3L.js";import"./zoom-B6Ipb64r.js";import"./ActionButton-DfR4oLvh.js";import"./vnode-BPkyunN_.js";const $e={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},De={class:"filter-bar"},Ae={key:0,style:{"font-size":"12px"}},Ie={style:{margin:"0 0 8px 0"}},Le={style:{"margin-left":"8px",color:"var(--text-secondary)"}},Oe={style:{"margin-top":"8px"}},je={style:{cursor:"pointer",color:"var(--text-secondary)"}},Fe={key:0},Ne={style:{margin:"0","max-height":"240px",overflow:"auto","font-size":"12px"}},Te={style:{margin:"16px 0 8px 0"}},Pe={style:{"font-size":"12px"}},Be={__name:"Multisig",setup(Ee){const N=ke(),{isEmbedded:Z}=xe();async function w(l,e,d,f=8e3){if(Z){const _=await N.sendRaw({type:l,...e},f);if(!_?.ok){const g=_?.error;throw new Error(typeof g=="string"?g:g?.message||`${l} failed`)}return _.result}return N.executeJson(d,f)}const D=k(!1),A=k([]),j=k([]),T=k("proposals"),I=k(""),L=k(""),h=k(!1),n=k(null),ee=[{title:"ID",key:"id",width:200},{title:"Domain",dataIndex:"domain",width:220},{title:"状态",key:"state",width:110},{title:"阈值",key:"sigs",width:80},{title:"创建",key:"createdAt",width:140},{title:"过期",key:"expiresAt",width:140},{title:"操作",key:"actions",width:240,fixed:"right"}],te=[{title:"DID",dataIndex:"did"},{title:"Alg",dataIndex:"alg",width:200}],$=Y(()=>{const l={pending:0,reached:0,consumed:0,cancelled:0,expired:0};for(const e of A.value)l[e.state]!==void 0&&(l[e.state]+=1);return l}),ae=Y(()=>A.value.filter(l=>!(I.value&&l.state!==I.value||L.value&&!l.domain.toLowerCase().includes(L.value.toLowerCase()))));function P(l){switch(l){case"pending":return"gold";case"reached":return"cyan";case"consumed":return"green";case"cancelled":return"default";case"expired":return"red";default:return"default"}}function B(l){const e=l-Date.now(),d=Math.abs(e)/6e4;if(d<60)return e>0?`${Math.round(d)} 分钟后`:`${Math.round(d)} 分钟前`;const f=d/60;if(f<24)return e>0?`${Math.round(f)} 小时后`:`${Math.round(f)} 小时前`;const _=f/24;return e>0?`${Math.round(_)} 天后`:`${Math.round(_)} 天前`}async function C(){D.value=!0;try{const[l,e]=await Promise.all([w("multisig.list",{limit:500},"multisig list --limit 500 --json",1e4).catch(()=>[]),Promise.all(["marketplace.purchase","did.rotate","crosschain.outbound"].map(async d=>{try{const f=await w("multisig.policy.show",{domain:d},`multisig policy show ${d} --json`,8e3);return{domain:d,policy:f,updatedAtMs:Date.now()}}catch{return null}})).then(d=>d.filter(Boolean))]);A.value=Array.isArray(l)?l:[],j.value=Array.isArray(e)?e:[]}catch(l){m.error("加载失败: "+(l.message||l))}finally{D.value=!1}}async function E(l){try{const e=await w("multisig.show",{proposalId:l.id},`multisig show ${l.id} --json`,8e3);n.value=e,h.value=!0}catch(e){m.error("加载详情失败: "+(e.message||e))}}function le(l){return{onClick:()=>E(l)}}async function R(l){Se.confirm({title:`取消提案 ${l.id.slice(0,12)}…?`,content:"已签名的成员需要重新发起新提案。此操作不可撤销。",okText:"取消提案",okType:"danger",cancelText:"保持",onOk:async()=>{try{const e=await w("multisig.cancel",{proposalId:l.id,reason:"web-shell"},`multisig cancel ${l.id} --reason web-shell --json`,8e3);e.ok?(m.success("提案已取消"),h.value=!1,await C()):m.error("取消失败: "+e.reason)}catch(e){m.error(e.message||String(e))}}})}async function K(l){try{const e=await w("marketplace.consume",{proposalId:l.id},`marketplace consume ${l.id} --json`,1e4);e.status==="consumed"?(m.success(`订单 ${e.order.itemId} 已执行 (¥${(e.order.amountFen/100).toFixed(2)})`),h.value=!1,await C()):m.error("执行失败: "+(e.reason||JSON.stringify(e)))}catch(e){m.error(e.message||String(e))}}async function oe(l){try{const e=await w("multisig.finalize",{proposalId:l.id},`multisig finalize ${l.id} --json`,8e3);e.ok?(m.success("提案已 finalize"),h.value=!1,await C()):m.error("Finalize 失败: "+e.reason)}catch(e){m.error(e.message||String(e))}}async function se(){try{const l=await w("multisig.sweep",{},"multisig sweep --json",8e3);l.expired===0?m.info("无过期提案"):(m.success(`已标记 ${l.expired} 条提案为过期`),await C())}catch(l){m.error(l.message||String(l))}}return _e(C),(l,e)=>{const d=i("a-button"),f=i("a-space"),_=i("a-statistic"),g=i("a-card"),z=i("a-col"),ne=i("a-row"),M=i("a-radio-button"),re=i("a-radio-group"),ie=i("a-input-search"),S=i("a-tag"),U=i("a-tooltip"),q=i("a-table"),J=i("a-tab-pane"),ue=i("a-empty"),v=i("a-descriptions-item"),V=i("a-descriptions"),Q=i("a-list-item"),W=i("a-list"),de=i("a-tabs"),pe=i("a-list-item-meta"),ce=i("a-divider"),me=i("a-alert"),fe=i("a-drawer");return p(),O("div",null,[y("div",$e,[e[9]||(e[9]=y("div",null,[y("h2",{class:"page-title"},"M-of-N 多签"),y("p",{class:"page-sub"},"marketplace.purchase 大额、DID 关键操作、跨链桥 outbound 的联合签名审批")],-1)),a(f,null,{default:t(()=>[a(d,{loading:D.value,onClick:C},{icon:t(()=>[a(b(we))]),default:t(()=>[e[7]||(e[7]=s(" 刷新 ",-1))]),_:1},8,["loading"]),a(d,{onClick:se},{icon:t(()=>[a(b(G))]),default:t(()=>[e[8]||(e[8]=s(" 扫过期 ",-1))]),_:1})]),_:1})]),a(ne,{gutter:[16,16],style:{"margin-bottom":"20px"}},{default:t(()=>[a(z,{xs:12,sm:8,lg:4},{default:t(()=>[a(g,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:t(()=>[a(_,{title:"总提案",value:A.value.length,"value-style":{color:"#1677ff",fontSize:"20px"}},{prefix:t(()=>[a(b(he))]),_:1},8,["value"])]),_:1})]),_:1}),a(z,{xs:12,sm:8,lg:4},{default:t(()=>[a(g,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:t(()=>[a(_,{title:"待签",value:$.value.pending,"value-style":{color:"#faad14",fontSize:"20px"}},{prefix:t(()=>[a(b(G))]),_:1},8,["value"])]),_:1})]),_:1}),a(z,{xs:12,sm:8,lg:4},{default:t(()=>[a(g,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:t(()=>[a(_,{title:"已达阈值",value:$.value.reached,"value-style":{color:"#13c2c2",fontSize:"20px"}},{prefix:t(()=>[a(b(Ce))]),_:1},8,["value"])]),_:1})]),_:1}),a(z,{xs:12,sm:8,lg:4},{default:t(()=>[a(g,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:t(()=>[a(_,{title:"已执行",value:$.value.consumed,"value-style":{color:"#52c41a",fontSize:"20px"}},{prefix:t(()=>[a(b(X))]),_:1},8,["value"])]),_:1})]),_:1}),a(z,{xs:12,sm:8,lg:4},{default:t(()=>[a(g,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:t(()=>[a(_,{title:"已取消",value:$.value.cancelled,"value-style":{color:"#8c8c8c",fontSize:"20px"}},{prefix:t(()=>[a(b(ze))]),_:1},8,["value"])]),_:1})]),_:1}),a(z,{xs:12,sm:8,lg:4},{default:t(()=>[a(g,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:t(()=>[a(_,{title:"已过期",value:$.value.expired,"value-style":{color:"#ff4d4f",fontSize:"20px"}},{prefix:t(()=>[a(b(Me))]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),a(de,{activeKey:T.value,"onUpdate:activeKey":e[2]||(e[2]=o=>T.value=o)},{default:t(()=>[a(J,{key:"proposals",tab:"提案列表"},{default:t(()=>[y("div",De,[a(re,{value:I.value,"onUpdate:value":e[0]||(e[0]=o=>I.value=o),size:"small","button-style":"solid"},{default:t(()=>[a(M,{value:""},{default:t(()=>[...e[10]||(e[10]=[s("全部",-1)])]),_:1}),a(M,{value:"pending"},{default:t(()=>[...e[11]||(e[11]=[s("待签",-1)])]),_:1}),a(M,{value:"reached"},{default:t(()=>[...e[12]||(e[12]=[s("已达阈值",-1)])]),_:1}),a(M,{value:"consumed"},{default:t(()=>[...e[13]||(e[13]=[s("已执行",-1)])]),_:1}),a(M,{value:"cancelled"},{default:t(()=>[...e[14]||(e[14]=[s("已取消",-1)])]),_:1}),a(M,{value:"expired"},{default:t(()=>[...e[15]||(e[15]=[s("已过期",-1)])]),_:1})]),_:1},8,["value"]),a(ie,{value:L.value,"onUpdate:value":e[1]||(e[1]=o=>L.value=o),placeholder:"按 domain 过滤 (marketplace.purchase 等)","allow-clear":"",style:{"max-width":"360px","margin-left":"12px"}},null,8,["value"])]),a(q,{columns:ee,"data-source":ae.value,loading:D.value,pagination:{pageSize:20,showSizeChanger:!0,pageSizeOptions:["10","20","50","100"]},"row-key":"id",size:"middle",onRowClick:le,"row-class-name":()=>"multisig-row"},{bodyCell:t(({column:o,record:u})=>[o.key==="id"?(p(),O("code",Ae,r(u.id.slice(0,16))+"…",1)):o.key==="state"?(p(),c(S,{key:1,color:P(u.state)},{default:t(()=>[s(r(u.state),1)]),_:2},1032,["color"])):o.key==="sigs"?(p(),c(S,{key:2,color:u.n===u.m?"cyan":"default"},{default:t(()=>[s(r(u.m)+"/"+r(u.n),1)]),_:2},1032,["color"])):o.key==="createdAt"?(p(),c(U,{key:3,title:new Date(u.createdAtMs).toLocaleString()},{default:t(()=>[s(r(B(u.createdAtMs)),1)]),_:2},1032,["title"])):o.key==="expiresAt"?(p(),c(U,{key:4,title:new Date(u.expiresAtMs).toLocaleString()},{default:t(()=>[y("span",{style:ye({color:u.expiresAtMs<Date.now()?"#ff4d4f":"inherit"})},r(B(u.expiresAtMs)),5)]),_:2},1032,["title"])):o.key==="actions"?(p(),c(f,{key:5,size:"small"},{default:t(()=>[a(d,{size:"small",onClick:F(H=>E(u),["stop"])},{default:t(()=>[...e[16]||(e[16]=[s("详情",-1)])]),_:1},8,["onClick"]),u.state==="pending"||u.state==="reached"?(p(),c(d,{key:0,size:"small",danger:"",onClick:F(H=>R(u),["stop"])},{default:t(()=>[...e[17]||(e[17]=[s("取消",-1)])]),_:1},8,["onClick"])):x("",!0),u.state==="reached"&&u.domain==="marketplace.purchase"?(p(),c(d,{key:1,size:"small",type:"primary",onClick:F(H=>K(u),["stop"])},{default:t(()=>[...e[18]||(e[18]=[s("执行购买",-1)])]),_:1},8,["onClick"])):x("",!0)]),_:2},1024)):x("",!0)]),_:1},8,["data-source","loading"])]),_:1}),a(J,{key:"policies",tab:"域策略"},{default:t(()=>[j.value.length===0?(p(),c(ue,{key:0,description:"暂无域策略 — 用 CLI 配置: cc multisig policy set <domain> --m <M> --members <json>"})):(p(),c(W,{key:1,"data-source":j.value,"item-layout":"vertical"},{renderItem:t(({item:o})=>[a(Q,null,{default:t(()=>[a(g,null,{default:t(()=>[y("h4",Ie,[a(S,{color:"purple"},{default:t(()=>[s(r(o.domain),1)]),_:2},1024),y("span",Le,[s(r(o.policy.m)+"-of-"+r(o.policy.members.length)+" ",1),o.policy.requirePqc?(p(),c(S,{key:0,color:"orange",style:{"margin-left":"8px"}},{default:t(()=>[...e[19]||(e[19]=[s("requirePQC",-1)])]),_:1})):x("",!0)])]),a(V,{size:"small",column:2},{default:t(()=>[a(v,{label:"阈值 M"},{default:t(()=>[s(r(o.policy.m),1)]),_:2},1024),a(v,{label:"成员数 N"},{default:t(()=>[s(r(o.policy.members.length),1)]),_:2},1024),a(v,{label:"算法"},{default:t(()=>[(p(!0),O(ve,null,ge(o.policy.algorithms||[],u=>(p(),c(S,{key:u,size:"small"},{default:t(()=>[s(r(u),1)]),_:2},1024))),128))]),_:2},1024),a(v,{label:"默认有效期"},{default:t(()=>[s(r(Math.round((o.policy.defaultExpiryMs||864e5)/1e3/60/60))+"h ",1)]),_:2},1024)]),_:2},1024),y("details",Oe,[y("summary",je,"展开成员列表 ("+r(o.policy.members.length)+")",1),a(q,{columns:te,"data-source":o.policy.members,pagination:!1,size:"small","row-key":"did",style:{"margin-top":"8px"}},null,8,["data-source"])])]),_:2},1024)]),_:2},1024)]),_:1},8,["data-source"]))]),_:1})]),_:1},8,["activeKey"]),a(fe,{open:h.value,"onUpdate:open":e[6]||(e[6]=o=>h.value=o),title:n.value?`提案 ${n.value.proposal.id}`:"提案详情",width:"640","destroy-on-close":""},{default:t(()=>[n.value?(p(),O("div",Fe,[a(V,{column:1,bordered:"",size:"small"},{default:t(()=>[a(v,{label:"Domain"},{default:t(()=>[s(r(n.value.proposal.domain),1)]),_:1}),a(v,{label:"状态"},{default:t(()=>[a(S,{color:P(n.value.proposal.state)},{default:t(()=>[s(r(n.value.proposal.state),1)]),_:1},8,["color"])]),_:1}),a(v,{label:"阈值"},{default:t(()=>[s(r(n.value.proposal.thresholdM)+"-of-"+r(n.value.proposal.memberSet.length),1)]),_:1}),a(v,{label:"已签 / 需签"},{default:t(()=>[s(r(n.value.signatures.length)+" / "+r(n.value.proposal.thresholdM),1)]),_:1}),a(v,{label:"发起方"},{default:t(()=>[s(r(n.value.proposal.initiatorDid),1)]),_:1}),a(v,{label:"创建时间"},{default:t(()=>[s(r(new Date(n.value.proposal.createdAtMs).toLocaleString()),1)]),_:1}),a(v,{label:"过期时间"},{default:t(()=>[s(r(new Date(n.value.proposal.expiresAtMs).toLocaleString()),1)]),_:1}),a(v,{label:"Payload"},{default:t(()=>[y("pre",Ne,r(n.value.proposal.payload?JSON.stringify(n.value.proposal.payload,null,2):n.value.proposal.payloadJcs),1)]),_:1})]),_:1}),y("h4",Te,"签名列表 ("+r(n.value.signatures.length)+")",1),a(W,{"data-source":n.value.signatures,size:"small"},{renderItem:t(({item:o})=>[a(Q,null,{default:t(()=>[a(pe,null,{title:t(()=>[a(b(X),{style:{color:"#52c41a","margin-right":"6px"}}),y("code",Pe,r(o.signerDid),1)]),description:t(()=>[s(r(o.alg)+" — "+r(new Date(o.signedAtMs).toLocaleString()),1)]),_:2},1024)]),_:2},1024)]),_:1},8,["data-source"]),a(ce),a(me,{message:"签名 / 执行操作需通过 CLI 提供私钥",description:"Web shell 不直接持有私钥(v1.3 接 Unified KeyStore)。本面板用于查看提案状态,操作请用:cc multisig sign / cancel,或 cc marketplace consume。",type:"info","show-icon":"",style:{"margin-bottom":"12px"}}),a(f,null,{default:t(()=>[n.value.proposal.state==="pending"||n.value.proposal.state==="reached"?(p(),c(d,{key:0,danger:"",onClick:e[3]||(e[3]=o=>R(n.value.proposal))},{default:t(()=>[...e[20]||(e[20]=[s("取消提案",-1)])]),_:1})):x("",!0),n.value.proposal.state==="reached"&&n.value.proposal.domain==="marketplace.purchase"?(p(),c(d,{key:1,type:"primary",onClick:e[4]||(e[4]=o=>K(n.value.proposal))},{default:t(()=>[...e[21]||(e[21]=[s("执行购买 (cc marketplace consume)",-1)])]),_:1})):x("",!0),n.value.proposal.state==="reached"&&n.value.proposal.domain!=="marketplace.purchase"?(p(),c(d,{key:2,type:"primary",onClick:e[5]||(e[5]=o=>oe(n.value.proposal))},{default:t(()=>[...e[22]||(e[22]=[s("finalize (cc multisig finalize)",-1)])]),_:1})):x("",!0)]),_:1})])):x("",!0)]),_:1},8,["open","title"])])}}},ct=be(Be,[["__scopeId","data-v-14541f7e"]]);export{ct as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{C as o}from"./Col-DzIUYUNu.js";import{S as t}from"./index-DPzT5L14.js";import"./index-D4rhVRSV.js";import"./vendor-M5lGV-wr.js";import"./icons-NT6gy8Ee.js";const s=t(o);export{s as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as o}from"./Row-8jdU1xYg.js";import{S as t}from"./index-DPzT5L14.js";import"./responsiveObserve-Ch48RA0m.js";import"./vendor-M5lGV-wr.js";import"./useFlexGapSupport-C92oHeXB.js";import"./styleChecker-C1IvuY3L.js";import"./index-D4rhVRSV.js";import"./icons-NT6gy8Ee.js";const l=t(o);export{l as default};
|