chainlesschain 0.166.62 → 0.166.64
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 +54 -8
- package/package.json +3 -1
- package/src/assets/web-panel/assets/{AIOps-BqoRiuXE.js → AIOps-BFbLDWTF.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BwBhyFIm.js → ActionButton-CAHMtgNB.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DTW03Emb.js → Analytics-CkrSj0oR.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CI-wxMLQ.js → AppLayout-BTb0Ws1l.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-DVqbM3iE.js → Artifacts-C2Pgepj-.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DulhOs16.js → Audit-ZweyxXW8.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DnRs67e8.js → BackgroundAgents-BS8tAnzP.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BFEZo0vX.js → Backup-CLkG_74M.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D185sBnp.js → BaseInput-MIfNcdUZ.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DUvP-2SK.js → Chat-DBwqlWWr.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-u9WKQbZb.js → ChatBubbleRenderer-6T0uoJuS.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-D8Zh_18b.js → Checkbox-DdBYhlVX.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-WdiWRdfC.js → Codegen-BR6MhiDo.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CnSoVpw6.js → Col-yO-5EbbM.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BJDHgBkw.js → Community-B608q_m7.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-uNRdmBaq.js → Compact-BmVHi7Z7.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-_6jRTJa3.js → Compliance-BQ-DzutA.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-D5lnbXR6.js → Cowork-BEfLyXvi.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-D6tuGBVg.js → Cron-Cld6NX-_.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Ce5e9Lbm.js → Crosschain-CUA3nDId.js} +1 -1
- package/src/assets/web-panel/assets/{DID-1VVKZ_c1.js → DID-DSI3E9zv.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DuHcZ13w.js → Dashboard-CoWtEdhO.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BC3EK0wN.js → Dropdown-CGhZ1Dyy.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DzLpGs5E.js → EmailListRenderer-BHZe2K5q.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-x2XZHG0Z.js → EvolutionSettings-Corjo98k.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-nAavV50Y.js → FamilyGuardDashboard-dPSWF3Pt.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CCHWVS5J.js → Federation-DT-Zr78c.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CGod_3Ni.js → FormItemContext-CzKq63B0.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DIFYQa2f.js → GenericCardRenderer-CDkKrmu0.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DikM1Nc5.js → Git-BrwRnLOv.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-SzzBXCDX.js → Governance-C4PtCzod.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-wVsu9QzM.js → Inference-CVPv5nwa.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DDpVxfO-.js → KnowledgeGraph-CmT9lvED.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BnIjS-2Z.js → Logs-DaRgv7pL.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-3AsRzie6.js → MarkdownRenderer-B3zZwlSz.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-Cj3PLhXV.js → Marketplace-Bm0GGEaL.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DMKO55Kz.js → McpTools-71L5h0en.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-wWJl5yJL.js → Memory-BoWrfASi.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CJ_VIPgJ.js → MobileBridge-Dp4FcX_-.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CiJT5cF8.js → MobileProjects-00ja0Z7O.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BXmndm9a.js → Mtc-BZF6YNYp.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-C3hWIAnz.js → MtcAudit-Bp_vcI6H.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DU4OUQ7u.js → Multisig-CnCo56CS.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CyAwOeU5.js → NLProgramming-BCSzNHpv.js} +1 -1
- package/src/assets/web-panel/assets/{Notes--YvcAg13.js → Notes-kXoQk8B7.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-Dyu6dC0D.js → NotificationSettings-oN-1fkcy.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Df-0iTO2.js → OrderTableRenderer-5ZVHrVZ9.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-a9Em4Sgu.js → Organization-D4_T9Tdc.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CCQtvcsw.js → Overflow-d8vZwo9w.js} +1 -1
- package/src/assets/web-panel/assets/{P2P--CaB5e38.js → P2P-0HGUdmTv.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CmfHjoJG.js → PdhVaultBrowser-Cx8vp92z.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BCDjNsXi.js → Permissions-XHd6pVQB.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-ByprqCJd.js → PersonalDataHub-CB5bZU9T.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-CZRZq-P0.js → Pipeline-Dy_qx4-0.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CeDay_dV.js → Privacy-BgR0-uEu.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CgpIfRAZ.js → ProjectInit-DAcRi1Nx.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CU8iakEs.js → ProjectSettings-Bd1Q0rK_.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-pPM0KRfQ.js → Projects-DVc9DcbM.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BfpxsZh1.js → Providers-C3c4QfUT.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Dmv3rax1.js → QrScannerModal-Ba_GbitW.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DBOtB5wd.js → QuickAsk-CSn5tIkO.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-C_KnHRvS.js → Recommend-B3-8PLX0.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-OIO9kT7D.js → RemoteSession-Bd_7Zmi-.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BCfNIBt3.js → Reputation-BU2A_wy5.js} +1 -1
- package/src/assets/web-panel/assets/{Row-pnhw7dyj.js → Row-I0JFMjCz.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CLJ1A3FF.js → RssFeed-CNc4Dgfz.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CSQzJ3gj.js → Search-uAA6ceLl.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CS_mvkaE.js → Security-U1SWj5nP.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DBqA2Csq.js → Services-BFjZ5ASY.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BjR3_iWH.js → Skeleton-B8InBvQf.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DwGIXRJS.js → Skills-BDYwf3QV.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DwiHHJtJ.js → Sla-Dcc6iq3q.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-QYN_t0CS.js → SpeechSettings-C3Ta-mC9.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DcXA1Jp3.js → SyncSettings-BNHEYO95.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-JbV6L1FX.js +1 -0
- package/src/assets/web-panel/assets/{Templates-C6MTuLXU.js → Templates-Yp0CUTBz.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DmbdMB2D.js → Tenant-CToNYxCo.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DYeXnE4A.js → Terminal-D7W9UqSD.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BrwLhsSE.js → TimelineRenderer-B7rqc1kE.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-C5kKpRWj.js → Tokens-QP7K4ppA.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-C4Zyg1jj.js → Trigger-CAWowQCR.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-D0mrY3kY.js → Trust-B-0XOP97.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Bq5NMLLb.js → UkeySign-BtiZbiuj.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-OObS6euz.js → VideoEditing-Dee11JI0.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Die77ZAO.js → Wallet-y7qOmaWY.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DFpqn0WO.js → WebAuthn-CjyRRWGK.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-BgKZiece.js → WorkflowEditor-D7Kiz25Q.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CbWtbRmr.js → chat-4F_yB-Gw.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Zu_TgmpG.js → colors-CrczPd-t.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BqABAwA_.js → compact-item-AenPL6fz.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DR6r1ykz.js → createContext-BcwoqPgi.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-C4qWsAvh.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BNnYbjOt.js → hasIn-YouHmap8.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQHn6m4S.js → index--xwN0ZvG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxloCIDQ.js → index-31dhJpt3.js} +1 -1
- package/src/assets/web-panel/assets/{index-CuYLjMxX.js → index-4r7B8sTx.js} +1 -1
- package/src/assets/web-panel/assets/{index-hZ41pakD.js → index-5GHNjmnt.js} +1 -1
- package/src/assets/web-panel/assets/{index--vigBXnN.js → index-B5Vmr0CM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpmSx_mp.js → index-B8EXHVmM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQ1WFS4G.js → index-BHA5Fyjc.js} +1 -1
- package/src/assets/web-panel/assets/{index-ys7--3Ab.js → index-B_I1INkw.js} +1 -1
- package/src/assets/web-panel/assets/{index-CO9hQ7ri.js → index-BaguGDJP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaKziwj_.js → index-BoVeUGhC.js} +1 -1
- package/src/assets/web-panel/assets/{index-DiaPl_6F.js → index-BsGhFk79.js} +1 -1
- package/src/assets/web-panel/assets/{index-DEdqCQKQ.js → index-BwUqDg9_.js} +1 -1
- package/src/assets/web-panel/assets/{index-hWckjvz-.js → index-BzyDSW_e.js} +1 -1
- package/src/assets/web-panel/assets/index-C-ltOW-O.js +1 -0
- package/src/assets/web-panel/assets/{index-P-0rrwu0.js → index-C5hpEYbx.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVgcq0cJ.js → index-CHNKoexH.js} +1 -1
- package/src/assets/web-panel/assets/{index-rS1lj7A9.js → index-COgeZETv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ct4xnx2r.js → index-CWgIKCVS.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYgH1j85.js → index-CZ9Ikuo6.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtQDpNFU.js → index-CZT-LLGS.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9qA3lcI.js → index-CedvtJA_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuCixW1o.js → index-D0dXNgvi.js} +1 -1
- package/src/assets/web-panel/assets/{index-55eCb40A.js → index-D5Rvq67L.js} +3 -3
- package/src/assets/web-panel/assets/index-D7Ir0TiS.js +1 -0
- package/src/assets/web-panel/assets/{index-fvl4dSWm.js → index-D7m5Z4We.js} +1 -1
- package/src/assets/web-panel/assets/{index-D08ytPR_.js → index-D8a1AEVK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbJgVaoQ.js → index-DAGfuEUu.js} +1 -1
- package/src/assets/web-panel/assets/{index-n62j7dTt.js → index-DAh5KwVL.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCyrVLzm.js → index-DE3qPp9l.js} +1 -1
- package/src/assets/web-panel/assets/{index-C912Wlyi.js → index-DNHmbdGm.js} +1 -1
- package/src/assets/web-panel/assets/{index--1t0mcMh.js → index-DPrzFdCg.js} +1 -1
- package/src/assets/web-panel/assets/{index-uwS83tsv.js → index-DVrgnhfu.js} +1 -1
- package/src/assets/web-panel/assets/{index-CR4uB9Mt.js → index-D_4VsL-L.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvQB-LK5.js → index-Dfw3WyZU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbHnxChr.js → index-GP5u18DV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkBDWART.js → index-YX4dcbgh.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSNMSJAt.js → index-fCuM1NPH.js} +1 -1
- package/src/assets/web-panel/assets/{index-GrGT2dft.js → index-gy1H_PJk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmGll9ri.js → index-q_9aqSgF.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BEtGYjIT.js → initDefaultProps-Ci6zc6ZA.js} +1 -1
- package/src/assets/web-panel/assets/{motion-Cvnft4fL.js → motion-DS3kjIxw.js} +1 -1
- package/src/assets/web-panel/assets/{move-CdxE_5Yl.js → move-DCdWAKk4.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CS0l6IJn.js → mtc-parser-B0Wfce9U.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Bnji87sb.js → omit-Clx9TR6z.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BYdnEgN3.js → pickAttrs-CqSiqUvN.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DYYd524z.js → placementArrow-BWe_v-40.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BbIJIkXp.js → responsiveObserve-BSJ68bw6.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BSvuvfUS.js → slide-VRPlLxZB.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DeLSt3js.js → statusUtils-BFBVDPdB.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DpJTPfyI.js → styleChecker-CehOXy1f.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-S7WdFQMU.js → useFlexGapSupport-BCOdfK18.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CkfCBy52.js → useFs-BMKrjfJQ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CA48p8Gt.js → usePersonalDataHub-BIjZ7IgI.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C9D1tq_L.js → vnode-oD0MXddQ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B0TG7YQI.js → zoom-D7WqH2Ai.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +26 -0
- package/src/lib/evolution/evolution-artifact-ports.js +3 -0
- package/src/lib/evolution/evolution-deployment-loader.js +125 -9
- package/src/lib/evolution/pm-exploration-budget-executor.js +346 -0
- package/src/lib/evolution/pm-exploration-business-grader.js +581 -0
- package/src/lib/evolution/pm-exploration-evidence-bundle.js +613 -0
- package/src/lib/evolution/pm-exploration-execution-host.js +946 -0
- package/src/lib/evolution/pm-exploration-ledger-adapter.js +210 -22
- package/src/lib/evolution/pm-exploration-provider-settlement-adapter.js +420 -0
- package/src/lib/evolution/pm-exploration-receipts.js +626 -0
- package/src/lib/evolution/pm-exploration-recovery-snapshot-store.js +521 -0
- package/src/lib/evolution/pm-exploration-rounds.js +12 -2
- package/src/lib/evolution/pm-exploration-transition-committer.js +541 -0
- package/src/lib/evolution/pm-exploration-volcengine-provider.js +724 -0
- package/src/lib/read-file-loop-guard.js +13 -7
- package/src/lib/task-progress-tracker.js +1 -1
- package/src/runtime/agent-core.js +14 -7
- package/src/assets/web-panel/assets/Tasks-DwWqvoyB.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CmMzSuk5.js +0 -1
- package/src/assets/web-panel/assets/index-Dw-oPGSM.js +0 -1
- package/src/assets/web-panel/assets/index-OXemaG8f.js +0 -1
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createHash,
|
|
3
|
+
createPrivateKey,
|
|
4
|
+
createPublicKey,
|
|
5
|
+
sign,
|
|
6
|
+
verify,
|
|
7
|
+
} from "node:crypto";
|
|
8
|
+
import { isKeyObject, isProxy } from "node:util/types";
|
|
9
|
+
|
|
10
|
+
export const PM_EXPLORATION_EXECUTION_RECEIPT_SCHEMA =
|
|
11
|
+
"chainlesschain.pm-exploration-execution-receipt/v1";
|
|
12
|
+
export const PM_EXPLORATION_GRADER_RECEIPT_SCHEMA =
|
|
13
|
+
"chainlesschain.pm-exploration-grader-receipt/v1";
|
|
14
|
+
export const PM_EXPLORATION_MERGE_RECEIPT_SCHEMA =
|
|
15
|
+
"chainlesschain.pm-exploration-merge-receipt/v1";
|
|
16
|
+
export const PM_EXPLORATION_EVALUATOR_RECEIPT_SCHEMA =
|
|
17
|
+
"chainlesschain.pm-exploration-evaluator-receipt/v1";
|
|
18
|
+
|
|
19
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
20
|
+
const ID = /^[a-z][a-z0-9]*(?:[._:@/-][a-z0-9]+)*$/u;
|
|
21
|
+
const ROLES = Object.freeze({
|
|
22
|
+
execution: PM_EXPLORATION_EXECUTION_RECEIPT_SCHEMA,
|
|
23
|
+
grader: PM_EXPLORATION_GRADER_RECEIPT_SCHEMA,
|
|
24
|
+
merge: PM_EXPLORATION_MERGE_RECEIPT_SCHEMA,
|
|
25
|
+
evaluator: PM_EXPLORATION_EVALUATOR_RECEIPT_SCHEMA,
|
|
26
|
+
});
|
|
27
|
+
const AUTHORITIES = new WeakMap();
|
|
28
|
+
const SIGNERS = new WeakMap();
|
|
29
|
+
|
|
30
|
+
function canonical(value) {
|
|
31
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
32
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
33
|
+
return `{${Object.keys(value)
|
|
34
|
+
.sort()
|
|
35
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
36
|
+
.join(",")}}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function hash(domain, value) {
|
|
40
|
+
return `sha256:${createHash("sha256")
|
|
41
|
+
.update(domain)
|
|
42
|
+
.update("\0")
|
|
43
|
+
.update(canonical(value))
|
|
44
|
+
.digest("hex")}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function deepFreeze(value, seen = new WeakSet()) {
|
|
48
|
+
if (!value || typeof value !== "object" || seen.has(value)) return value;
|
|
49
|
+
seen.add(value);
|
|
50
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
51
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
52
|
+
if (descriptor && "value" in descriptor) deepFreeze(descriptor.value, seen);
|
|
53
|
+
}
|
|
54
|
+
return Object.freeze(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function exact(value, keys, label) {
|
|
58
|
+
if (
|
|
59
|
+
!value ||
|
|
60
|
+
typeof value !== "object" ||
|
|
61
|
+
Array.isArray(value) ||
|
|
62
|
+
isProxy(value) ||
|
|
63
|
+
Object.getPrototypeOf(value) !== Object.prototype
|
|
64
|
+
) {
|
|
65
|
+
throw new TypeError(`${label} must be a plain object`);
|
|
66
|
+
}
|
|
67
|
+
const actual = Reflect.ownKeys(value);
|
|
68
|
+
if (
|
|
69
|
+
actual.length !== keys.length ||
|
|
70
|
+
actual.some((key) => {
|
|
71
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
72
|
+
return (
|
|
73
|
+
typeof key !== "string" ||
|
|
74
|
+
!keys.includes(key) ||
|
|
75
|
+
!descriptor ||
|
|
76
|
+
!descriptor.enumerable ||
|
|
77
|
+
!("value" in descriptor)
|
|
78
|
+
);
|
|
79
|
+
})
|
|
80
|
+
) {
|
|
81
|
+
throw new TypeError(`${label} has unexpected or accessor fields`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function identifier(value, label) {
|
|
86
|
+
if (typeof value !== "string" || value.length > 256 || !ID.test(value))
|
|
87
|
+
throw new TypeError(`${label} is invalid`);
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function digest(value, label) {
|
|
92
|
+
if (typeof value !== "string" || !DIGEST.test(value))
|
|
93
|
+
throw new TypeError(`${label} must be a sha256 digest`);
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function integer(value, label, minimum = 0, maximum = Number.MAX_SAFE_INTEGER) {
|
|
98
|
+
if (!Number.isSafeInteger(value) || value < minimum || value > maximum)
|
|
99
|
+
throw new TypeError(`${label} is outside its allowed range`);
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function role(value) {
|
|
104
|
+
if (typeof value !== "string" || !Object.hasOwn(ROLES, value))
|
|
105
|
+
throw new TypeError("PM exploration receipt role is invalid");
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function issuedAt(value) {
|
|
110
|
+
if (
|
|
111
|
+
typeof value !== "string" ||
|
|
112
|
+
!Number.isFinite(Date.parse(value)) ||
|
|
113
|
+
new Date(value).toISOString() !== value
|
|
114
|
+
) {
|
|
115
|
+
throw new TypeError("receipt issuedAt must be an ISO timestamp");
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function metrics(value, label) {
|
|
121
|
+
exact(value, ["tokens", "toolCalls", "wallClockMs"], label);
|
|
122
|
+
return Object.freeze({
|
|
123
|
+
tokens: integer(value.tokens, `${label}.tokens`),
|
|
124
|
+
toolCalls: integer(value.toolCalls, `${label}.toolCalls`),
|
|
125
|
+
wallClockMs: integer(value.wallClockMs, `${label}.wallClockMs`),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function branchCheckpoints(value) {
|
|
130
|
+
if (
|
|
131
|
+
!Array.isArray(value) ||
|
|
132
|
+
isProxy(value) ||
|
|
133
|
+
Object.getPrototypeOf(value) !== Array.prototype ||
|
|
134
|
+
value.length < 1 ||
|
|
135
|
+
value.length > 8 ||
|
|
136
|
+
Reflect.ownKeys(value).length !== value.length + 1
|
|
137
|
+
) {
|
|
138
|
+
throw new TypeError("merge branchCheckpoints are invalid");
|
|
139
|
+
}
|
|
140
|
+
const seen = new Set();
|
|
141
|
+
return Object.freeze(
|
|
142
|
+
value.map((entry, index) => {
|
|
143
|
+
if (!Object.hasOwn(value, index))
|
|
144
|
+
throw new TypeError("merge branchCheckpoints cannot contain holes");
|
|
145
|
+
exact(
|
|
146
|
+
entry,
|
|
147
|
+
["branchId", "checkpointDigest", "memoryDigest"],
|
|
148
|
+
`merge branch checkpoint ${index}`,
|
|
149
|
+
);
|
|
150
|
+
const normalized = Object.freeze({
|
|
151
|
+
branchId: identifier(entry.branchId, "merge branchId"),
|
|
152
|
+
checkpointDigest: digest(
|
|
153
|
+
entry.checkpointDigest,
|
|
154
|
+
"merge checkpointDigest",
|
|
155
|
+
),
|
|
156
|
+
memoryDigest: digest(entry.memoryDigest, "merge memoryDigest"),
|
|
157
|
+
});
|
|
158
|
+
if (seen.has(normalized.branchId))
|
|
159
|
+
throw new TypeError("merge branchCheckpoints must be unique");
|
|
160
|
+
seen.add(normalized.branchId);
|
|
161
|
+
return normalized;
|
|
162
|
+
}),
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function normalizeExecutionPayload(value) {
|
|
167
|
+
exact(
|
|
168
|
+
value,
|
|
169
|
+
[
|
|
170
|
+
"planDigest",
|
|
171
|
+
"environmentDigest",
|
|
172
|
+
"requestDigest",
|
|
173
|
+
"roundId",
|
|
174
|
+
"stage",
|
|
175
|
+
"branchId",
|
|
176
|
+
"taskId",
|
|
177
|
+
"inputMemoryDigest",
|
|
178
|
+
"outputMemoryDigest",
|
|
179
|
+
"traceDigest",
|
|
180
|
+
"status",
|
|
181
|
+
"failureClass",
|
|
182
|
+
"metrics",
|
|
183
|
+
"issuedAt",
|
|
184
|
+
],
|
|
185
|
+
"execution receipt payload",
|
|
186
|
+
);
|
|
187
|
+
if (!["broad", "deep"].includes(value.stage))
|
|
188
|
+
throw new TypeError("execution receipt stage is invalid");
|
|
189
|
+
if (value.stage === "broad") identifier(value.branchId, "branchId");
|
|
190
|
+
else if (value.branchId !== null)
|
|
191
|
+
throw new TypeError("Deep execution receipts cannot name a branch");
|
|
192
|
+
if (!["succeeded", "failed", "aborted"].includes(value.status))
|
|
193
|
+
throw new TypeError("execution receipt status is invalid");
|
|
194
|
+
if (
|
|
195
|
+
![
|
|
196
|
+
"none",
|
|
197
|
+
"model",
|
|
198
|
+
"tool",
|
|
199
|
+
"provider",
|
|
200
|
+
"sandbox",
|
|
201
|
+
"permission",
|
|
202
|
+
"budget",
|
|
203
|
+
"infrastructure",
|
|
204
|
+
"unknown",
|
|
205
|
+
].includes(value.failureClass)
|
|
206
|
+
) {
|
|
207
|
+
throw new TypeError("execution receipt failureClass is invalid");
|
|
208
|
+
}
|
|
209
|
+
if (
|
|
210
|
+
(value.status === "succeeded" && value.failureClass !== "none") ||
|
|
211
|
+
(value.status !== "succeeded" && value.failureClass === "none")
|
|
212
|
+
) {
|
|
213
|
+
throw new TypeError("execution receipt status and failureClass disagree");
|
|
214
|
+
}
|
|
215
|
+
return deepFreeze({
|
|
216
|
+
planDigest: digest(value.planDigest, "planDigest"),
|
|
217
|
+
environmentDigest: digest(value.environmentDigest, "environmentDigest"),
|
|
218
|
+
requestDigest: digest(value.requestDigest, "requestDigest"),
|
|
219
|
+
roundId: identifier(value.roundId, "roundId"),
|
|
220
|
+
stage: value.stage,
|
|
221
|
+
branchId: value.branchId,
|
|
222
|
+
taskId: identifier(value.taskId, "taskId"),
|
|
223
|
+
inputMemoryDigest: digest(value.inputMemoryDigest, "inputMemoryDigest"),
|
|
224
|
+
outputMemoryDigest: digest(value.outputMemoryDigest, "outputMemoryDigest"),
|
|
225
|
+
traceDigest: digest(value.traceDigest, "traceDigest"),
|
|
226
|
+
status: value.status,
|
|
227
|
+
failureClass: value.failureClass,
|
|
228
|
+
metrics: metrics(value.metrics, "execution metrics"),
|
|
229
|
+
issuedAt: issuedAt(value.issuedAt),
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function normalizeGraderPayload(value) {
|
|
234
|
+
exact(
|
|
235
|
+
value,
|
|
236
|
+
[
|
|
237
|
+
"planDigest",
|
|
238
|
+
"environmentDigest",
|
|
239
|
+
"requestDigest",
|
|
240
|
+
"roundId",
|
|
241
|
+
"executionReceiptDigest",
|
|
242
|
+
"outputMemoryDigest",
|
|
243
|
+
"decision",
|
|
244
|
+
"scoreBasisPoints",
|
|
245
|
+
"resultDigest",
|
|
246
|
+
"metrics",
|
|
247
|
+
"issuedAt",
|
|
248
|
+
],
|
|
249
|
+
"grader receipt payload",
|
|
250
|
+
);
|
|
251
|
+
if (!["accept", "reject", "unsafe"].includes(value.decision))
|
|
252
|
+
throw new TypeError("grader receipt decision is invalid");
|
|
253
|
+
return deepFreeze({
|
|
254
|
+
planDigest: digest(value.planDigest, "planDigest"),
|
|
255
|
+
environmentDigest: digest(value.environmentDigest, "environmentDigest"),
|
|
256
|
+
requestDigest: digest(value.requestDigest, "requestDigest"),
|
|
257
|
+
roundId: identifier(value.roundId, "roundId"),
|
|
258
|
+
executionReceiptDigest: digest(
|
|
259
|
+
value.executionReceiptDigest,
|
|
260
|
+
"executionReceiptDigest",
|
|
261
|
+
),
|
|
262
|
+
outputMemoryDigest: digest(value.outputMemoryDigest, "outputMemoryDigest"),
|
|
263
|
+
decision: value.decision,
|
|
264
|
+
scoreBasisPoints: integer(
|
|
265
|
+
value.scoreBasisPoints,
|
|
266
|
+
"scoreBasisPoints",
|
|
267
|
+
0,
|
|
268
|
+
10_000,
|
|
269
|
+
),
|
|
270
|
+
resultDigest: digest(value.resultDigest, "resultDigest"),
|
|
271
|
+
metrics: metrics(value.metrics, "grader metrics"),
|
|
272
|
+
issuedAt: issuedAt(value.issuedAt),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function normalizeMergePayload(value) {
|
|
277
|
+
exact(
|
|
278
|
+
value,
|
|
279
|
+
[
|
|
280
|
+
"planDigest",
|
|
281
|
+
"environmentDigest",
|
|
282
|
+
"requestDigest",
|
|
283
|
+
"mergeId",
|
|
284
|
+
"branchCheckpoints",
|
|
285
|
+
"outputMemoryDigest",
|
|
286
|
+
"conflictResolutionDigest",
|
|
287
|
+
"status",
|
|
288
|
+
"failureClass",
|
|
289
|
+
"metrics",
|
|
290
|
+
"issuedAt",
|
|
291
|
+
],
|
|
292
|
+
"merge receipt payload",
|
|
293
|
+
);
|
|
294
|
+
if (!["succeeded", "failed", "aborted"].includes(value.status))
|
|
295
|
+
throw new TypeError("merge receipt status is invalid");
|
|
296
|
+
if (
|
|
297
|
+
!["none", "budget", "infrastructure", "unknown"].includes(
|
|
298
|
+
value.failureClass,
|
|
299
|
+
)
|
|
300
|
+
) {
|
|
301
|
+
throw new TypeError("merge receipt failureClass is invalid");
|
|
302
|
+
}
|
|
303
|
+
if (
|
|
304
|
+
(value.status === "succeeded" && value.failureClass !== "none") ||
|
|
305
|
+
(value.status !== "succeeded" && value.failureClass === "none")
|
|
306
|
+
) {
|
|
307
|
+
throw new TypeError("merge receipt status and failureClass disagree");
|
|
308
|
+
}
|
|
309
|
+
return deepFreeze({
|
|
310
|
+
planDigest: digest(value.planDigest, "planDigest"),
|
|
311
|
+
environmentDigest: digest(value.environmentDigest, "environmentDigest"),
|
|
312
|
+
requestDigest: digest(value.requestDigest, "requestDigest"),
|
|
313
|
+
mergeId: identifier(value.mergeId, "mergeId"),
|
|
314
|
+
branchCheckpoints: branchCheckpoints(value.branchCheckpoints),
|
|
315
|
+
outputMemoryDigest: digest(value.outputMemoryDigest, "outputMemoryDigest"),
|
|
316
|
+
conflictResolutionDigest: digest(
|
|
317
|
+
value.conflictResolutionDigest,
|
|
318
|
+
"conflictResolutionDigest",
|
|
319
|
+
),
|
|
320
|
+
status: value.status,
|
|
321
|
+
failureClass: value.failureClass,
|
|
322
|
+
metrics: metrics(value.metrics, "merge metrics"),
|
|
323
|
+
issuedAt: issuedAt(value.issuedAt),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function normalizeEvaluatorPayload(value) {
|
|
328
|
+
exact(
|
|
329
|
+
value,
|
|
330
|
+
[
|
|
331
|
+
"planDigest",
|
|
332
|
+
"environmentDigest",
|
|
333
|
+
"requestDigest",
|
|
334
|
+
"mergeReceiptDigest",
|
|
335
|
+
"finalCheckpointDigest",
|
|
336
|
+
"finalMemoryDigest",
|
|
337
|
+
"decision",
|
|
338
|
+
"scoreBasisPoints",
|
|
339
|
+
"evaluationDigest",
|
|
340
|
+
"metrics",
|
|
341
|
+
"issuedAt",
|
|
342
|
+
],
|
|
343
|
+
"evaluator receipt payload",
|
|
344
|
+
);
|
|
345
|
+
if (!["accept", "reject", "unsafe"].includes(value.decision))
|
|
346
|
+
throw new TypeError("evaluator receipt decision is invalid");
|
|
347
|
+
return deepFreeze({
|
|
348
|
+
planDigest: digest(value.planDigest, "planDigest"),
|
|
349
|
+
environmentDigest: digest(value.environmentDigest, "environmentDigest"),
|
|
350
|
+
requestDigest: digest(value.requestDigest, "requestDigest"),
|
|
351
|
+
mergeReceiptDigest: digest(value.mergeReceiptDigest, "mergeReceiptDigest"),
|
|
352
|
+
finalCheckpointDigest: digest(
|
|
353
|
+
value.finalCheckpointDigest,
|
|
354
|
+
"finalCheckpointDigest",
|
|
355
|
+
),
|
|
356
|
+
finalMemoryDigest: digest(value.finalMemoryDigest, "finalMemoryDigest"),
|
|
357
|
+
decision: value.decision,
|
|
358
|
+
scoreBasisPoints: integer(
|
|
359
|
+
value.scoreBasisPoints,
|
|
360
|
+
"scoreBasisPoints",
|
|
361
|
+
0,
|
|
362
|
+
10_000,
|
|
363
|
+
),
|
|
364
|
+
evaluationDigest: digest(value.evaluationDigest, "evaluationDigest"),
|
|
365
|
+
metrics: metrics(value.metrics, "evaluator metrics"),
|
|
366
|
+
issuedAt: issuedAt(value.issuedAt),
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function normalizePayload(receiptRole, value) {
|
|
371
|
+
if (receiptRole === "execution") return normalizeExecutionPayload(value);
|
|
372
|
+
if (receiptRole === "grader") return normalizeGraderPayload(value);
|
|
373
|
+
if (receiptRole === "merge") return normalizeMergePayload(value);
|
|
374
|
+
return normalizeEvaluatorPayload(value);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function publicKey(value) {
|
|
378
|
+
let key;
|
|
379
|
+
try {
|
|
380
|
+
key = isKeyObject(value) ? value : createPublicKey(value);
|
|
381
|
+
} catch (cause) {
|
|
382
|
+
throw new TypeError("PM exploration receipt publicKey is invalid", {
|
|
383
|
+
cause,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
if (key.type !== "public" || key.asymmetricKeyType !== "ed25519")
|
|
387
|
+
throw new TypeError("PM exploration receipt publicKey must be Ed25519");
|
|
388
|
+
return key;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function privateKey(value) {
|
|
392
|
+
let key;
|
|
393
|
+
try {
|
|
394
|
+
key = isKeyObject(value) ? value : createPrivateKey(value);
|
|
395
|
+
} catch (cause) {
|
|
396
|
+
throw new TypeError("PM exploration receipt privateKey is invalid", {
|
|
397
|
+
cause,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
if (key.type !== "private" || key.asymmetricKeyType !== "ed25519")
|
|
401
|
+
throw new TypeError("PM exploration receipt privateKey must be Ed25519");
|
|
402
|
+
return key;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function keyDigest(key) {
|
|
406
|
+
return `sha256:${createHash("sha256")
|
|
407
|
+
.update(key.export({ format: "der", type: "spki" }))
|
|
408
|
+
.digest("hex")}`;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function descriptor(input, key) {
|
|
412
|
+
exact(
|
|
413
|
+
input,
|
|
414
|
+
["role", "authorityId", "revision", "handlerArtifactDigest"],
|
|
415
|
+
"PM exploration receipt authority descriptor",
|
|
416
|
+
);
|
|
417
|
+
return deepFreeze({
|
|
418
|
+
role: role(input.role),
|
|
419
|
+
authorityId: identifier(input.authorityId, "authorityId"),
|
|
420
|
+
revision: integer(input.revision, "revision", 1),
|
|
421
|
+
handlerArtifactDigest: digest(
|
|
422
|
+
input.handlerArtifactDigest,
|
|
423
|
+
"handlerArtifactDigest",
|
|
424
|
+
),
|
|
425
|
+
publicKeyDigest: keyDigest(key),
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export function createPmExplorationReceiptAuthority(options = {}) {
|
|
430
|
+
exact(
|
|
431
|
+
options,
|
|
432
|
+
["role", "authorityId", "revision", "handlerArtifactDigest", "publicKey"],
|
|
433
|
+
"PM exploration receipt authority options",
|
|
434
|
+
);
|
|
435
|
+
const key = publicKey(options.publicKey);
|
|
436
|
+
const authority = Object.freeze({});
|
|
437
|
+
AUTHORITIES.set(authority, {
|
|
438
|
+
descriptor: descriptor(
|
|
439
|
+
{
|
|
440
|
+
role: options.role,
|
|
441
|
+
authorityId: options.authorityId,
|
|
442
|
+
revision: options.revision,
|
|
443
|
+
handlerArtifactDigest: options.handlerArtifactDigest,
|
|
444
|
+
},
|
|
445
|
+
key,
|
|
446
|
+
),
|
|
447
|
+
publicKey: key,
|
|
448
|
+
});
|
|
449
|
+
return authority;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export function createPmExplorationReceiptSigner(options = {}) {
|
|
453
|
+
exact(
|
|
454
|
+
options,
|
|
455
|
+
[
|
|
456
|
+
"role",
|
|
457
|
+
"authorityId",
|
|
458
|
+
"revision",
|
|
459
|
+
"handlerArtifactDigest",
|
|
460
|
+
"privateKey",
|
|
461
|
+
"publicKey",
|
|
462
|
+
],
|
|
463
|
+
"PM exploration receipt signer options",
|
|
464
|
+
);
|
|
465
|
+
const signingKey = privateKey(options.privateKey);
|
|
466
|
+
const verificationKey = publicKey(options.publicKey);
|
|
467
|
+
if (keyDigest(createPublicKey(signingKey)) !== keyDigest(verificationKey))
|
|
468
|
+
throw new TypeError("PM exploration receipt key pair does not match");
|
|
469
|
+
const authority = createPmExplorationReceiptAuthority({
|
|
470
|
+
role: options.role,
|
|
471
|
+
authorityId: options.authorityId,
|
|
472
|
+
revision: options.revision,
|
|
473
|
+
handlerArtifactDigest: options.handlerArtifactDigest,
|
|
474
|
+
publicKey: verificationKey,
|
|
475
|
+
});
|
|
476
|
+
const signer = Object.freeze({});
|
|
477
|
+
SIGNERS.set(signer, { authority, privateKey: signingKey });
|
|
478
|
+
return signer;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export function inspectPmExplorationReceiptAuthority(value) {
|
|
482
|
+
const signer = SIGNERS.get(value);
|
|
483
|
+
const binding = signer
|
|
484
|
+
? AUTHORITIES.get(signer.authority)
|
|
485
|
+
: AUTHORITIES.get(value);
|
|
486
|
+
if (!binding)
|
|
487
|
+
throw new TypeError(
|
|
488
|
+
"a branded PM exploration receipt authority is required",
|
|
489
|
+
);
|
|
490
|
+
return binding.descriptor;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export function getPmExplorationReceiptSignerAuthority(value) {
|
|
494
|
+
const binding = SIGNERS.get(value);
|
|
495
|
+
if (!binding)
|
|
496
|
+
throw new TypeError("a branded PM exploration receipt signer is required");
|
|
497
|
+
return binding.authority;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
export function issuePmExplorationReceipt(signer, payloadInput) {
|
|
501
|
+
const signing = SIGNERS.get(signer);
|
|
502
|
+
if (!signing)
|
|
503
|
+
throw new TypeError("a branded PM exploration receipt signer is required");
|
|
504
|
+
const authority = AUTHORITIES.get(signing.authority);
|
|
505
|
+
const receiptRole = authority.descriptor.role;
|
|
506
|
+
const payload = normalizePayload(receiptRole, payloadInput);
|
|
507
|
+
const core = deepFreeze({
|
|
508
|
+
schema: ROLES[receiptRole],
|
|
509
|
+
role: receiptRole,
|
|
510
|
+
authenticated: true,
|
|
511
|
+
authority: authority.descriptor,
|
|
512
|
+
payload,
|
|
513
|
+
});
|
|
514
|
+
const receiptDigest = hash(ROLES[receiptRole], core);
|
|
515
|
+
const signature = sign(
|
|
516
|
+
null,
|
|
517
|
+
Buffer.from(`${ROLES[receiptRole]}\0${receiptDigest}`, "utf8"),
|
|
518
|
+
signing.privateKey,
|
|
519
|
+
).toString("base64url");
|
|
520
|
+
return deepFreeze({ ...core, receiptDigest, signature });
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function signatureBytes(value) {
|
|
524
|
+
if (typeof value !== "string" || value.length > 256)
|
|
525
|
+
throw new TypeError("PM exploration receipt signature is invalid");
|
|
526
|
+
const bytes = Buffer.from(value, "base64url");
|
|
527
|
+
if (bytes.length !== 64 || bytes.toString("base64url") !== value)
|
|
528
|
+
throw new TypeError("PM exploration receipt signature is invalid");
|
|
529
|
+
return bytes;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function expectedPayload(value) {
|
|
533
|
+
if (value === undefined) return null;
|
|
534
|
+
if (
|
|
535
|
+
!value ||
|
|
536
|
+
typeof value !== "object" ||
|
|
537
|
+
Array.isArray(value) ||
|
|
538
|
+
isProxy(value) ||
|
|
539
|
+
Object.getPrototypeOf(value) !== Object.prototype
|
|
540
|
+
) {
|
|
541
|
+
throw new TypeError("expected receipt payload bindings must be plain data");
|
|
542
|
+
}
|
|
543
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
544
|
+
const field = Object.getOwnPropertyDescriptor(value, key);
|
|
545
|
+
if (
|
|
546
|
+
typeof key !== "string" ||
|
|
547
|
+
!field ||
|
|
548
|
+
!field.enumerable ||
|
|
549
|
+
!("value" in field)
|
|
550
|
+
) {
|
|
551
|
+
throw new TypeError("expected receipt payload bindings are invalid");
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return value;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
export function verifyPmExplorationReceipt(
|
|
558
|
+
authorityValue,
|
|
559
|
+
value,
|
|
560
|
+
expectedInput,
|
|
561
|
+
) {
|
|
562
|
+
const authority = AUTHORITIES.get(authorityValue);
|
|
563
|
+
if (!authority)
|
|
564
|
+
throw new TypeError(
|
|
565
|
+
"a branded PM exploration receipt authority is required",
|
|
566
|
+
);
|
|
567
|
+
exact(
|
|
568
|
+
value,
|
|
569
|
+
[
|
|
570
|
+
"schema",
|
|
571
|
+
"role",
|
|
572
|
+
"authenticated",
|
|
573
|
+
"authority",
|
|
574
|
+
"payload",
|
|
575
|
+
"receiptDigest",
|
|
576
|
+
"signature",
|
|
577
|
+
],
|
|
578
|
+
"PM exploration receipt",
|
|
579
|
+
);
|
|
580
|
+
const receiptRole = authority.descriptor.role;
|
|
581
|
+
if (
|
|
582
|
+
value.schema !== ROLES[receiptRole] ||
|
|
583
|
+
value.role !== receiptRole ||
|
|
584
|
+
value.authenticated !== true ||
|
|
585
|
+
canonical(value.authority) !== canonical(authority.descriptor)
|
|
586
|
+
) {
|
|
587
|
+
throw new Error("PM exploration receipt authority binding mismatch");
|
|
588
|
+
}
|
|
589
|
+
const payload = normalizePayload(receiptRole, value.payload);
|
|
590
|
+
const core = deepFreeze({
|
|
591
|
+
schema: value.schema,
|
|
592
|
+
role: value.role,
|
|
593
|
+
authenticated: true,
|
|
594
|
+
authority: authority.descriptor,
|
|
595
|
+
payload,
|
|
596
|
+
});
|
|
597
|
+
const receiptDigest = hash(value.schema, core);
|
|
598
|
+
if (value.receiptDigest !== receiptDigest)
|
|
599
|
+
throw new Error("PM exploration receipt digest mismatch");
|
|
600
|
+
if (
|
|
601
|
+
!verify(
|
|
602
|
+
null,
|
|
603
|
+
Buffer.from(`${value.schema}\0${receiptDigest}`, "utf8"),
|
|
604
|
+
authority.publicKey,
|
|
605
|
+
signatureBytes(value.signature),
|
|
606
|
+
)
|
|
607
|
+
) {
|
|
608
|
+
throw new Error("PM exploration receipt signature rejected");
|
|
609
|
+
}
|
|
610
|
+
const expected = expectedPayload(expectedInput);
|
|
611
|
+
if (expected) {
|
|
612
|
+
for (const key of Object.keys(expected)) {
|
|
613
|
+
if (
|
|
614
|
+
!Object.hasOwn(payload, key) ||
|
|
615
|
+
canonical(payload[key]) !== canonical(expected[key])
|
|
616
|
+
) {
|
|
617
|
+
throw new Error(`PM exploration receipt ${key} binding mismatch`);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return deepFreeze({ ...core, receiptDigest, signature: value.signature });
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
export function computePmExplorationReceiptDigest(domain, value) {
|
|
625
|
+
return hash(domain, value);
|
|
626
|
+
}
|