chainlesschain 0.166.38 → 0.166.39
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 +6 -1
- package/scripts/governed-learning-local-attestor-service.mjs +222 -0
- package/scripts/governed-learning-local-attestor-trust-approval-service.mjs +338 -0
- package/scripts/governed-learning-local-attestor-trust-operations-service.mjs +575 -0
- package/scripts/governed-learning-windows-secure-pipe-broker.ps1 +375 -0
- package/src/assets/web-panel/assets/{AIOps-DBbcVPqB.js → AIOps-qWUdiFr5.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-D5vETPOk.js → ActionButton-B_f7go3E.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-WVhas3Fw.js → Analytics-hSGFlSkB.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CSTRI93Q.js → AppLayout-CCYGgj71.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BZT8FOoE.js → Artifacts-BdS1H9gq.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CT2-Tsby.js → Audit-Cck9IebC.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BWA5LNBe.js → BackgroundAgents-DZzoM_QS.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-B-zEbldA.js → Backup-D8H_QtGu.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BAEwtdNT.js → BaseInput-CTsNF_pu.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BT1-y6t1.js → Chat-CcEiTYY8.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BVijMHeO.js → ChatBubbleRenderer-9BY1DPuc.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B8IJYZsD.js → Checkbox-BPB9NNJx.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DEt453nL.js → Codegen-CKKMf7jD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DWuVSmZv.js → Col-DpSSB4Uu.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CcoNuU33.js → Community-CfR6ikoH.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BKtuIYWA.js → Compact-CqnkGGjK.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-bHzxGq3P.js → Compliance-9IzhdVQb.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BY2Kb15t.js → Cowork-eXsgH33N.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-DC-j0jvp.js → Cron-DvkzHFRi.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CzEuAHQz.js → Crosschain--az9d9f7.js} +1 -1
- package/src/assets/web-panel/assets/{DID-7QUNq6Fz.js → DID-_Eb4kpnJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CT6RiEFl.js → Dashboard-aDVisdXj.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CW8IPY7r.js → Dropdown-oQ54XzS9.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Zt8WOLuN.js → EmailListRenderer-BUPdMau1.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-B6aymxi7.js → FamilyGuardDashboard-DtQTOCQI.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BiuFrRq0.js → Federation-Cpnb3Moe.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DaiOAkHa.js → FormItemContext-DmsrJkeU.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-D1KbDpXs.js → GenericCardRenderer-CpFDYnh3.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BILl0huA.js → Git-HFG17p7Q.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CLyhrPrh.js → Governance-D5Z5c7N8.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DyNhiIpK.js → Inference-DH159h74.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Bor_ye4m.js → KnowledgeGraph-DuL1pcJD.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-ZDqbu8kg.js → Logs-Gqn8hFsM.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-NHJaejHI.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-DbDi29dH.js → Marketplace-BArcWifg.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DfU8dWbV.js → McpTools-Q1BfBSnd.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-DeAz-2-6.js → Memory-Cz8nRL7N.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-ws3TJXal.js → MobileBridge-CRuxLRJw.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CGwVfeTv.js → MobileProjects-B1CQIAGp.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BtJjJJpl.js → Mtc-CFhXZbPk.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BNZwipXs.js → MtcAudit-C69LqcZ5.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-9mSOrKWA.js → Multisig-y7yZeTTG.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-gz1lEDED.js → NLProgramming-DgjhoWea.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BeufuOVX.js → Notes-DRc2WTDh.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CbFyi9jZ.js → NotificationSettings-CLPx24yn.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CMSNA4CO.js +1 -0
- package/src/assets/web-panel/assets/{Organization-DKBKNViH.js → Organization-Dm6LIyhZ.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-CvPfKE1x.js → Overflow-DP4DOYd-.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DjL2q8og.js → P2P-HFwvtFI1.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-D9gPfKRM.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-BUoNho3w.js → Permissions-Bdtxniwh.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-C4Iu2Pic.js → PersonalDataHub-Dgl2AbES.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-BiDrIlwr.js → Pipeline-DpZrzYwK.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BnvU6vGp.js → Privacy-EQ551c0t.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DDzoyhnH.js → ProjectInit-xUSeczsM.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CV6b43H0.js → ProjectSettings-B66Sr_t8.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-B0k1907g.js → Projects-B4zikj95.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DaeuFo-x.js → Providers-DjLbqQPh.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-C03Bll1h.js → QrScannerModal-KVsAQCd_.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Cn9nLaen.js → QuickAsk-C4noJXu8.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BXfkC8Ts.js → Recommend-Cn15clqY.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DNj6D_LI.js → RemoteSession-DdonMFwH.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-DDDIwiUI.js → Reputation-Bqe3NwWN.js} +1 -1
- package/src/assets/web-panel/assets/{Row-JukNm-id.js → Row-CnxBgjkD.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B1AhzL2z.js → RssFeed-CSRrgZyK.js} +2 -2
- package/src/assets/web-panel/assets/{Search-B5y6_DVm.js → Search-DTUYUfFx.js} +1 -1
- package/src/assets/web-panel/assets/{Security-C2pvv32x.js → Security-BHExHVIm.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DBka7ppY.js → Services-B_IWqPes.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DfPwNTSh.js → Skeleton-C_oAtzmX.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Cs4ntp-l.js → Skills-maJNokSL.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CrUJ0guM.js → Sla-CMM_ZsLH.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BFbokLV1.js → SpeechSettings-D7w_oNwK.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CSnh1o3D.js → SyncSettings-D0Zl3NIr.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CQZppIPo.js → Tasks-Bs0H0ctR.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BqLeHq7Z.js → Templates-C6T6oCpR.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CkzPA-ri.js → Tenant-ByL-kAYO.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D5IRhnu6.js → Terminal-6JXNhc3b.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-ICdiYzgz.js → TimelineRenderer-KiuUtCsl.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-89CaZBwe.js → Tokens-C0TWTIER.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Di251qR1.js → Trigger-DpC5aaJu.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-M4sC3Mv6.js → Trust-lqqflCwv.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BL7EUWxj.js → UkeySign-BYSlVfBc.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BV5Se5il.js → VideoEditing-DX08oo_R.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-IoY13rov.js → Wallet-CcIFPvzL.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DKFPq0uV.js → WebAuthn-D8DfxfVT.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-oizkYeQD.js → WorkflowEditor-Csadpaln.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Du6ZthE5.js → chat-CewHWc_T.js} +1 -1
- package/src/assets/web-panel/assets/{colors-I2ie73HS.js → colors-B8at89r3.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C-02XOOx.js → compact-item-v_gxtF5-.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DgP09zg2.js → createContext-BOwFpJqA.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DenB_kSS.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-kWDasRib.js → hasIn-DjHUzt7E.js} +1 -1
- package/src/assets/web-panel/assets/{index-HH3Zccc0.js → index-1Tfwr_GA.js} +1 -1
- package/src/assets/web-panel/assets/{index-M9mzJo6V.js → index-5qmLo1us.js} +1 -1
- package/src/assets/web-panel/assets/index-B8bNwM9U.js +1 -0
- package/src/assets/web-panel/assets/{index-CDM6OO4D.js → index-BC20EQ7h.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cokjvq67.js → index-BGrmPk8T.js} +1 -1
- package/src/assets/web-panel/assets/{index-5Ll5Fdqb.js → index-BPJ7uL2Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-H_31JkaZ.js → index-BRNyE3Kb.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9HwtJX5.js → index-BVPsegMN.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bpz5RnQy.js → index-B_egGFcR.js} +3 -3
- package/src/assets/web-panel/assets/{index-CjuJ1FYZ.js → index-BdZLA7k9.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx5dAdFu.js → index-Bk_Te9OR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHSghc3j.js → index-Bz8C8VXx.js} +1 -1
- package/src/assets/web-panel/assets/{index-RwcHDSqP.js → index-C7MHbmwn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtbMRqD-.js → index-CFL1Hewx.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0EQSoEb.js → index-CV1SgaBd.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3D5NSjS.js → index-CXIPAeAB.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZ6bWk4x.js → index-Ca8YZU2B.js} +1 -1
- package/src/assets/web-panel/assets/{index-AtAiEmjM.js → index-Caf9UjhG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKJ-d5F1.js → index-Cb1uNDOv.js} +1 -1
- package/src/assets/web-panel/assets/{index-mF8UmKqp.js → index-CquUCUzS.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpOQeTac.js → index-CwHoF-TP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Na5QA1LE.js → index-Cxk0mCoQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BUvpjPMv.js → index-D3o-pacB.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZcdP3id.js → index-DA3n0Y28.js} +1 -1
- package/src/assets/web-panel/assets/index-DC0cpgIP.js +1 -0
- package/src/assets/web-panel/assets/{index-LLQQqj9B.js → index-DRRK_8Eg.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5LV04FO.js → index-DUMvVGyf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkcCllZ7.js → index-DdHdbXpy.js} +1 -1
- package/src/assets/web-panel/assets/{index-OYyn8GoU.js → index-Ddw05Myq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgogPjKJ.js → index-Dfrb3Prv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbHEQTU6.js → index-DiKaYIdo.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQCdk4dn.js → index-DmZLZsyC.js} +1 -1
- package/src/assets/web-panel/assets/{index-uHI8QHu4.js → index-FgUrhq_H.js} +1 -1
- package/src/assets/web-panel/assets/{index-I4A_y2Ee.js → index-Khw7wzVk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSlTGxUJ.js → index-San3zacc.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYxia8nl.js → index-coOi37of.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkP2DW3a.js → index-hyeBuocp.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ryflob2W.js → index-uk59xr0W.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcVj7YJB.js → index-wjvn8-9F.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BPHGo-UX.js → initDefaultProps-Id2dFdjh.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BBr8JvWc.js → motion-DRxtwxng.js} +1 -1
- package/src/assets/web-panel/assets/{move-CdKWToz7.js → move-BDYvdTb6.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-B8tkkKBs.js → mtc-parser-cz8LGI8Z.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DN4aP33H.js → omit-DHJeh6tH.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CoHRkRJq.js → pickAttrs-XJEQIp7e.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DpGGGAPa.js → placementArrow-AFcf8lEn.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BabRsZo5.js → responsiveObserve-CDEeBxs1.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DJjyrwqK.js → slide-CvbVfi6T.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BaRVkO5S.js → statusUtils-DtCyuEnq.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-HcMYUjTR.js → styleChecker--UgmTsGY.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-c3IBzp2l.js → useFlexGapSupport-D9i1as-Y.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DD7igwyF.js → useFs-CJx3zw01.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-GEF0hhnd.js → usePersonalDataHub-ZsIKYdZv.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-D51u7zqF.js → vnode-B2RGEQG4.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-tXG23Lc9.js → zoom-ob-0px2z.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/evolution-attestor-trust.js +113 -0
- package/src/commands/evolution.js +2 -0
- package/src/commands/learning.js +34 -5
- package/src/data/changelog.json +13 -0
- package/src/lib/evolution/evolution-artifact-ports.js +21 -0
- package/src/lib/evolution/evolution-deployment-loader.js +56 -0
- package/src/lib/evolution/evolution-immutable-ledger-segment-store.js +812 -0
- package/src/lib/evolution/evolution-ledger-file-manifest-catalog.js +218 -0
- package/src/lib/evolution/evolution-ledger-manifest-catalog.js +472 -0
- package/src/lib/evolution/evolution-ledger-manifest-chain.js +997 -0
- package/src/lib/evolution/evolution-ledger-manifest-head-store.js +408 -0
- package/src/lib/evolution/evolution-ledger-manifest-witness-adapter.js +554 -0
- package/src/lib/evolution/evolution-ledger-v2-manifest-backend.js +460 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-ipc-endpoint.js +94 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-approval-client.js +485 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-ipc-capability.js +200 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-ledger.js +1222 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations-cli-host.js +802 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations-client.js +445 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations.js +1082 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operator-registry.js +1453 -0
- package/src/lib/evolution/governed-skill-synthesis-candidate-evaluator.js +147 -0
- package/src/lib/evolution/governed-skill-synthesis-cli-host.js +115 -0
- package/src/lib/evolution/governed-skill-synthesis-evaluation-ledger-adapter.js +715 -0
- package/src/lib/evolution/governed-skill-synthesis-external-attestor.js +499 -0
- package/src/lib/evolution/governed-skill-synthesis-model-evaluator.js +514 -0
- package/src/lib/evolution/governed-skill-synthesis-process-attestor-worker.mjs +208 -0
- package/src/lib/evolution/governed-skill-synthesis-process-attestor.js +557 -0
- package/src/lib/evolution/governed-skill-synthesis-process-grader-worker.mjs +143 -0
- package/src/lib/evolution/governed-skill-synthesis-process-grader.js +444 -0
- package/src/lib/evolution/governed-skill-synthesis-provider-chat.js +220 -0
- package/src/lib/evolution/governed-skill-synthesis-windows-secure-pipe-host.js +236 -0
- package/src/lib/hook-audit-store.js +68 -2
- package/src/lib/hooks-v2-runtime.js +52 -26
- package/src/lib/learning/skill-synthesizer.js +66 -5
- package/src/lib/remote-read-loop-guard.js +30 -3
- package/src/assets/web-panel/assets/MarkdownRenderer-DnSfkf98.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CFbhBT44.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-Cv9PLMWJ.js +0 -7
- package/src/assets/web-panel/assets/devWarning-CxKkOIjh.js +0 -1
- package/src/assets/web-panel/assets/index-b5a6l3Uu.js +0 -1
- package/src/assets/web-panel/assets/index-xt-BOyp_.js +0 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { types as utilTypes } from "node:util";
|
|
5
|
+
|
|
6
|
+
import { ensurePrivateDirectory, ensurePrivateFile } from "../secure-fs.js";
|
|
7
|
+
import { withFileLock } from "../with-file-lock.js";
|
|
8
|
+
import { readBoundedDescriptor } from "./bounded-descriptor-read.js";
|
|
9
|
+
import { EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_RESULT_SCHEMA } from "./evolution-ledger-manifest-catalog.js";
|
|
10
|
+
|
|
11
|
+
export const EVOLUTION_LEDGER_FILE_MANIFEST_CATALOG_SCHEMA =
|
|
12
|
+
"chainlesschain.evolution-ledger-file-manifest-catalog/v2";
|
|
13
|
+
|
|
14
|
+
const STATE_SCHEMA =
|
|
15
|
+
"chainlesschain.evolution-ledger-file-manifest-catalog-state/v2";
|
|
16
|
+
const STATE_KEYS = new Set(["manifests", "schema"]);
|
|
17
|
+
const DEFAULT_MAXIMUM_BYTES = 64 * 1024 * 1024;
|
|
18
|
+
|
|
19
|
+
function exactRecord(value, keys, label) {
|
|
20
|
+
if (
|
|
21
|
+
!value ||
|
|
22
|
+
typeof value !== "object" ||
|
|
23
|
+
Array.isArray(value) ||
|
|
24
|
+
utilTypes.isProxy(value)
|
|
25
|
+
) {
|
|
26
|
+
throw new Error(`${label} is invalid`);
|
|
27
|
+
}
|
|
28
|
+
const fields = Object.getOwnPropertyDescriptors(value);
|
|
29
|
+
const names = Object.keys(fields);
|
|
30
|
+
if (names.length !== keys.size || names.some((name) => !keys.has(name))) {
|
|
31
|
+
throw new Error(`${label} fields are invalid`);
|
|
32
|
+
}
|
|
33
|
+
for (const name of names) {
|
|
34
|
+
if (!("value" in fields[name]))
|
|
35
|
+
throw new Error(`${label}.${name} must be own data`);
|
|
36
|
+
}
|
|
37
|
+
return fields;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function syncDirectory(fsImpl, directory) {
|
|
41
|
+
let descriptor;
|
|
42
|
+
try {
|
|
43
|
+
descriptor = fsImpl.openSync(directory, "r");
|
|
44
|
+
fsImpl.fsyncSync(descriptor);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (
|
|
47
|
+
process.platform !== "win32" ||
|
|
48
|
+
!["EACCES", "EINVAL", "EISDIR", "EPERM"].includes(error?.code)
|
|
49
|
+
) {
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
} finally {
|
|
53
|
+
if (descriptor !== undefined) fsImpl.closeSync(descriptor);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function createEvolutionLedgerFileManifestCatalogBackend({
|
|
58
|
+
directoryPath,
|
|
59
|
+
fsImpl = fs,
|
|
60
|
+
lock = withFileLock,
|
|
61
|
+
maximumBytes = DEFAULT_MAXIMUM_BYTES,
|
|
62
|
+
random = () => crypto.randomBytes(16).toString("hex"),
|
|
63
|
+
} = {}) {
|
|
64
|
+
if (typeof directoryPath !== "string" || directoryPath.trim() === "") {
|
|
65
|
+
throw new TypeError("manifest catalog directoryPath is required");
|
|
66
|
+
}
|
|
67
|
+
if (typeof lock !== "function" || typeof random !== "function") {
|
|
68
|
+
throw new TypeError("manifest catalog lock and random ports are required");
|
|
69
|
+
}
|
|
70
|
+
if (!Number.isSafeInteger(maximumBytes) || maximumBytes < 4096) {
|
|
71
|
+
throw new TypeError("manifest catalog maximumBytes must be at least 4096");
|
|
72
|
+
}
|
|
73
|
+
const directory = path.resolve(directoryPath);
|
|
74
|
+
const file = path.join(directory, "manifest-catalog.json");
|
|
75
|
+
const secureOptions = { deps: { fs: fsImpl }, failIfUnavailable: true };
|
|
76
|
+
ensurePrivateDirectory(directory, secureOptions);
|
|
77
|
+
|
|
78
|
+
const readBytes = () => {
|
|
79
|
+
if (!fsImpl.existsSync(file)) return null;
|
|
80
|
+
const stat = fsImpl.lstatSync(file);
|
|
81
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1) {
|
|
82
|
+
throw new Error("manifest catalog file identity is invalid");
|
|
83
|
+
}
|
|
84
|
+
if (stat.size > maximumBytes)
|
|
85
|
+
throw new Error("manifest catalog exceeds maximumBytes");
|
|
86
|
+
let descriptor;
|
|
87
|
+
try {
|
|
88
|
+
descriptor = fsImpl.openSync(
|
|
89
|
+
file,
|
|
90
|
+
fsImpl.constants.O_RDONLY | (fsImpl.constants.O_NOFOLLOW || 0),
|
|
91
|
+
);
|
|
92
|
+
const opened = fsImpl.fstatSync(descriptor);
|
|
93
|
+
if (!opened.isFile() || opened.nlink !== 1 || opened.size !== stat.size) {
|
|
94
|
+
throw new Error("manifest catalog changed while opening");
|
|
95
|
+
}
|
|
96
|
+
const bytes = readBoundedDescriptor(
|
|
97
|
+
fsImpl,
|
|
98
|
+
descriptor,
|
|
99
|
+
stat.size,
|
|
100
|
+
maximumBytes,
|
|
101
|
+
);
|
|
102
|
+
const after = fsImpl.lstatSync(file);
|
|
103
|
+
if (after.isSymbolicLink() || after.size !== stat.size) {
|
|
104
|
+
throw new Error("manifest catalog changed while reading");
|
|
105
|
+
}
|
|
106
|
+
return bytes;
|
|
107
|
+
} finally {
|
|
108
|
+
if (descriptor !== undefined) fsImpl.closeSync(descriptor);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const readState = () => {
|
|
113
|
+
const bytes = readBytes();
|
|
114
|
+
if (bytes === null) return { manifests: [], schema: STATE_SCHEMA };
|
|
115
|
+
let parsed;
|
|
116
|
+
try {
|
|
117
|
+
parsed = JSON.parse(
|
|
118
|
+
new TextDecoder("utf-8", { fatal: true }).decode(bytes),
|
|
119
|
+
);
|
|
120
|
+
} catch {
|
|
121
|
+
throw new Error("manifest catalog is not valid UTF-8 JSON");
|
|
122
|
+
}
|
|
123
|
+
const fields = exactRecord(parsed, STATE_KEYS, "manifest catalog state");
|
|
124
|
+
if (
|
|
125
|
+
fields.schema.value !== STATE_SCHEMA ||
|
|
126
|
+
!Array.isArray(fields.manifests.value)
|
|
127
|
+
) {
|
|
128
|
+
throw new Error("manifest catalog state is invalid");
|
|
129
|
+
}
|
|
130
|
+
if (
|
|
131
|
+
Object.keys(fields.manifests.value).length !==
|
|
132
|
+
fields.manifests.value.length
|
|
133
|
+
) {
|
|
134
|
+
throw new Error("manifest catalog manifests must be dense");
|
|
135
|
+
}
|
|
136
|
+
return parsed;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const writeState = (state) => {
|
|
140
|
+
const bytes = Buffer.from(`${JSON.stringify(state)}\n`, "utf8");
|
|
141
|
+
if (bytes.length > maximumBytes)
|
|
142
|
+
throw new Error("manifest catalog exceeds maximumBytes");
|
|
143
|
+
const token = random();
|
|
144
|
+
if (typeof token !== "string" || !/^[a-zA-Z0-9_-]{8,128}$/u.test(token)) {
|
|
145
|
+
throw new Error("manifest catalog random token is invalid");
|
|
146
|
+
}
|
|
147
|
+
const temporary = `${file}.${token}.tmp`;
|
|
148
|
+
let descriptor;
|
|
149
|
+
try {
|
|
150
|
+
descriptor = fsImpl.openSync(temporary, "wx", 0o600);
|
|
151
|
+
fsImpl.writeFileSync(descriptor, bytes);
|
|
152
|
+
fsImpl.fsyncSync(descriptor);
|
|
153
|
+
fsImpl.closeSync(descriptor);
|
|
154
|
+
descriptor = undefined;
|
|
155
|
+
fsImpl.renameSync(temporary, file);
|
|
156
|
+
ensurePrivateFile(file, secureOptions);
|
|
157
|
+
descriptor = fsImpl.openSync(file, "r+");
|
|
158
|
+
fsImpl.fsyncSync(descriptor);
|
|
159
|
+
fsImpl.closeSync(descriptor);
|
|
160
|
+
descriptor = undefined;
|
|
161
|
+
syncDirectory(fsImpl, directory);
|
|
162
|
+
const readback = readBytes();
|
|
163
|
+
if (readback === null || !readback.equals(bytes)) {
|
|
164
|
+
throw new Error("manifest catalog durable readback differs");
|
|
165
|
+
}
|
|
166
|
+
} finally {
|
|
167
|
+
if (descriptor !== undefined) fsImpl.closeSync(descriptor);
|
|
168
|
+
try {
|
|
169
|
+
if (fsImpl.existsSync(temporary)) fsImpl.unlinkSync(temporary);
|
|
170
|
+
} catch {
|
|
171
|
+
// A private incomplete staging file cannot change the committed catalog.
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
return Object.freeze({
|
|
177
|
+
descriptor: Object.freeze({
|
|
178
|
+
file,
|
|
179
|
+
localOnly: true,
|
|
180
|
+
schema: EVOLUTION_LEDGER_FILE_MANIFEST_CATALOG_SCHEMA,
|
|
181
|
+
}),
|
|
182
|
+
compareAndAppend(request) {
|
|
183
|
+
return lock(
|
|
184
|
+
file,
|
|
185
|
+
() => {
|
|
186
|
+
const state = readState();
|
|
187
|
+
const latest = state.manifests.at(-1) ?? null;
|
|
188
|
+
if (
|
|
189
|
+
(latest?.manifestDigest ?? null) !== request.expectedManifestDigest
|
|
190
|
+
) {
|
|
191
|
+
return Object.freeze({
|
|
192
|
+
appended: false,
|
|
193
|
+
latest,
|
|
194
|
+
schema: EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_RESULT_SCHEMA,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
const next = {
|
|
198
|
+
manifests: [...state.manifests, structuredClone(request.manifest)],
|
|
199
|
+
schema: STATE_SCHEMA,
|
|
200
|
+
};
|
|
201
|
+
writeState(next);
|
|
202
|
+
return Object.freeze({
|
|
203
|
+
appended: true,
|
|
204
|
+
latest: structuredClone(request.manifest),
|
|
205
|
+
schema: EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_RESULT_SCHEMA,
|
|
206
|
+
});
|
|
207
|
+
},
|
|
208
|
+
{ _fs: fsImpl, failIfUnavailable: true },
|
|
209
|
+
);
|
|
210
|
+
},
|
|
211
|
+
list() {
|
|
212
|
+
return structuredClone(readState().manifests);
|
|
213
|
+
},
|
|
214
|
+
loadLatest() {
|
|
215
|
+
return structuredClone(readState().manifests.at(-1) ?? null);
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
}
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { types as utilTypes } from "node:util";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
captureEvolutionLedgerManifestAuthority,
|
|
5
|
+
verifyEvolutionLedgerSegmentManifest,
|
|
6
|
+
} from "./evolution-ledger-manifest-chain.js";
|
|
7
|
+
|
|
8
|
+
export const EVOLUTION_LEDGER_MANIFEST_CATALOG_SCHEMA =
|
|
9
|
+
"chainlesschain.evolution-ledger-manifest-catalog/v2";
|
|
10
|
+
export const EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_REQUEST_SCHEMA =
|
|
11
|
+
"chainlesschain.evolution-ledger-manifest-catalog-append-request/v2";
|
|
12
|
+
export const EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_RESULT_SCHEMA =
|
|
13
|
+
"chainlesschain.evolution-ledger-manifest-catalog-append-result/v2";
|
|
14
|
+
export const EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE =
|
|
15
|
+
"CC_EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID";
|
|
16
|
+
export const EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE =
|
|
17
|
+
"CC_EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT";
|
|
18
|
+
export const EVOLUTION_LEDGER_MANIFEST_CATALOG_UNAVAILABLE_CODE =
|
|
19
|
+
"CC_EVOLUTION_LEDGER_MANIFEST_CATALOG_UNAVAILABLE";
|
|
20
|
+
export const EVOLUTION_LEDGER_MANIFEST_CATALOG_COMMIT_UNKNOWN_CODE =
|
|
21
|
+
"CC_EVOLUTION_LEDGER_MANIFEST_CATALOG_COMMIT_UNKNOWN";
|
|
22
|
+
|
|
23
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
24
|
+
const CONFIG_KEYS = new Set(["backend", "descriptor", "manifestAuthority"]);
|
|
25
|
+
const DESCRIPTOR_KEYS = new Set([
|
|
26
|
+
"epoch",
|
|
27
|
+
"ledgerId",
|
|
28
|
+
"maximumEventsPerSegment",
|
|
29
|
+
"tenantId",
|
|
30
|
+
]);
|
|
31
|
+
const APPEND_KEYS = new Set(["expectedManifestDigest", "manifest"]);
|
|
32
|
+
const RESULT_KEYS = new Set(["appended", "latest", "schema"]);
|
|
33
|
+
const CATALOGS = new WeakSet();
|
|
34
|
+
|
|
35
|
+
export class EvolutionLedgerManifestCatalogError extends Error {
|
|
36
|
+
constructor(code, message, options = undefined) {
|
|
37
|
+
super(message, options);
|
|
38
|
+
this.name = "EvolutionLedgerManifestCatalogError";
|
|
39
|
+
this.code = code;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function failure(code, message, options = undefined) {
|
|
44
|
+
return new EvolutionLedgerManifestCatalogError(code, message, options);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function rejectProxy(
|
|
48
|
+
value,
|
|
49
|
+
label,
|
|
50
|
+
code = EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
51
|
+
) {
|
|
52
|
+
if (
|
|
53
|
+
(typeof value === "object" && value !== null) ||
|
|
54
|
+
typeof value === "function"
|
|
55
|
+
) {
|
|
56
|
+
if (utilTypes.isProxy(value))
|
|
57
|
+
throw failure(code, `${label} must not be a Proxy`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function exactRecord(
|
|
62
|
+
value,
|
|
63
|
+
keys,
|
|
64
|
+
label,
|
|
65
|
+
code = EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
66
|
+
) {
|
|
67
|
+
rejectProxy(value, label, code);
|
|
68
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
69
|
+
throw failure(code, `${label} must be a record`);
|
|
70
|
+
}
|
|
71
|
+
const prototype = Object.getPrototypeOf(value);
|
|
72
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
73
|
+
throw failure(code, `${label} must use a plain prototype`);
|
|
74
|
+
}
|
|
75
|
+
const fields = Object.getOwnPropertyDescriptors(value);
|
|
76
|
+
const names = Object.keys(fields);
|
|
77
|
+
if (names.length !== keys.size || names.some((name) => !keys.has(name))) {
|
|
78
|
+
throw failure(code, `${label} fields are invalid`);
|
|
79
|
+
}
|
|
80
|
+
for (const name of names) {
|
|
81
|
+
if (!("value" in fields[name])) {
|
|
82
|
+
throw failure(code, `${label}.${name} must be an own data property`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return fields;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function data(fields, name) {
|
|
89
|
+
return fields[name].value;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function identifier(
|
|
93
|
+
value,
|
|
94
|
+
label,
|
|
95
|
+
code = EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
96
|
+
) {
|
|
97
|
+
if (
|
|
98
|
+
typeof value !== "string" ||
|
|
99
|
+
value.trim() !== value ||
|
|
100
|
+
value.length < 1 ||
|
|
101
|
+
value.length > 512 ||
|
|
102
|
+
value.includes("\0")
|
|
103
|
+
) {
|
|
104
|
+
throw failure(code, `${label} is invalid`);
|
|
105
|
+
}
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function maximum(
|
|
110
|
+
value,
|
|
111
|
+
label,
|
|
112
|
+
code = EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
113
|
+
) {
|
|
114
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > 1024) {
|
|
115
|
+
throw failure(code, `${label} is invalid`);
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function digest(
|
|
121
|
+
value,
|
|
122
|
+
label,
|
|
123
|
+
code = EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
124
|
+
) {
|
|
125
|
+
if (!DIGEST.test(value || ""))
|
|
126
|
+
throw failure(code, `${label} must be sha256-bound`);
|
|
127
|
+
return value;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function nullableDigest(
|
|
131
|
+
value,
|
|
132
|
+
label,
|
|
133
|
+
code = EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
134
|
+
) {
|
|
135
|
+
return value === null ? null : digest(value, label, code);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function descriptor(value) {
|
|
139
|
+
const fields = exactRecord(
|
|
140
|
+
value,
|
|
141
|
+
DESCRIPTOR_KEYS,
|
|
142
|
+
"manifest catalog descriptor",
|
|
143
|
+
);
|
|
144
|
+
return Object.freeze({
|
|
145
|
+
epoch: identifier(data(fields, "epoch"), "descriptor.epoch"),
|
|
146
|
+
ledgerId: identifier(data(fields, "ledgerId"), "descriptor.ledgerId"),
|
|
147
|
+
maximumEventsPerSegment: maximum(
|
|
148
|
+
data(fields, "maximumEventsPerSegment"),
|
|
149
|
+
"descriptor.maximumEventsPerSegment",
|
|
150
|
+
),
|
|
151
|
+
tenantId: identifier(data(fields, "tenantId"), "descriptor.tenantId"),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function callable(value, name) {
|
|
156
|
+
const field = Object.getOwnPropertyDescriptor(value, name);
|
|
157
|
+
if (!field || !("value" in field) || typeof field.value !== "function") {
|
|
158
|
+
throw failure(
|
|
159
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
160
|
+
`manifest catalog backend.${name} must be an own function`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
rejectProxy(field.value, `manifest catalog backend.${name}`);
|
|
164
|
+
return field.value;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function synchronous(
|
|
168
|
+
value,
|
|
169
|
+
label,
|
|
170
|
+
code = EVOLUTION_LEDGER_MANIFEST_CATALOG_UNAVAILABLE_CODE,
|
|
171
|
+
) {
|
|
172
|
+
rejectProxy(value, label, code);
|
|
173
|
+
if (utilTypes.isPromise(value))
|
|
174
|
+
throw failure(code, `${label} must be synchronous`);
|
|
175
|
+
return value;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function manifest(authority, descriptorValue, value, code) {
|
|
179
|
+
try {
|
|
180
|
+
return verifyEvolutionLedgerSegmentManifest({
|
|
181
|
+
authority,
|
|
182
|
+
descriptor: descriptorValue,
|
|
183
|
+
manifest: value,
|
|
184
|
+
});
|
|
185
|
+
} catch (cause) {
|
|
186
|
+
throw failure(code, "manifest catalog manifest is invalid", { cause });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function latest(authority, descriptorValue, raw, code) {
|
|
191
|
+
return raw === null ? null : manifest(authority, descriptorValue, raw, code);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function sameManifest(left, right) {
|
|
195
|
+
return left?.manifestDigest === right?.manifestDigest;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function linked(previous, next) {
|
|
199
|
+
return (
|
|
200
|
+
next.manifestSequence === (previous?.manifestSequence ?? 0) + 1 &&
|
|
201
|
+
next.previousManifestDigest === (previous?.manifestDigest ?? null) &&
|
|
202
|
+
next.sequenceStart === (previous?.sequenceEnd ?? 0) + 1
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function createEvolutionLedgerManifestCatalog(options = undefined) {
|
|
207
|
+
const fields = exactRecord(
|
|
208
|
+
options,
|
|
209
|
+
CONFIG_KEYS,
|
|
210
|
+
"manifest catalog configuration",
|
|
211
|
+
);
|
|
212
|
+
const descriptorValue = descriptor(data(fields, "descriptor"));
|
|
213
|
+
const authority = captureEvolutionLedgerManifestAuthority(
|
|
214
|
+
data(fields, "manifestAuthority"),
|
|
215
|
+
);
|
|
216
|
+
const backend = data(fields, "backend");
|
|
217
|
+
rejectProxy(backend, "manifest catalog backend");
|
|
218
|
+
if (!backend || typeof backend !== "object") {
|
|
219
|
+
throw failure(
|
|
220
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
221
|
+
"manifest catalog backend is required",
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const loadLatest = callable(backend, "loadLatest");
|
|
225
|
+
const compareAndAppend = callable(backend, "compareAndAppend");
|
|
226
|
+
const list = callable(backend, "list");
|
|
227
|
+
|
|
228
|
+
const readLatest = () => {
|
|
229
|
+
let raw;
|
|
230
|
+
try {
|
|
231
|
+
raw = synchronous(
|
|
232
|
+
Reflect.apply(loadLatest, backend, [
|
|
233
|
+
Object.freeze({ ...descriptorValue }),
|
|
234
|
+
]),
|
|
235
|
+
"manifest catalog loadLatest result",
|
|
236
|
+
);
|
|
237
|
+
} catch (cause) {
|
|
238
|
+
if (cause instanceof EvolutionLedgerManifestCatalogError) throw cause;
|
|
239
|
+
throw failure(
|
|
240
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_UNAVAILABLE_CODE,
|
|
241
|
+
"manifest catalog loadLatest failed",
|
|
242
|
+
{ cause },
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
return latest(
|
|
246
|
+
authority,
|
|
247
|
+
descriptorValue,
|
|
248
|
+
raw,
|
|
249
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
250
|
+
);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const catalog = Object.freeze({
|
|
254
|
+
descriptor: Object.freeze({
|
|
255
|
+
...descriptorValue,
|
|
256
|
+
schema: EVOLUTION_LEDGER_MANIFEST_CATALOG_SCHEMA,
|
|
257
|
+
}),
|
|
258
|
+
append(input) {
|
|
259
|
+
const request = exactRecord(
|
|
260
|
+
input,
|
|
261
|
+
APPEND_KEYS,
|
|
262
|
+
"manifest catalog append request",
|
|
263
|
+
);
|
|
264
|
+
const expectedManifestDigest = nullableDigest(
|
|
265
|
+
data(request, "expectedManifestDigest"),
|
|
266
|
+
"expectedManifestDigest",
|
|
267
|
+
);
|
|
268
|
+
const next = manifest(
|
|
269
|
+
authority,
|
|
270
|
+
descriptorValue,
|
|
271
|
+
data(request, "manifest"),
|
|
272
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
273
|
+
);
|
|
274
|
+
const observed = readLatest();
|
|
275
|
+
if ((observed?.manifestDigest ?? null) !== expectedManifestDigest) {
|
|
276
|
+
return Object.freeze({
|
|
277
|
+
appended: false,
|
|
278
|
+
conflict: true,
|
|
279
|
+
latest: observed,
|
|
280
|
+
schema: EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_RESULT_SCHEMA,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
if (!linked(observed, next)) {
|
|
284
|
+
throw failure(
|
|
285
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
286
|
+
"manifest catalog append does not link to its current latest manifest",
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
let rawResult;
|
|
290
|
+
try {
|
|
291
|
+
rawResult = synchronous(
|
|
292
|
+
Reflect.apply(compareAndAppend, backend, [
|
|
293
|
+
Object.freeze({
|
|
294
|
+
expectedManifestDigest,
|
|
295
|
+
manifest: next,
|
|
296
|
+
schema: EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_REQUEST_SCHEMA,
|
|
297
|
+
}),
|
|
298
|
+
]),
|
|
299
|
+
"manifest catalog compareAndAppend result",
|
|
300
|
+
);
|
|
301
|
+
} catch (cause) {
|
|
302
|
+
throw failure(
|
|
303
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_COMMIT_UNKNOWN_CODE,
|
|
304
|
+
"manifest catalog acknowledgement was lost; reopen before retrying",
|
|
305
|
+
{ cause },
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
let result;
|
|
309
|
+
try {
|
|
310
|
+
const resultFields = exactRecord(
|
|
311
|
+
rawResult,
|
|
312
|
+
RESULT_KEYS,
|
|
313
|
+
"manifest catalog append result",
|
|
314
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
315
|
+
);
|
|
316
|
+
if (
|
|
317
|
+
data(resultFields, "schema") !==
|
|
318
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_RESULT_SCHEMA ||
|
|
319
|
+
typeof data(resultFields, "appended") !== "boolean"
|
|
320
|
+
) {
|
|
321
|
+
throw failure(
|
|
322
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
323
|
+
"manifest catalog append result is invalid",
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
result = Object.freeze({
|
|
327
|
+
appended: data(resultFields, "appended"),
|
|
328
|
+
latest: latest(
|
|
329
|
+
authority,
|
|
330
|
+
descriptorValue,
|
|
331
|
+
data(resultFields, "latest"),
|
|
332
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
333
|
+
),
|
|
334
|
+
});
|
|
335
|
+
} catch (cause) {
|
|
336
|
+
throw failure(
|
|
337
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_COMMIT_UNKNOWN_CODE,
|
|
338
|
+
"manifest catalog acknowledgement is invalid; reopen before retrying",
|
|
339
|
+
{ cause },
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
if (!result.appended) {
|
|
343
|
+
if (sameManifest(result.latest, next)) {
|
|
344
|
+
throw failure(
|
|
345
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
346
|
+
"manifest catalog denied a manifest that it returned as latest",
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
return Object.freeze({
|
|
350
|
+
appended: false,
|
|
351
|
+
conflict: true,
|
|
352
|
+
latest: result.latest,
|
|
353
|
+
schema: EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_RESULT_SCHEMA,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
if (!sameManifest(result.latest, next)) {
|
|
357
|
+
throw failure(
|
|
358
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_COMMIT_UNKNOWN_CODE,
|
|
359
|
+
"manifest catalog acknowledged substituted data; reopen before retrying",
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
let readback;
|
|
363
|
+
try {
|
|
364
|
+
readback = readLatest();
|
|
365
|
+
} catch (cause) {
|
|
366
|
+
throw failure(
|
|
367
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_COMMIT_UNKNOWN_CODE,
|
|
368
|
+
"manifest catalog may be committed; reopen before retrying",
|
|
369
|
+
{ cause },
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
if (!sameManifest(readback, next)) {
|
|
373
|
+
throw failure(
|
|
374
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_COMMIT_UNKNOWN_CODE,
|
|
375
|
+
"manifest catalog readback differs; reopen before retrying",
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
return Object.freeze({
|
|
379
|
+
appended: true,
|
|
380
|
+
conflict: false,
|
|
381
|
+
latest: readback,
|
|
382
|
+
schema: EVOLUTION_LEDGER_MANIFEST_CATALOG_APPEND_RESULT_SCHEMA,
|
|
383
|
+
});
|
|
384
|
+
},
|
|
385
|
+
list() {
|
|
386
|
+
let raw;
|
|
387
|
+
try {
|
|
388
|
+
raw = synchronous(
|
|
389
|
+
Reflect.apply(list, backend, [Object.freeze({ ...descriptorValue })]),
|
|
390
|
+
"manifest catalog list result",
|
|
391
|
+
);
|
|
392
|
+
} catch (cause) {
|
|
393
|
+
if (cause instanceof EvolutionLedgerManifestCatalogError) throw cause;
|
|
394
|
+
throw failure(
|
|
395
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_UNAVAILABLE_CODE,
|
|
396
|
+
"manifest catalog list failed",
|
|
397
|
+
{ cause },
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
rejectProxy(
|
|
401
|
+
raw,
|
|
402
|
+
"manifest catalog list",
|
|
403
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
404
|
+
);
|
|
405
|
+
if (!Array.isArray(raw) || Object.keys(raw).length !== raw.length) {
|
|
406
|
+
throw failure(
|
|
407
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
408
|
+
"manifest catalog list must be a dense array",
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
let previous = null;
|
|
412
|
+
const manifests = raw.map((entry) => {
|
|
413
|
+
const current = manifest(
|
|
414
|
+
authority,
|
|
415
|
+
descriptorValue,
|
|
416
|
+
entry,
|
|
417
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
418
|
+
);
|
|
419
|
+
if (!linked(previous, current)) {
|
|
420
|
+
throw failure(
|
|
421
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
422
|
+
"manifest catalog chain linkage is invalid",
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
previous = current;
|
|
426
|
+
return current;
|
|
427
|
+
});
|
|
428
|
+
const currentLatest = readLatest();
|
|
429
|
+
if (!sameManifest(currentLatest, manifests.at(-1) ?? null)) {
|
|
430
|
+
throw failure(
|
|
431
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_CORRUPT_CODE,
|
|
432
|
+
"manifest catalog latest differs from its listed chain",
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
return Object.freeze(manifests);
|
|
436
|
+
},
|
|
437
|
+
readLatest,
|
|
438
|
+
});
|
|
439
|
+
CATALOGS.add(catalog);
|
|
440
|
+
return catalog;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export function captureEvolutionLedgerManifestCatalog(
|
|
444
|
+
value,
|
|
445
|
+
expected = undefined,
|
|
446
|
+
) {
|
|
447
|
+
if (!CATALOGS.has(value)) {
|
|
448
|
+
throw new TypeError(
|
|
449
|
+
"a branded Evolution Ledger manifest catalog is required",
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
if (expected !== undefined) {
|
|
453
|
+
const fields = exactRecord(
|
|
454
|
+
expected,
|
|
455
|
+
new Set(["epoch", "ledgerId", "tenantId"]),
|
|
456
|
+
"expected manifest catalog scope",
|
|
457
|
+
);
|
|
458
|
+
for (const field of ["epoch", "ledgerId", "tenantId"]) {
|
|
459
|
+
if (value.descriptor[field] !== data(fields, field)) {
|
|
460
|
+
throw failure(
|
|
461
|
+
EVOLUTION_LEDGER_MANIFEST_CATALOG_INVALID_CODE,
|
|
462
|
+
`manifest catalog ${field} scope differs`,
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return value;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export function isEvolutionLedgerManifestCatalog(value) {
|
|
471
|
+
return CATALOGS.has(value);
|
|
472
|
+
}
|