chainlesschain 0.166.65 → 0.166.69

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.
Files changed (200) hide show
  1. package/README.md +20 -12
  2. package/package.json +4 -4
  3. package/src/assets/web-panel/assets/{AIOps-Byz17CTN.js → AIOps-FhevRfL6.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-C5LiW2-J.js → ActionButton-rOeOykx5.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-D1INcvZF.js → Analytics-BK_wYlfz.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-DZzHO1VV.js → AppLayout-_2cCtZKV.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-WfYQL6Ia.js → Artifacts-D5MSvVzk.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-DohBoGWO.js → Audit-yd-Ah-A3.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-Chtk-Hde.js → BackgroundAgents-yCaw_Gu_.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-B813PuMz.js → Backup-G3ADD4N-.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-DaDdWWgK.js → BaseInput-ByDhkLbF.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-D4pJ6oZ7.js → Chat-BMrc7qjz.js} +4 -4
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-nA7n0I6S.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-Clo9TvO6.js → Checkbox-BHYgyZWA.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-uejLg8Ih.js → Codegen-DJfcy0jC.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-B7nbx-iJ.js → Col-C27zROxc.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-FEyjPK1j.js → Community-CuS5tq_1.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-B6Fk0Kn6.js → Compact-BrYJNe7Q.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BQG8goUl.js → Compliance-8hfahYHT.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-CbBeEfHp.js → Cowork-DdE0n2lp.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-DPzlFcEZ.js → Cron-CUq3aSiX.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-B8pWJrbg.js → Crosschain-BM4XSPWG.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-gGQHUlFN.js → DID-CdaBY57N.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-C2TMFHrn.js → Dashboard-Cwtd52So.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-BVPxGbll.js → Dropdown-BvlObh6U.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-CNPxs0hd.js → EmailListRenderer-e3fLhjnX.js} +1 -1
  27. package/src/assets/web-panel/assets/{EvolutionSettings-_XTiB7q1.js → EvolutionSettings-CTtk1Zo8.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-UyE3VWtI.js → FamilyGuardDashboard-BpPJUnCU.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-CLt6FHK-.js → Federation-vzjZ6_nQ.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-CdNQPRPw.js → FormItemContext-DEDNLhkE.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-BJ0AMhrh.js → GenericCardRenderer-DEl2Te5f.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-CQnvMfOM.js → Git-BzsYQnCq.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-deYsHC-o.js → Governance-zxJs6Y8s.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-qaSck43z.js → Inference-5JUsrmF1.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-De0aJ3Ls.js → KnowledgeGraph-Br8b5Htz.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-ZtS98jCm.js → Logs-D-tubDMJ.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-In4itZX2.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-Byz3xCBN.js → Marketplace-s8MmWkS9.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-DOZUUW6z.js → McpTools-Wu-WRg4M.js} +3 -3
  40. package/src/assets/web-panel/assets/{Memory-C33wC2hA.js → Memory-B_i-eX9w.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-zZe-T_6M.js → MobileBridge-Ca64kjVx.js} +1 -1
  42. package/src/assets/web-panel/assets/{MobileProjects-CRnUIume.js → MobileProjects-Cq9AFiO4.js} +1 -1
  43. package/src/assets/web-panel/assets/{Mtc-C1xlRVAN.js → Mtc-DKvGmG3y.js} +4 -4
  44. package/src/assets/web-panel/assets/{MtcAudit-D0U07bIi.js → MtcAudit-BVvWx8pF.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-DF8uvV3h.js → Multisig-wqeJ2O9x.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-bBPGAFlt.js → NLProgramming-DX87ysYu.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-BHAaOsgg.js → Notes-ChenGdu0.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-Cl0fG_rA.js → NotificationSettings-BZRa68-x.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-BEPAs8Zv.js → OrderTableRenderer-DZ6xG1M6.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-BAxSwgk5.js → Organization-BWJp4VPX.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-D68KubAu.js → Overflow-BoM4bYt5.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-bhdT17zk.js → P2P-Cvi8YV09.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-DqaO6wgH.js → PdhVaultBrowser-CNVC1NIj.js} +3 -3
  54. package/src/assets/web-panel/assets/{Permissions-Bq8fvkak.js → Permissions-DNd1MRjW.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-BYd2JEic.js → PersonalDataHub-DGSBYZ5-.js} +5 -5
  56. package/src/assets/web-panel/assets/{Pipeline-Csg_ja69.js → Pipeline-DkcoGMBo.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-lwxwLj4M.js → Privacy-DltwvMAW.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-BdBZkH8z.js → ProjectInit-ChYbpHg8.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-ClWgFy-K.js → ProjectSettings-B8FWiHTJ.js} +2 -2
  60. package/src/assets/web-panel/assets/{Projects-Bu-qj8N1.js → Projects-DuyhtSm4.js} +1 -1
  61. package/src/assets/web-panel/assets/{Providers-DEjxrxw3.js → Providers-Bo18Tx_6.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-eccy-8Vi.js → QrScannerModal-6W85KlsG.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-Vx3uDvFg.js → QuickAsk-DznRUedP.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-CfUivNps.js → Recommend-CQDN3_p-.js} +1 -1
  65. package/src/assets/web-panel/assets/{RemoteSession-BU4gk7GI.js → RemoteSession-CiJgokEj.js} +3 -3
  66. package/src/assets/web-panel/assets/{Reputation-CbPzdZ0C.js → Reputation-DexzGH7E.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-CYLrgfKA.js → Row-BgZOIvSi.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-DbY1oyuv.js → RssFeed-BWIZJ_Jr.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-QeW41K5r.js → Search-B376EwWJ.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-CJxf1kLZ.js → Security-92mUR5OD.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-CFO9ySZc.js → Services-ClSEAOHk.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-CQFjeQN0.js → Skeleton-DVhLbv99.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-CLLB4INW.js → Skills-JTcXs_xI.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-DxeLIJk0.js → Sla-DnKY9zy9.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-D4FA9KYI.js → SpeechSettings-GO1JefAH.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-C6NOkcQK.js → SyncSettings-jX5tB2St.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-LmVPWDfQ.js → Tasks-BxRBzhUc.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-BdEfUoVB.js → Templates-CAVkbTG1.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-IUlESacN.js → Tenant-5Y7sHBkz.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-B9pDe7sn.js → Terminal-CbbLShYb.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-ZCwB-Pki.js → TimelineRenderer-2HptWihL.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-4qk16LX1.js → Tokens-B-jGxzHl.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-jXNyargn.js → Trigger-9DGa90DT.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-D13PydtT.js → Trust-BSJEkEOO.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-yPgws6mS.js → UkeySign-C807So5R.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-B329WjpG.js → VideoEditing-ByiieAv-.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-T8VM-Ttm.js → Wallet-BixbIOUv.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-XuRibrpP.js → WebAuthn-z7akhor4.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-D1Gwz3YR.js → WorkflowEditor-KvijuUuR.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-DjydtnT-.js → chat-BYKoh0YG.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-gFtBvPrr.js → colors-CLT8IYBt.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-CndxhGfx.js → compact-item-DlBIyYHF.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-DnfGpd0L.js → createContext-5XmAnNLr.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-BmcCIHwY.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-CmT5hRVW.js → hasIn-rPdRhm7K.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DoBKSzqu.js → index-8un-eUDI.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DGbKeg8G.js → index-B-0nAxf5.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DreYqebI.js → index-B1VfBUPB.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-zQf599Uq.js → index-BBt2CSAx.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BlTcxT_L.js → index-BDtlwjSr.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CqpR0Des.js → index-BIRl2Ii5.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-C3HvYeA3.js → index-BgevTkUv.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-B0WFjxWs.js → index-Bve7Wsgf.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BNHdO6Jr.js → index-Bzd0sFkp.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DV2PR3Fa.js → index-C2sFDVb_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-D2d7358Y.js → index-CErvHCDe.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DaEPE2DC.js → index-CM_a9spK.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DKyuE_Y2.js → index-CY6TMc2m.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BVM_w30N.js → index-ChlzaTV3.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CZLDbPTa.js → index-CsnbOKdI.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-HHP1zzo7.js → index-D3-NL-x-.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BFif4Cev.js → index-D3f9Jzx2.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-C14jryXi.js → index-DCDSycWo.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CB27echm.js → index-DIVrVGvf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BGlmPbl_.js → index-DI_tYFBe.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BsRKmb6k.js → index-DPS4mWnI.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BXNUTiW8.js → index-DTslLzPJ.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Dbpk75MO.js → index-DW8vozBS.js} +1 -1
  119. package/src/assets/web-panel/assets/index-DY8rmd6x.js +1 -0
  120. package/src/assets/web-panel/assets/{index-DjY-3sMA.js → index-DZiSMYoD.js} +3 -3
  121. package/src/assets/web-panel/assets/{index-DV6NrfJx.js → index-DZjGcIGU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-ktN-K1Tf.js → index-Dea32nOK.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DjcR-CwS.js → index-Djd7uqwM.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CuOx4Pbe.js → index-Dntid6oj.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BW3nWiu0.js → index-DqZU4_7J.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-C4Mqhmas.js → index-DuvweiCz.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CRqz8TtI.js → index-DzExCCLS.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-D5na0B7G.js → index-LKT-Ol0A.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-_-wGLtAg.js → index-akwXS-FF.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CgMKElUh.js → index-b-rQCMkx.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DUlubR4l.js → index-eHbr3f5I.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D88-8bsB.js → index-kx6zDWew.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DuAvYTmY.js → index-rRuCGdKW.js} +1 -1
  134. package/src/assets/web-panel/assets/index-sbwcUeRS.js +1 -0
  135. package/src/assets/web-panel/assets/{initDefaultProps-KV3V-PNH.js → initDefaultProps-a8411LiK.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-PFGQg7_X.js → motion-oVcQdpCm.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-Dnl79wq4.js → move-B-eyzzzL.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-Bwl5JH9V.js → mtc-parser-BCYIxuG7.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-DCcTtM1l.js → omit-DuFtWiYh.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-Cl6BjjDf.js → pickAttrs-CVAoJhGu.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-fdqhyo42.js → placementArrow-Y2iub2bO.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-DYQpmcDW.js → responsiveObserve-BHenWIVD.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-C4l-VfO4.js → slide-CKrMaL29.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-DYDw_dyZ.js → statusUtils-w8eb_1da.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-BEsubSMu.js → styleChecker-CCVi_Ww3.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-Cj82ggQ_.js → useFlexGapSupport-BsmR_q0r.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-B7L1eJ0V.js → useFs-a8GMBjnc.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-DVlJVD4d.js → usePersonalDataHub-BMUYSPn-.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-BBAbRN_Y.js → vnode-DL2pI31V.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-BYn48q-I.js → zoom-Cbi8fISi.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/data/changelog.json +33 -7
  153. package/src/lib/dependency-install-policy.js +1 -1
  154. package/src/lib/evolution/browser-download-action-authority.js +747 -0
  155. package/src/lib/evolution/browser-download-artifact-disposal-authority.js +436 -0
  156. package/src/lib/evolution/browser-filesystem-quarantine-custody.js +2453 -0
  157. package/src/lib/evolution/browser-filesystem-quarantine-disposal.js +36 -0
  158. package/src/lib/evolution/browser-keyboard-action-authority.js +560 -0
  159. package/src/lib/evolution/browser-navigation-action-authority.js +546 -0
  160. package/src/lib/evolution/browser-quarantine-lock-maintenance-authority.js +573 -0
  161. package/src/lib/evolution/browser-quarantine-operator-revocation-authority.js +442 -0
  162. package/src/lib/evolution/browser-quarantine-retention-authority.js +503 -0
  163. package/src/lib/evolution/browser-quarantine-retention-scheduler.js +207 -0
  164. package/src/lib/evolution/browser-quarantined-download-executor.js +525 -0
  165. package/src/lib/evolution/browser-tab-open-action-authority.js +491 -0
  166. package/src/lib/evolution/browser-vision-action-authority.js +444 -0
  167. package/src/lib/evolution/browser-vision-observation-authority.js +304 -0
  168. package/src/lib/evolution/evolution-deployment-loader.js +241 -1
  169. package/src/lib/evolution/evolution-eval-child-evidence-ledger-adapter.js +5 -0
  170. package/src/lib/evolution/evolution-eval-gate.js +2 -1
  171. package/src/lib/evolution/evolution-eval-process-supervisor-worker.mjs +71 -9
  172. package/src/lib/evolution/evolution-eval-process-supervisor.js +276 -9
  173. package/src/lib/evolution/evolution-workbench-metrics.js +81 -21
  174. package/src/lib/evolution/pm-exploration-benchmark.js +747 -0
  175. package/src/lib/evolution/pm-exploration-budget-executor.js +106 -9
  176. package/src/lib/evolution/pm-exploration-egress-authority.js +382 -0
  177. package/src/lib/evolution/pm-exploration-evidence-bundle.js +149 -44
  178. package/src/lib/evolution/pm-exploration-execution-host.js +1254 -8
  179. package/src/lib/evolution/pm-exploration-process-grader.js +458 -0
  180. package/src/lib/evolution/pm-exploration-process-reviewer.js +456 -0
  181. package/src/lib/evolution/pm-exploration-process-runner.js +500 -0
  182. package/src/lib/evolution/pm-exploration-receipts.js +211 -11
  183. package/src/lib/evolution/pm-exploration-recovery-snapshot-store.js +465 -46
  184. package/src/lib/evolution/pm-exploration-transition-committer.js +185 -34
  185. package/src/lib/evolution/skill-outcome-index-authority.js +7 -3
  186. package/src/lib/evolution/skill-writer-inventory-manifest.js +0 -39
  187. package/src/lib/evolution/volcengine-function-execution-authority.js +2949 -0
  188. package/src/lib/evolution/volcengine-function-process-executor.js +615 -0
  189. package/src/lib/evolution/volcengine-function-replay-store.js +836 -0
  190. package/src/lib/evolution/volcengine-function-revocation-status-floor-store.js +480 -0
  191. package/src/lib/governance-coverage.js +1 -1
  192. package/src/lib/headless-manifest.js +1 -1
  193. package/src/lib/protocol-replay.js +1 -1
  194. package/src/lib/skill-outcome-transcript-authority.js +45 -5
  195. package/src/runtime/agent-core.js +17 -0
  196. package/src/assets/web-panel/assets/ChatBubbleRenderer-Cf3LLgDc.js +0 -1
  197. package/src/assets/web-panel/assets/MarkdownRenderer-CTsYo9NN.js +0 -1
  198. package/src/assets/web-panel/assets/devWarning-D60SbiD-.js +0 -1
  199. package/src/assets/web-panel/assets/index-C0yR4_7h.js +0 -1
  200. package/src/assets/web-panel/assets/index-D4xuvo03.js +0 -1
@@ -0,0 +1,573 @@
1
+ import { createHash } from "node:crypto";
2
+ import { types } from "node:util";
3
+
4
+ import {
5
+ BROWSER_FILESYSTEM_QUARANTINE_LOCK_DIAGNOSTIC_SCHEMA,
6
+ BROWSER_FILESYSTEM_QUARANTINE_LOCK_RELEASE_ACK_SCHEMA,
7
+ captureBrowserFilesystemQuarantineCustody,
8
+ } from "./browser-filesystem-quarantine-custody.js";
9
+ export { BROWSER_FILESYSTEM_QUARANTINE_LOCK_MAINTENANCE_DESCRIPTOR_SCHEMA } from "./browser-filesystem-quarantine-custody.js";
10
+
11
+ export const BROWSER_QUARANTINE_LOCK_MAINTENANCE_REQUEST_SCHEMA =
12
+ "chainlesschain.browser-quarantine-lock-maintenance-request/v1";
13
+ export const BROWSER_QUARANTINE_LOCK_MAINTENANCE_RECEIPT_SCHEMA =
14
+ "chainlesschain.browser-quarantine-lock-maintenance-receipt/v1";
15
+ export const BROWSER_QUARANTINE_LOCK_MAINTENANCE_OUTCOME_REQUEST_SCHEMA =
16
+ "chainlesschain.browser-quarantine-lock-maintenance-outcome-request/v1";
17
+ export const BROWSER_QUARANTINE_LOCK_MAINTENANCE_OUTCOME_ACK_SCHEMA =
18
+ "chainlesschain.browser-quarantine-lock-maintenance-outcome-ack/v1";
19
+ export const BROWSER_QUARANTINE_LOCK_MAINTENANCE_RESULT_SCHEMA =
20
+ "chainlesschain.browser-quarantine-lock-maintenance-result/v1";
21
+
22
+ const DIGEST = /^sha256:[a-f0-9]{64}$/u;
23
+ const ID = /^[A-Za-z0-9._:-]{1,128}$/u;
24
+ const ARTIFACT_REF = /^quarantine:[A-Za-z0-9][A-Za-z0-9._-]{0,95}$/u;
25
+ const LOCK_STATUSES = new Set([
26
+ "absent",
27
+ "owned-live",
28
+ "owned-dead",
29
+ "owned-invalid",
30
+ "owner-initializing",
31
+ "owner-orphaned",
32
+ ]);
33
+ const LOCK_OPERATIONS = new Set([
34
+ "write",
35
+ "scan",
36
+ "complete",
37
+ "dispose",
38
+ "recover",
39
+ ]);
40
+ const authorities = new WeakMap();
41
+
42
+ function canonical(value) {
43
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
44
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
45
+ return `{${Object.keys(value)
46
+ .sort()
47
+ .map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
48
+ .join(",")}}`;
49
+ }
50
+
51
+ function digest(domain, value) {
52
+ return `sha256:${createHash("sha256")
53
+ .update(`${domain}\0`)
54
+ .update(canonical(value))
55
+ .digest("hex")}`;
56
+ }
57
+
58
+ function exact(value, keys, label) {
59
+ if (
60
+ !value ||
61
+ typeof value !== "object" ||
62
+ Array.isArray(value) ||
63
+ types.isProxy(value) ||
64
+ ![Object.prototype, null].includes(Object.getPrototypeOf(value)) ||
65
+ Reflect.ownKeys(value).length !== keys.length ||
66
+ keys.some((key) => {
67
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
68
+ return !descriptor?.enumerable || !("value" in descriptor);
69
+ })
70
+ )
71
+ throw new TypeError(`${label} has unexpected or accessor fields`);
72
+ }
73
+
74
+ function snapshotJson(value, label) {
75
+ const visit = (entry, depth) => {
76
+ if (depth > 8) throw new TypeError(`${label} exceeds its depth budget`);
77
+ if (
78
+ entry === null ||
79
+ typeof entry === "string" ||
80
+ typeof entry === "boolean" ||
81
+ (typeof entry === "number" && Number.isFinite(entry))
82
+ )
83
+ return entry;
84
+ if (
85
+ !entry ||
86
+ typeof entry !== "object" ||
87
+ types.isProxy(entry) ||
88
+ ![Object.prototype, null, Array.prototype].includes(
89
+ Object.getPrototypeOf(entry),
90
+ )
91
+ )
92
+ throw new TypeError(`${label} must be finite plain JSON data`);
93
+ if (Array.isArray(entry))
94
+ return Object.freeze(entry.map((item) => visit(item, depth + 1)));
95
+ const result = {};
96
+ for (const key of Object.keys(entry)) {
97
+ const descriptor = Object.getOwnPropertyDescriptor(entry, key);
98
+ if (!descriptor?.enumerable || !("value" in descriptor))
99
+ throw new TypeError(`${label} must contain plain data`);
100
+ result[key] = visit(descriptor.value, depth + 1);
101
+ }
102
+ return Object.freeze(result);
103
+ };
104
+ const result = visit(value, 0);
105
+ if (Buffer.byteLength(canonical(result), "utf8") > 16 * 1024)
106
+ throw new TypeError(`${label} exceeds its byte budget`);
107
+ return result;
108
+ }
109
+
110
+ function normalizeRequest(value) {
111
+ exact(
112
+ value,
113
+ [
114
+ "schema",
115
+ "requestId",
116
+ "operation",
117
+ "artifactRef",
118
+ "expectedLockStateDigest",
119
+ "operatorIdDigest",
120
+ "authorization",
121
+ "requestedAt",
122
+ ],
123
+ "operator lock maintenance request",
124
+ );
125
+ if (
126
+ value.schema !== BROWSER_QUARANTINE_LOCK_MAINTENANCE_REQUEST_SCHEMA ||
127
+ !ID.test(value.requestId) ||
128
+ !["inspect", "release"].includes(value.operation) ||
129
+ !ARTIFACT_REF.test(value.artifactRef) ||
130
+ (value.operation === "inspect"
131
+ ? value.expectedLockStateDigest !== null
132
+ : !DIGEST.test(value.expectedLockStateDigest)) ||
133
+ !DIGEST.test(value.operatorIdDigest) ||
134
+ !Number.isFinite(Date.parse(value.requestedAt))
135
+ )
136
+ throw new TypeError("operator lock maintenance request is invalid");
137
+ return Object.freeze({
138
+ ...value,
139
+ authorization: snapshotJson(
140
+ value.authorization,
141
+ "operator lock maintenance authorization",
142
+ ),
143
+ });
144
+ }
145
+
146
+ function normalizeDecision(value, nowMs, maxGrantTtlMs) {
147
+ if (
148
+ !value ||
149
+ typeof value !== "object" ||
150
+ Array.isArray(value) ||
151
+ types.isProxy(value) ||
152
+ ![Object.prototype, null].includes(Object.getPrototypeOf(value))
153
+ )
154
+ throw new TypeError("operator lock maintenance decision is invalid");
155
+ if (value.decision === "deny") {
156
+ exact(value, ["decision", "reason"], "operator lock maintenance denial");
157
+ if (
158
+ typeof value.reason !== "string" ||
159
+ value.reason.length < 1 ||
160
+ value.reason.length > 512
161
+ )
162
+ throw new TypeError("operator lock maintenance denial is invalid");
163
+ return Object.freeze({ ...value });
164
+ }
165
+ exact(
166
+ value,
167
+ ["decision", "operatorEvidenceRef", "validUntil"],
168
+ "operator lock maintenance decision",
169
+ );
170
+ const validUntilMs = Date.parse(value.validUntil);
171
+ if (
172
+ value.decision !== "allow" ||
173
+ typeof value.operatorEvidenceRef !== "string" ||
174
+ value.operatorEvidenceRef.length < 1 ||
175
+ value.operatorEvidenceRef.length > 512 ||
176
+ !Number.isFinite(validUntilMs) ||
177
+ validUntilMs <= nowMs ||
178
+ validUntilMs > nowMs + maxGrantTtlMs
179
+ )
180
+ throw new Error("operator lock maintenance decision is invalid");
181
+ return Object.freeze({ ...value, validUntilMs });
182
+ }
183
+
184
+ function normalizeDiagnostic(value, descriptor, artifactRef) {
185
+ exact(
186
+ value,
187
+ [
188
+ "schema",
189
+ "custodyId",
190
+ "tenantId",
191
+ "handlerArtifactDigest",
192
+ "artifactRefDigest",
193
+ "status",
194
+ "ownerOperation",
195
+ "ownerPid",
196
+ "ownerAcquiredAt",
197
+ "ownerEvidenceDigest",
198
+ "lockDirectoryIdentityDigest",
199
+ "observedAt",
200
+ "lockStateDigest",
201
+ ],
202
+ "operator lock diagnostic",
203
+ );
204
+ const artifactRefDigest = digest(
205
+ "chainlesschain.browser-download-artifact-ref/v1",
206
+ artifactRef,
207
+ );
208
+ const hasOwner = ["owned-live", "owned-dead"].includes(value.status);
209
+ const absent = value.status === "absent";
210
+ const stateCore = Object.freeze({
211
+ custodyId: value.custodyId,
212
+ tenantId: value.tenantId,
213
+ handlerArtifactDigest: value.handlerArtifactDigest,
214
+ artifactRefDigest: value.artifactRefDigest,
215
+ lockDirectoryIdentityDigest: value.lockDirectoryIdentityDigest,
216
+ ownerEvidenceDigest: value.ownerEvidenceDigest,
217
+ });
218
+ if (
219
+ value.schema !== BROWSER_FILESYSTEM_QUARANTINE_LOCK_DIAGNOSTIC_SCHEMA ||
220
+ !ID.test(value.custodyId) ||
221
+ value.tenantId !== descriptor.tenantId ||
222
+ value.handlerArtifactDigest !== descriptor.handlerArtifactDigest ||
223
+ value.artifactRefDigest !== artifactRefDigest ||
224
+ !LOCK_STATUSES.has(value.status) ||
225
+ (hasOwner
226
+ ? !LOCK_OPERATIONS.has(value.ownerOperation) ||
227
+ !Number.isSafeInteger(value.ownerPid) ||
228
+ value.ownerPid < 1 ||
229
+ !Number.isFinite(Date.parse(value.ownerAcquiredAt))
230
+ : value.ownerOperation !== null ||
231
+ value.ownerPid !== null ||
232
+ value.ownerAcquiredAt !== null) ||
233
+ (absent
234
+ ? value.ownerEvidenceDigest !== null ||
235
+ value.lockDirectoryIdentityDigest !== null
236
+ : !DIGEST.test(value.ownerEvidenceDigest) ||
237
+ !DIGEST.test(value.lockDirectoryIdentityDigest)) ||
238
+ !Number.isFinite(Date.parse(value.observedAt)) ||
239
+ value.lockStateDigest !==
240
+ digest(BROWSER_FILESYSTEM_QUARANTINE_LOCK_DIAGNOSTIC_SCHEMA, stateCore)
241
+ )
242
+ throw new Error("operator lock diagnostic is invalid");
243
+ return Object.freeze({ ...value });
244
+ }
245
+
246
+ function normalizeReleaseAck(
247
+ value,
248
+ descriptor,
249
+ request,
250
+ receiptDigest,
251
+ requestDigest,
252
+ ) {
253
+ exact(
254
+ value,
255
+ [
256
+ "schema",
257
+ "custodyId",
258
+ "authorityId",
259
+ "tenantId",
260
+ "handlerArtifactDigest",
261
+ "policyRevision",
262
+ "actionReceiptDigest",
263
+ "requestDigest",
264
+ "artifactRefDigest",
265
+ "releasedLockStateDigest",
266
+ "releasedAt",
267
+ "releaseReceiptDigest",
268
+ "authenticated",
269
+ "durable",
270
+ "readbackVerified",
271
+ "artifactBytesChanged",
272
+ "qualifiesForPromotion",
273
+ ],
274
+ "operator lock release acknowledgement",
275
+ );
276
+ const core = Object.freeze({
277
+ schema: value.schema,
278
+ custodyId: value.custodyId,
279
+ authorityId: value.authorityId,
280
+ tenantId: value.tenantId,
281
+ handlerArtifactDigest: value.handlerArtifactDigest,
282
+ policyRevision: value.policyRevision,
283
+ actionReceiptDigest: value.actionReceiptDigest,
284
+ requestDigest: value.requestDigest,
285
+ artifactRefDigest: value.artifactRefDigest,
286
+ releasedLockStateDigest: value.releasedLockStateDigest,
287
+ releasedAt: value.releasedAt,
288
+ });
289
+ if (
290
+ value.schema !== BROWSER_FILESYSTEM_QUARANTINE_LOCK_RELEASE_ACK_SCHEMA ||
291
+ !ID.test(value.custodyId) ||
292
+ value.authorityId !== descriptor.authorityId ||
293
+ value.tenantId !== descriptor.tenantId ||
294
+ value.handlerArtifactDigest !== descriptor.handlerArtifactDigest ||
295
+ value.policyRevision !== descriptor.policyRevision ||
296
+ value.actionReceiptDigest !== receiptDigest ||
297
+ value.requestDigest !== requestDigest ||
298
+ value.artifactRefDigest !==
299
+ digest(
300
+ "chainlesschain.browser-download-artifact-ref/v1",
301
+ request.artifactRef,
302
+ ) ||
303
+ value.releasedLockStateDigest !== request.expectedLockStateDigest ||
304
+ !Number.isFinite(Date.parse(value.releasedAt)) ||
305
+ value.releaseReceiptDigest !==
306
+ digest(BROWSER_FILESYSTEM_QUARANTINE_LOCK_RELEASE_ACK_SCHEMA, core) ||
307
+ value.authenticated !== true ||
308
+ value.durable !== true ||
309
+ value.readbackVerified !== true ||
310
+ value.artifactBytesChanged !== false ||
311
+ value.qualifiesForPromotion !== false
312
+ )
313
+ throw new Error("operator lock release acknowledgement is invalid");
314
+ return Object.freeze({ ...value });
315
+ }
316
+
317
+ function normalizeOutcomeAck(value, descriptor, request) {
318
+ exact(
319
+ value,
320
+ [
321
+ "schema",
322
+ "authorityId",
323
+ "tenantId",
324
+ "handlerArtifactDigest",
325
+ "maintenanceReceiptDigest",
326
+ "outcomeRequestDigest",
327
+ "auditEventDigest",
328
+ "durabilityReceiptDigest",
329
+ "authenticated",
330
+ "durable",
331
+ "readbackVerified",
332
+ "qualifiesForPromotion",
333
+ ],
334
+ "operator lock maintenance outcome acknowledgement",
335
+ );
336
+ if (
337
+ value.schema !== BROWSER_QUARANTINE_LOCK_MAINTENANCE_OUTCOME_ACK_SCHEMA ||
338
+ value.authorityId !== descriptor.authorityId ||
339
+ value.tenantId !== descriptor.tenantId ||
340
+ value.handlerArtifactDigest !== descriptor.handlerArtifactDigest ||
341
+ value.maintenanceReceiptDigest !== request.maintenanceReceiptDigest ||
342
+ value.outcomeRequestDigest !== request.outcomeRequestDigest ||
343
+ !DIGEST.test(value.auditEventDigest) ||
344
+ !DIGEST.test(value.durabilityReceiptDigest) ||
345
+ value.authenticated !== true ||
346
+ value.durable !== true ||
347
+ value.readbackVerified !== true ||
348
+ value.qualifiesForPromotion !== false
349
+ )
350
+ throw new Error(
351
+ "operator lock maintenance outcome acknowledgement is invalid",
352
+ );
353
+ return Object.freeze({ ...value });
354
+ }
355
+
356
+ export function createBrowserQuarantineLockMaintenanceAuthority(options) {
357
+ exact(
358
+ options,
359
+ ["descriptor", "custody", "authorizeMaintenance", "recordOutcome", "now"],
360
+ "browser quarantine lock maintenance authority",
361
+ );
362
+ const custody = captureBrowserFilesystemQuarantineCustody(options.custody);
363
+ const maintenance = custody.bindLockMaintenanceAuthority(options.descriptor);
364
+ for (const [name, port] of Object.entries({
365
+ authorizeMaintenance: options.authorizeMaintenance,
366
+ recordOutcome: options.recordOutcome,
367
+ now: options.now,
368
+ })) {
369
+ if (typeof port !== "function" || types.isProxy(port))
370
+ throw new TypeError(`operator lock maintenance ${name} port is invalid`);
371
+ }
372
+ const authority = Object.freeze({});
373
+ authorities.set(authority, {
374
+ descriptor: Object.freeze({ ...options.descriptor }),
375
+ inspectLock: maintenance.inspectLock,
376
+ releaseLock: maintenance.releaseLock,
377
+ authorizeMaintenance: options.authorizeMaintenance,
378
+ recordOutcome: options.recordOutcome,
379
+ now: options.now,
380
+ });
381
+ return authority;
382
+ }
383
+
384
+ export function captureBrowserQuarantineLockMaintenanceAuthority(value) {
385
+ const state = authorities.get(value);
386
+ if (!state)
387
+ throw new TypeError(
388
+ "A branded browser quarantine lock maintenance authority is required",
389
+ );
390
+ return Object.freeze({
391
+ descriptor: state.descriptor,
392
+ maintainLock: async (input) => {
393
+ const request = normalizeRequest(input);
394
+ const nowMs = state.now();
395
+ if (!Number.isFinite(nowMs))
396
+ throw new Error("operator lock maintenance clock is invalid");
397
+ const artifactRefDigest = digest(
398
+ "chainlesschain.browser-download-artifact-ref/v1",
399
+ request.artifactRef,
400
+ );
401
+ const authorizationDigest = digest(
402
+ "chainlesschain.browser-quarantine-lock-maintenance-authorization/v1",
403
+ request.authorization,
404
+ );
405
+ const requestCore = Object.freeze({
406
+ schema: BROWSER_QUARANTINE_LOCK_MAINTENANCE_REQUEST_SCHEMA,
407
+ requestId: request.requestId,
408
+ operation: request.operation,
409
+ artifactRefDigest,
410
+ expectedLockStateDigest: request.expectedLockStateDigest,
411
+ operatorIdDigest: request.operatorIdDigest,
412
+ authorizationDigest,
413
+ requestedAt: request.requestedAt,
414
+ });
415
+ const requestDigest = digest(
416
+ BROWSER_QUARANTINE_LOCK_MAINTENANCE_REQUEST_SCHEMA,
417
+ requestCore,
418
+ );
419
+ const decision = normalizeDecision(
420
+ await state.authorizeMaintenance(
421
+ Object.freeze({
422
+ ...requestCore,
423
+ requestDigest,
424
+ authorization: request.authorization,
425
+ }),
426
+ ),
427
+ nowMs,
428
+ state.descriptor.maxGrantTtlMs,
429
+ );
430
+ if (decision.decision === "deny") {
431
+ const error = new Error(decision.reason);
432
+ error.code = "BROWSER_QUARANTINE_LOCK_MAINTENANCE_DENIED";
433
+ throw error;
434
+ }
435
+ const receiptCore = Object.freeze({
436
+ schema: BROWSER_QUARANTINE_LOCK_MAINTENANCE_RECEIPT_SCHEMA,
437
+ authorityId: state.descriptor.authorityId,
438
+ tenantId: state.descriptor.tenantId,
439
+ handlerArtifactDigest: state.descriptor.handlerArtifactDigest,
440
+ policyRevision: state.descriptor.policyRevision,
441
+ requestId: request.requestId,
442
+ operation: request.operation,
443
+ artifactRefDigest,
444
+ expectedLockStateDigest: request.expectedLockStateDigest,
445
+ operatorIdDigest: request.operatorIdDigest,
446
+ requestDigest,
447
+ operatorEvidenceRef: decision.operatorEvidenceRef,
448
+ authorizedAt: new Date(nowMs).toISOString(),
449
+ validUntil: decision.validUntil,
450
+ });
451
+ const receiptDigest = digest(
452
+ BROWSER_QUARANTINE_LOCK_MAINTENANCE_RECEIPT_SCHEMA,
453
+ receiptCore,
454
+ );
455
+ let diagnostic = null;
456
+ let release = null;
457
+ let executionError = null;
458
+ try {
459
+ const executionMs = state.now();
460
+ if (
461
+ !Number.isFinite(executionMs) ||
462
+ executionMs >= decision.validUntilMs
463
+ )
464
+ throw new Error(
465
+ "operator lock maintenance grant expired before execution",
466
+ );
467
+ diagnostic = normalizeDiagnostic(
468
+ await state.inspectLock(request.artifactRef),
469
+ state.descriptor,
470
+ request.artifactRef,
471
+ );
472
+ if (request.operation === "release") {
473
+ if (diagnostic.lockStateDigest !== request.expectedLockStateDigest)
474
+ throw new Error("operator lock maintenance target changed");
475
+ release = normalizeReleaseAck(
476
+ await state.releaseLock({
477
+ actionReceiptDigest: receiptDigest,
478
+ requestDigest,
479
+ artifactRef: request.artifactRef,
480
+ expectedLockStateDigest: request.expectedLockStateDigest,
481
+ }),
482
+ state.descriptor,
483
+ request,
484
+ receiptDigest,
485
+ requestDigest,
486
+ );
487
+ }
488
+ } catch (error) {
489
+ executionError = error;
490
+ }
491
+ const recordedAtMs = state.now();
492
+ if (!Number.isFinite(recordedAtMs))
493
+ throw new Error("operator lock maintenance clock is invalid");
494
+ const outcomeCore = Object.freeze({
495
+ schema: BROWSER_QUARANTINE_LOCK_MAINTENANCE_OUTCOME_REQUEST_SCHEMA,
496
+ authorityId: state.descriptor.authorityId,
497
+ tenantId: state.descriptor.tenantId,
498
+ handlerArtifactDigest: state.descriptor.handlerArtifactDigest,
499
+ policyRevision: state.descriptor.policyRevision,
500
+ maintenanceReceiptDigest: receiptDigest,
501
+ requestDigest,
502
+ operation: request.operation,
503
+ artifactRefDigest,
504
+ operatorIdDigest: request.operatorIdDigest,
505
+ status: executionError === null ? "succeeded" : "failed",
506
+ lockStatus: diagnostic?.status ?? null,
507
+ lockStateDigest: diagnostic?.lockStateDigest ?? null,
508
+ releaseReceiptDigest: release?.releaseReceiptDigest ?? null,
509
+ failureDigest:
510
+ executionError === null
511
+ ? null
512
+ : digest(
513
+ "chainlesschain.browser-quarantine-lock-maintenance-failure/v1",
514
+ {
515
+ name: executionError?.name ?? "Error",
516
+ code: executionError?.code ?? null,
517
+ },
518
+ ),
519
+ recordedAt: new Date(recordedAtMs).toISOString(),
520
+ });
521
+ const outcomeRequest = Object.freeze({
522
+ ...outcomeCore,
523
+ outcomeRequestDigest: digest(
524
+ BROWSER_QUARANTINE_LOCK_MAINTENANCE_OUTCOME_REQUEST_SCHEMA,
525
+ outcomeCore,
526
+ ),
527
+ });
528
+ const outcomeAck = normalizeOutcomeAck(
529
+ await state.recordOutcome(outcomeRequest),
530
+ state.descriptor,
531
+ outcomeRequest,
532
+ );
533
+ if (executionError !== null) {
534
+ const uncertain = new Error(
535
+ "operator lock maintenance execution failed",
536
+ { cause: executionError },
537
+ );
538
+ uncertain.code = "BROWSER_QUARANTINE_LOCK_MAINTENANCE_FAILED";
539
+ throw uncertain;
540
+ }
541
+ const ownerProcessDigest =
542
+ diagnostic.ownerPid === null
543
+ ? null
544
+ : digest("chainlesschain.browser-quarantine-lock-owner-process/v1", {
545
+ pid: diagnostic.ownerPid,
546
+ acquiredAt: diagnostic.ownerAcquiredAt,
547
+ });
548
+ const resultCore = Object.freeze({
549
+ schema: BROWSER_QUARANTINE_LOCK_MAINTENANCE_RESULT_SCHEMA,
550
+ status: request.operation === "release" ? "released" : "inspected",
551
+ operation: request.operation,
552
+ artifactRefDigest,
553
+ lockStatus: diagnostic.status,
554
+ ownerOperation: diagnostic.ownerOperation,
555
+ ownerProcessDigest,
556
+ ownerAcquiredAt: diagnostic.ownerAcquiredAt,
557
+ lockStateDigest: diagnostic.lockStateDigest,
558
+ releaseReceiptDigest: release?.releaseReceiptDigest ?? null,
559
+ operatorIdDigest: request.operatorIdDigest,
560
+ outcomeRequestDigest: outcomeRequest.outcomeRequestDigest,
561
+ auditEventDigest: outcomeAck.auditEventDigest,
562
+ durabilityReceiptDigest: outcomeAck.durabilityReceiptDigest,
563
+ });
564
+ return Object.freeze({
565
+ ...resultCore,
566
+ resultDigest: digest(
567
+ BROWSER_QUARANTINE_LOCK_MAINTENANCE_RESULT_SCHEMA,
568
+ resultCore,
569
+ ),
570
+ });
571
+ },
572
+ });
573
+ }