clinkx 0.2.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (574) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +10 -0
  3. package/README.md +113 -18
  4. package/clinkx-workflows/dist/allowed-roots.d.ts +1 -0
  5. package/clinkx-workflows/dist/allowed-roots.js +5 -0
  6. package/clinkx-workflows/dist/allowed-roots.js.map +1 -0
  7. package/clinkx-workflows/dist/artifacts.d.ts +20 -1
  8. package/clinkx-workflows/dist/artifacts.js +38 -9
  9. package/clinkx-workflows/dist/artifacts.js.map +1 -1
  10. package/clinkx-workflows/dist/backend.d.ts +4 -0
  11. package/clinkx-workflows/dist/citation-check.d.ts +40 -0
  12. package/clinkx-workflows/dist/citation-check.js +348 -0
  13. package/clinkx-workflows/dist/citation-check.js.map +1 -0
  14. package/clinkx-workflows/dist/clink-client.d.ts +2 -1
  15. package/clinkx-workflows/dist/clink-client.js +17 -4
  16. package/clinkx-workflows/dist/clink-client.js.map +1 -1
  17. package/clinkx-workflows/dist/config.d.ts +145 -16
  18. package/clinkx-workflows/dist/config.js +384 -26
  19. package/clinkx-workflows/dist/config.js.map +1 -1
  20. package/clinkx-workflows/dist/contained-file.d.ts +172 -0
  21. package/clinkx-workflows/dist/contained-file.js +483 -0
  22. package/clinkx-workflows/dist/contained-file.js.map +1 -0
  23. package/clinkx-workflows/dist/context-builder-lifecycle-contract.d.ts +416 -0
  24. package/clinkx-workflows/dist/context-builder-lifecycle-contract.js +328 -0
  25. package/clinkx-workflows/dist/context-builder-lifecycle-contract.js.map +1 -0
  26. package/clinkx-workflows/dist/context-builder-lifecycle-router.d.ts +24 -0
  27. package/clinkx-workflows/dist/context-builder-lifecycle-router.js +39 -0
  28. package/clinkx-workflows/dist/context-builder-lifecycle-router.js.map +1 -0
  29. package/clinkx-workflows/dist/context-cache-key.d.ts +53 -0
  30. package/clinkx-workflows/dist/context-cache-key.js +91 -0
  31. package/clinkx-workflows/dist/context-cache-key.js.map +1 -0
  32. package/clinkx-workflows/dist/context-mode-resolver.d.ts +27 -0
  33. package/clinkx-workflows/dist/context-mode-resolver.js +126 -0
  34. package/clinkx-workflows/dist/context-mode-resolver.js.map +1 -0
  35. package/clinkx-workflows/dist/context-preflight.d.ts +184 -0
  36. package/clinkx-workflows/dist/context-preflight.js +91 -0
  37. package/clinkx-workflows/dist/context-preflight.js.map +1 -0
  38. package/clinkx-workflows/dist/council-expander.d.ts +1 -1
  39. package/clinkx-workflows/dist/council-expander.js +2 -1
  40. package/clinkx-workflows/dist/council-expander.js.map +1 -1
  41. package/clinkx-workflows/dist/dashboard/activity-contract.d.ts +165 -0
  42. package/clinkx-workflows/dist/dashboard/activity-contract.js +105 -0
  43. package/clinkx-workflows/dist/dashboard/activity-contract.js.map +1 -0
  44. package/clinkx-workflows/dist/dashboard/activity-lease.d.ts +25 -0
  45. package/clinkx-workflows/dist/dashboard/activity-lease.js +34 -0
  46. package/clinkx-workflows/dist/dashboard/activity-lease.js.map +1 -0
  47. package/clinkx-workflows/dist/dashboard/activity-reader.d.ts +86 -0
  48. package/clinkx-workflows/dist/dashboard/activity-reader.js +480 -0
  49. package/clinkx-workflows/dist/dashboard/activity-reader.js.map +1 -0
  50. package/clinkx-workflows/dist/dashboard/api-routes.d.ts +36 -0
  51. package/clinkx-workflows/dist/dashboard/api-routes.js +1047 -0
  52. package/clinkx-workflows/dist/dashboard/api-routes.js.map +1 -0
  53. package/clinkx-workflows/dist/dashboard/artifact-index.d.ts +37 -0
  54. package/clinkx-workflows/dist/dashboard/artifact-index.js +145 -0
  55. package/clinkx-workflows/dist/dashboard/artifact-index.js.map +1 -0
  56. package/clinkx-workflows/dist/dashboard/auth/challenge-store.d.ts +31 -0
  57. package/clinkx-workflows/dist/dashboard/auth/challenge-store.js +65 -0
  58. package/clinkx-workflows/dist/dashboard/auth/challenge-store.js.map +1 -0
  59. package/clinkx-workflows/dist/dashboard/auth/controller.d.ts +26 -0
  60. package/clinkx-workflows/dist/dashboard/auth/controller.js +596 -0
  61. package/clinkx-workflows/dist/dashboard/auth/controller.js.map +1 -0
  62. package/clinkx-workflows/dist/dashboard/auth/credential-store.d.ts +60 -0
  63. package/clinkx-workflows/dist/dashboard/auth/credential-store.js +776 -0
  64. package/clinkx-workflows/dist/dashboard/auth/credential-store.js.map +1 -0
  65. package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.d.ts +9 -0
  66. package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.js +44 -0
  67. package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.js.map +1 -0
  68. package/clinkx-workflows/dist/dashboard/auth/session-store.d.ts +17 -0
  69. package/clinkx-workflows/dist/dashboard/auth/session-store.js +77 -0
  70. package/clinkx-workflows/dist/dashboard/auth/session-store.js.map +1 -0
  71. package/clinkx-workflows/dist/dashboard/auth/webauthn-service.d.ts +25 -0
  72. package/clinkx-workflows/dist/dashboard/auth/webauthn-service.js +71 -0
  73. package/clinkx-workflows/dist/dashboard/auth/webauthn-service.js.map +1 -0
  74. package/clinkx-workflows/dist/dashboard/context-run-liveness.d.ts +37 -0
  75. package/clinkx-workflows/dist/dashboard/context-run-liveness.js +49 -0
  76. package/clinkx-workflows/dist/dashboard/context-run-liveness.js.map +1 -0
  77. package/clinkx-workflows/dist/dashboard/context-run-reader.d.ts +222 -0
  78. package/clinkx-workflows/dist/dashboard/context-run-reader.js +1178 -0
  79. package/clinkx-workflows/dist/dashboard/context-run-reader.js.map +1 -0
  80. package/clinkx-workflows/dist/dashboard/contracts.d.ts +8936 -0
  81. package/clinkx-workflows/dist/dashboard/contracts.js +1157 -0
  82. package/clinkx-workflows/dist/dashboard/contracts.js.map +1 -0
  83. package/clinkx-workflows/dist/dashboard/generation.d.ts +14 -0
  84. package/clinkx-workflows/dist/dashboard/generation.js +41 -0
  85. package/clinkx-workflows/dist/dashboard/generation.js.map +1 -0
  86. package/clinkx-workflows/dist/dashboard/index.d.ts +28 -0
  87. package/clinkx-workflows/dist/dashboard/index.js +16 -0
  88. package/clinkx-workflows/dist/dashboard/index.js.map +1 -0
  89. package/clinkx-workflows/dist/dashboard/lazy-content.d.ts +101 -0
  90. package/clinkx-workflows/dist/dashboard/lazy-content.js +748 -0
  91. package/clinkx-workflows/dist/dashboard/lazy-content.js.map +1 -0
  92. package/clinkx-workflows/dist/dashboard/progress-report-contract.d.ts +303 -0
  93. package/clinkx-workflows/dist/dashboard/progress-report-contract.js +221 -0
  94. package/clinkx-workflows/dist/dashboard/progress-report-contract.js.map +1 -0
  95. package/clinkx-workflows/dist/dashboard/progress-report-reader.d.ts +50 -0
  96. package/clinkx-workflows/dist/dashboard/progress-report-reader.js +581 -0
  97. package/clinkx-workflows/dist/dashboard/progress-report-reader.js.map +1 -0
  98. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.d.ts +89 -0
  99. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.js +71 -0
  100. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.js.map +1 -0
  101. package/clinkx-workflows/dist/dashboard/progress-report-status-store.d.ts +28 -0
  102. package/clinkx-workflows/dist/dashboard/progress-report-status-store.js +110 -0
  103. package/clinkx-workflows/dist/dashboard/progress-report-status-store.js.map +1 -0
  104. package/clinkx-workflows/dist/dashboard/read-model.d.ts +86 -0
  105. package/clinkx-workflows/dist/dashboard/read-model.js +440 -0
  106. package/clinkx-workflows/dist/dashboard/read-model.js.map +1 -0
  107. package/clinkx-workflows/dist/dashboard/request-admission.d.ts +31 -0
  108. package/clinkx-workflows/dist/dashboard/request-admission.js +126 -0
  109. package/clinkx-workflows/dist/dashboard/request-admission.js.map +1 -0
  110. package/clinkx-workflows/dist/dashboard/scanner.d.ts +75 -0
  111. package/clinkx-workflows/dist/dashboard/scanner.js +1110 -0
  112. package/clinkx-workflows/dist/dashboard/scanner.js.map +1 -0
  113. package/clinkx-workflows/dist/dashboard/server-factory.d.ts +50 -0
  114. package/clinkx-workflows/dist/dashboard/server-factory.js +431 -0
  115. package/clinkx-workflows/dist/dashboard/server-factory.js.map +1 -0
  116. package/clinkx-workflows/dist/dashboard/session-log-contract.d.ts +2611 -0
  117. package/clinkx-workflows/dist/dashboard/session-log-contract.js +480 -0
  118. package/clinkx-workflows/dist/dashboard/session-log-contract.js.map +1 -0
  119. package/clinkx-workflows/dist/dashboard/session-log-identity.d.ts +21 -0
  120. package/clinkx-workflows/dist/dashboard/session-log-identity.js +101 -0
  121. package/clinkx-workflows/dist/dashboard/session-log-identity.js.map +1 -0
  122. package/clinkx-workflows/dist/dashboard/session-log-journal.d.ts +43 -0
  123. package/clinkx-workflows/dist/dashboard/session-log-journal.js +522 -0
  124. package/clinkx-workflows/dist/dashboard/session-log-journal.js.map +1 -0
  125. package/clinkx-workflows/dist/dashboard/session-log-reader.d.ts +61 -0
  126. package/clinkx-workflows/dist/dashboard/session-log-reader.js +378 -0
  127. package/clinkx-workflows/dist/dashboard/session-log-reader.js.map +1 -0
  128. package/clinkx-workflows/dist/dashboard/session-log-redaction.d.ts +6 -0
  129. package/clinkx-workflows/dist/dashboard/session-log-redaction.js +367 -0
  130. package/clinkx-workflows/dist/dashboard/session-log-redaction.js.map +1 -0
  131. package/clinkx-workflows/dist/dashboard/session-log-retention.d.ts +23 -0
  132. package/clinkx-workflows/dist/dashboard/session-log-retention.js +212 -0
  133. package/clinkx-workflows/dist/dashboard/session-log-retention.js.map +1 -0
  134. package/clinkx-workflows/dist/dashboard/static-responses.d.ts +10 -0
  135. package/clinkx-workflows/dist/dashboard/static-responses.js +94 -0
  136. package/clinkx-workflows/dist/dashboard/static-responses.js.map +1 -0
  137. package/clinkx-workflows/dist/dashboard/worker-lock-observer.d.ts +28 -0
  138. package/clinkx-workflows/dist/dashboard/worker-lock-observer.js +241 -0
  139. package/clinkx-workflows/dist/dashboard/worker-lock-observer.js.map +1 -0
  140. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  141. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  142. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  143. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  144. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  145. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  146. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  147. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  148. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  149. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  150. package/clinkx-workflows/dist/dashboard-ui/assets/index-DOkMXTfB.js +25 -0
  151. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  152. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  153. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  154. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  155. package/clinkx-workflows/dist/dashboard-ui/assets/style-ChJsn0KD.css +1 -0
  156. package/clinkx-workflows/dist/dashboard-ui/contracts/council-plan-review-input-v1.json +158 -0
  157. package/clinkx-workflows/dist/dashboard-ui/index.html +15 -0
  158. package/clinkx-workflows/dist/dashboard-ui/licenses/IBM-Plex-Mono-OFL.txt +93 -0
  159. package/clinkx-workflows/dist/dashboard-ui/licenses/IBM-Plex-Sans-OFL.txt +93 -0
  160. package/clinkx-workflows/dist/dashboard-ui/licenses/JetBrains-Mono-OFL.txt +93 -0
  161. package/clinkx-workflows/dist/dashboard-ui/licenses/NOTICE.md +32 -0
  162. package/clinkx-workflows/dist/dashboard-ui/theme-init.js +8 -0
  163. package/clinkx-workflows/dist/definition-normalizer.d.ts +19 -0
  164. package/clinkx-workflows/dist/definition-normalizer.js.map +1 -1
  165. package/clinkx-workflows/dist/delegate-validate.d.ts +78 -0
  166. package/clinkx-workflows/dist/delegate-validate.js +97 -0
  167. package/clinkx-workflows/dist/delegate-validate.js.map +1 -0
  168. package/clinkx-workflows/dist/engine.d.ts +141 -0
  169. package/clinkx-workflows/dist/engine.js +882 -28
  170. package/clinkx-workflows/dist/engine.js.map +1 -1
  171. package/clinkx-workflows/dist/errors.d.ts +2 -0
  172. package/clinkx-workflows/dist/errors.js.map +1 -1
  173. package/clinkx-workflows/dist/fingerprint.d.ts +1 -1
  174. package/clinkx-workflows/dist/fingerprint.js +1 -1
  175. package/clinkx-workflows/dist/index.d.ts +19 -0
  176. package/clinkx-workflows/dist/index.js +15 -0
  177. package/clinkx-workflows/dist/index.js.map +1 -1
  178. package/clinkx-workflows/dist/loader.d.ts +9 -3
  179. package/clinkx-workflows/dist/loader.js +92 -21
  180. package/clinkx-workflows/dist/loader.js.map +1 -1
  181. package/clinkx-workflows/dist/plan-review/admission.d.ts +160 -0
  182. package/clinkx-workflows/dist/plan-review/admission.js +290 -0
  183. package/clinkx-workflows/dist/plan-review/admission.js.map +1 -0
  184. package/clinkx-workflows/dist/plan-review/context-policy.d.ts +55 -0
  185. package/clinkx-workflows/dist/plan-review/context-policy.js +146 -0
  186. package/clinkx-workflows/dist/plan-review/context-policy.js.map +1 -0
  187. package/clinkx-workflows/dist/plan-review/contract.d.ts +763 -0
  188. package/clinkx-workflows/dist/plan-review/contract.js +289 -0
  189. package/clinkx-workflows/dist/plan-review/contract.js.map +1 -0
  190. package/clinkx-workflows/dist/plan-review/digest.d.ts +68 -0
  191. package/clinkx-workflows/dist/plan-review/digest.js +241 -0
  192. package/clinkx-workflows/dist/plan-review/digest.js.map +1 -0
  193. package/clinkx-workflows/dist/plan-review/discovery.d.ts +45 -0
  194. package/clinkx-workflows/dist/plan-review/discovery.js +36 -0
  195. package/clinkx-workflows/dist/plan-review/discovery.js.map +1 -0
  196. package/clinkx-workflows/dist/plan-review/execution-contract.d.ts +298 -0
  197. package/clinkx-workflows/dist/plan-review/execution-contract.js +194 -0
  198. package/clinkx-workflows/dist/plan-review/execution-contract.js.map +1 -0
  199. package/clinkx-workflows/dist/plan-review/expander.d.ts +48 -0
  200. package/clinkx-workflows/dist/plan-review/expander.js +243 -0
  201. package/clinkx-workflows/dist/plan-review/expander.js.map +1 -0
  202. package/clinkx-workflows/dist/plan-review/projector.d.ts +126 -0
  203. package/clinkx-workflows/dist/plan-review/projector.js +437 -0
  204. package/clinkx-workflows/dist/plan-review/projector.js.map +1 -0
  205. package/clinkx-workflows/dist/plan-review/publication.d.ts +95 -0
  206. package/clinkx-workflows/dist/plan-review/publication.js +182 -0
  207. package/clinkx-workflows/dist/plan-review/publication.js.map +1 -0
  208. package/clinkx-workflows/dist/plan-review/ranking-reducer.d.ts +34 -0
  209. package/clinkx-workflows/dist/plan-review/ranking-reducer.js +139 -0
  210. package/clinkx-workflows/dist/plan-review/ranking-reducer.js.map +1 -0
  211. package/clinkx-workflows/dist/plan-review/resume.d.ts +38 -0
  212. package/clinkx-workflows/dist/plan-review/resume.js +122 -0
  213. package/clinkx-workflows/dist/plan-review/resume.js.map +1 -0
  214. package/clinkx-workflows/dist/plan-review/rubric.d.ts +7 -0
  215. package/clinkx-workflows/dist/plan-review/rubric.js +24 -0
  216. package/clinkx-workflows/dist/plan-review/rubric.js.map +1 -0
  217. package/clinkx-workflows/dist/plan-review/run-state.d.ts +398 -0
  218. package/clinkx-workflows/dist/plan-review/run-state.js +183 -0
  219. package/clinkx-workflows/dist/plan-review/run-state.js.map +1 -0
  220. package/clinkx-workflows/dist/plan-review/runtime-policy.d.ts +74 -0
  221. package/clinkx-workflows/dist/plan-review/runtime-policy.js +186 -0
  222. package/clinkx-workflows/dist/plan-review/runtime-policy.js.map +1 -0
  223. package/clinkx-workflows/dist/plan-review/snapshot.d.ts +81 -0
  224. package/clinkx-workflows/dist/plan-review/snapshot.js +170 -0
  225. package/clinkx-workflows/dist/plan-review/snapshot.js.map +1 -0
  226. package/clinkx-workflows/dist/plan-review/stage-error.d.ts +19 -0
  227. package/clinkx-workflows/dist/plan-review/stage-error.js +20 -0
  228. package/clinkx-workflows/dist/plan-review/stage-error.js.map +1 -0
  229. package/clinkx-workflows/dist/post-processors/index.d.ts +20 -0
  230. package/clinkx-workflows/dist/post-processors/index.js +21 -0
  231. package/clinkx-workflows/dist/post-processors/index.js.map +1 -0
  232. package/clinkx-workflows/dist/prompt-budget.d.ts +7 -0
  233. package/clinkx-workflows/dist/prompt-budget.js +7 -1
  234. package/clinkx-workflows/dist/prompt-budget.js.map +1 -1
  235. package/clinkx-workflows/dist/reducers/index.js +2 -0
  236. package/clinkx-workflows/dist/reducers/index.js.map +1 -1
  237. package/clinkx-workflows/dist/run-lock-heartbeat.d.ts +2 -0
  238. package/clinkx-workflows/dist/run-lock-heartbeat.js +3 -0
  239. package/clinkx-workflows/dist/run-lock-heartbeat.js.map +1 -0
  240. package/clinkx-workflows/dist/run-summary/cards/council-plan-review.d.ts +34 -0
  241. package/clinkx-workflows/dist/run-summary/cards/council-plan-review.js +74 -0
  242. package/clinkx-workflows/dist/run-summary/cards/council-plan-review.js.map +1 -0
  243. package/clinkx-workflows/dist/run-summary/cards/index.js +5 -0
  244. package/clinkx-workflows/dist/run-summary/cards/index.js.map +1 -1
  245. package/clinkx-workflows/dist/run-summary.d.ts +13 -0
  246. package/clinkx-workflows/dist/run-summary.js +29 -1
  247. package/clinkx-workflows/dist/run-summary.js.map +1 -1
  248. package/clinkx-workflows/dist/schema.d.ts +76 -21
  249. package/clinkx-workflows/dist/schema.js +10 -1
  250. package/clinkx-workflows/dist/schema.js.map +1 -1
  251. package/clinkx-workflows/dist/seed-terms.d.ts +30 -0
  252. package/clinkx-workflows/dist/seed-terms.js +176 -0
  253. package/clinkx-workflows/dist/seed-terms.js.map +1 -0
  254. package/clinkx-workflows/dist/server.d.ts +5 -2
  255. package/clinkx-workflows/dist/server.js +82 -52
  256. package/clinkx-workflows/dist/server.js.map +1 -1
  257. package/clinkx-workflows/dist/shutdown.d.ts +18 -20
  258. package/clinkx-workflows/dist/shutdown.js +43 -61
  259. package/clinkx-workflows/dist/shutdown.js.map +1 -1
  260. package/clinkx-workflows/dist/state-schema.d.ts +38 -0
  261. package/clinkx-workflows/dist/state.d.ts +170 -3
  262. package/clinkx-workflows/dist/state.js +1275 -28
  263. package/clinkx-workflows/dist/state.js.map +1 -1
  264. package/clinkx-workflows/dist/transport.d.ts +15 -0
  265. package/clinkx-workflows/dist/transport.js +19 -10
  266. package/clinkx-workflows/dist/transport.js.map +1 -1
  267. package/clinkx-workflows/dist/types.d.ts +14 -2
  268. package/clinkx-workflows/dist/validators/council.d.ts +318 -85
  269. package/clinkx-workflows/dist/validators/council.js +52 -13
  270. package/clinkx-workflows/dist/validators/council.js.map +1 -1
  271. package/clinkx-workflows/dist/validators/index.d.ts +1 -0
  272. package/clinkx-workflows/dist/validators/index.js +3 -0
  273. package/clinkx-workflows/dist/validators/index.js.map +1 -1
  274. package/clinkx-workflows/dist/validators/plan-review.d.ts +398 -0
  275. package/clinkx-workflows/dist/validators/plan-review.js +316 -0
  276. package/clinkx-workflows/dist/validators/plan-review.js.map +1 -0
  277. package/clinkx-workflows/dist/workflow-receipt.js +188 -4
  278. package/clinkx-workflows/dist/workflow-receipt.js.map +1 -1
  279. package/clinkx-workflows/dist/workflow-tools.d.ts +48 -3
  280. package/clinkx-workflows/dist/workflow-tools.js +1402 -59
  281. package/clinkx-workflows/dist/workflow-tools.js.map +1 -1
  282. package/clinkx-workflows/dist/workspace-signature.d.ts +16 -0
  283. package/clinkx-workflows/dist/workspace-signature.js +388 -0
  284. package/clinkx-workflows/dist/workspace-signature.js.map +1 -0
  285. package/clinkx-workflows/templates/council/answer-specialist.txt +2 -1
  286. package/clinkx-workflows/templates/council/code-review-chairman.txt +13 -0
  287. package/clinkx-workflows/templates/council/code-review-cross-reviewer.txt +4 -1
  288. package/clinkx-workflows/templates/council/code-review-reviewer.txt +19 -3
  289. package/clinkx-workflows/templates/council/debug-debugger.txt +2 -1
  290. package/clinkx-workflows/templates/council/discover-analyst.txt +2 -1
  291. package/clinkx-workflows/templates/council/member.txt +2 -1
  292. package/clinkx-workflows/templates/council/plan-review-chairman.txt +68 -0
  293. package/clinkx-workflows/templates/council/plan-review-cross-reviewer.txt +51 -0
  294. package/clinkx-workflows/templates/council/plan-review-reviewer.txt +60 -0
  295. package/clinkx-workflows/templates/plan-review/chairman.txt +48 -0
  296. package/clinkx-workflows/templates/plan-review/cross-review.txt +52 -0
  297. package/clinkx-workflows/templates/plan-review/ranking.txt +16 -0
  298. package/clinkx-workflows/templates/plan-review/reviewer.txt +57 -0
  299. package/clinkx-workflows/workflows/council-answer.yaml +97 -8
  300. package/clinkx-workflows/workflows/council-code-review.yaml +103 -8
  301. package/clinkx-workflows/workflows/council-debug.yaml +97 -8
  302. package/clinkx-workflows/workflows/council-default.yaml +97 -8
  303. package/clinkx-workflows/workflows/council-discover.yaml +97 -8
  304. package/clinkx-workflows/workflows/council-plan-review.yaml +250 -0
  305. package/clinkx-workflows/workflows/plan-review-receipts.yaml +230 -0
  306. package/conf/adapters/agy.json +49 -0
  307. package/conf/adapters/claude.json +5 -0
  308. package/conf/adapters/codex-app-server.json +44 -0
  309. package/conf/adapters/codex.json +7 -2
  310. package/conf/adapters/glm.json +5 -0
  311. package/conf/adapters/grok.json +60 -0
  312. package/conf/adapters/hapi/agy.json +52 -0
  313. package/conf/adapters/hapi/claude.json +5 -0
  314. package/conf/adapters/hapi/codex.json +7 -2
  315. package/conf/adapters/hapi/glm.json +5 -0
  316. package/conf/prompts/json-codereviewer.txt +1 -0
  317. package/conf/prompts/json.txt +1 -0
  318. package/dist/activity-journal.d.ts +42 -0
  319. package/dist/activity-journal.js +381 -0
  320. package/dist/activity-journal.js.map +1 -0
  321. package/dist/allowed-roots.d.ts +53 -0
  322. package/dist/allowed-roots.js +216 -0
  323. package/dist/allowed-roots.js.map +1 -0
  324. package/dist/codex/activity-session-log.d.ts +14 -0
  325. package/dist/codex/activity-session-log.js +206 -0
  326. package/dist/codex/activity-session-log.js.map +1 -0
  327. package/dist/codex/agent-tools.d.ts +23 -0
  328. package/dist/codex/agent-tools.js +1270 -0
  329. package/dist/codex/agent-tools.js.map +1 -0
  330. package/dist/codex/app-server-client.d.ts +76 -0
  331. package/dist/codex/app-server-client.js +582 -0
  332. package/dist/codex/app-server-client.js.map +1 -0
  333. package/dist/codex/app-server-registry.d.ts +389 -0
  334. package/dist/codex/app-server-registry.js +1407 -0
  335. package/dist/codex/app-server-registry.js.map +1 -0
  336. package/dist/codex/client-types.d.ts +109 -0
  337. package/dist/codex/client-types.js +2 -0
  338. package/dist/codex/client-types.js.map +1 -0
  339. package/dist/codex/protocol.d.ts +5375 -0
  340. package/dist/codex/protocol.js +614 -0
  341. package/dist/codex/protocol.js.map +1 -0
  342. package/dist/codex/session.d.ts +263 -0
  343. package/dist/codex/session.js +466 -0
  344. package/dist/codex/session.js.map +1 -0
  345. package/dist/config.d.ts +185 -19
  346. package/dist/config.js +82 -16
  347. package/dist/config.js.map +1 -1
  348. package/dist/context-builder/anchors.d.ts +12 -0
  349. package/dist/context-builder/anchors.js +22 -0
  350. package/dist/context-builder/anchors.js.map +1 -0
  351. package/dist/context-builder/bundle.d.ts +109 -0
  352. package/dist/context-builder/bundle.js +1498 -0
  353. package/dist/context-builder/bundle.js.map +1 -0
  354. package/dist/context-builder/codemap.d.ts +22 -0
  355. package/dist/context-builder/codemap.js +675 -0
  356. package/dist/context-builder/codemap.js.map +1 -0
  357. package/dist/context-builder/config.d.ts +61 -0
  358. package/dist/context-builder/config.js +216 -0
  359. package/dist/context-builder/config.js.map +1 -0
  360. package/dist/context-builder/context-run-catalog.d.ts +17 -0
  361. package/dist/context-builder/context-run-catalog.js +99 -0
  362. package/dist/context-builder/context-run-catalog.js.map +1 -0
  363. package/dist/context-builder/delegate-packet.d.ts +219 -0
  364. package/dist/context-builder/delegate-packet.js +1190 -0
  365. package/dist/context-builder/delegate-packet.js.map +1 -0
  366. package/dist/context-builder/delegate-reconstruction.d.ts +13 -0
  367. package/dist/context-builder/delegate-reconstruction.js +220 -0
  368. package/dist/context-builder/delegate-reconstruction.js.map +1 -0
  369. package/dist/context-builder/delegate-validation.d.ts +27 -0
  370. package/dist/context-builder/delegate-validation.js +479 -0
  371. package/dist/context-builder/delegate-validation.js.map +1 -0
  372. package/dist/context-builder/delegate.d.ts +26 -0
  373. package/dist/context-builder/delegate.js +134 -0
  374. package/dist/context-builder/delegate.js.map +1 -0
  375. package/dist/context-builder/diagnostics.d.ts +36 -0
  376. package/dist/context-builder/diagnostics.js +107 -0
  377. package/dist/context-builder/diagnostics.js.map +1 -0
  378. package/dist/context-builder/discovery.d.ts +146 -0
  379. package/dist/context-builder/discovery.js +2129 -0
  380. package/dist/context-builder/discovery.js.map +1 -0
  381. package/dist/context-builder/globs.d.ts +14 -0
  382. package/dist/context-builder/globs.js +175 -0
  383. package/dist/context-builder/globs.js.map +1 -0
  384. package/dist/context-builder/handler.d.ts +41 -0
  385. package/dist/context-builder/handler.js +2590 -0
  386. package/dist/context-builder/handler.js.map +1 -0
  387. package/dist/context-builder/lifecycle-contract.d.ts +424 -0
  388. package/dist/context-builder/lifecycle-contract.js +523 -0
  389. package/dist/context-builder/lifecycle-contract.js.map +1 -0
  390. package/dist/context-builder/lifecycle-journal.d.ts +62 -0
  391. package/dist/context-builder/lifecycle-journal.js +88 -0
  392. package/dist/context-builder/lifecycle-journal.js.map +1 -0
  393. package/dist/context-builder/lifecycle-observer.d.ts +102 -0
  394. package/dist/context-builder/lifecycle-observer.js +258 -0
  395. package/dist/context-builder/lifecycle-observer.js.map +1 -0
  396. package/dist/context-builder/lifecycle-reconcile.d.ts +32 -0
  397. package/dist/context-builder/lifecycle-reconcile.js +191 -0
  398. package/dist/context-builder/lifecycle-reconcile.js.map +1 -0
  399. package/dist/context-builder/lifecycle-recovery.d.ts +2 -0
  400. package/dist/context-builder/lifecycle-recovery.js +14 -0
  401. package/dist/context-builder/lifecycle-recovery.js.map +1 -0
  402. package/dist/context-builder/path-signals.d.ts +7 -0
  403. package/dist/context-builder/path-signals.js +70 -0
  404. package/dist/context-builder/path-signals.js.map +1 -0
  405. package/dist/context-builder/paths.d.ts +30 -0
  406. package/dist/context-builder/paths.js +153 -0
  407. package/dist/context-builder/paths.js.map +1 -0
  408. package/dist/context-builder/progress.d.ts +17 -0
  409. package/dist/context-builder/progress.js +93 -0
  410. package/dist/context-builder/progress.js.map +1 -0
  411. package/dist/context-builder/receipt.d.ts +91 -0
  412. package/dist/context-builder/receipt.js +180 -0
  413. package/dist/context-builder/receipt.js.map +1 -0
  414. package/dist/context-builder/refine-handler.d.ts +14 -0
  415. package/dist/context-builder/refine-handler.js +790 -0
  416. package/dist/context-builder/refine-handler.js.map +1 -0
  417. package/dist/context-builder/review-coverage.d.ts +84 -0
  418. package/dist/context-builder/review-coverage.js +437 -0
  419. package/dist/context-builder/review-coverage.js.map +1 -0
  420. package/dist/context-builder/run-id.d.ts +7 -0
  421. package/dist/context-builder/run-id.js +31 -0
  422. package/dist/context-builder/run-id.js.map +1 -0
  423. package/dist/context-builder/schema.d.ts +669 -0
  424. package/dist/context-builder/schema.js +399 -0
  425. package/dist/context-builder/schema.js.map +1 -0
  426. package/dist/context-builder/secrets.d.ts +41 -0
  427. package/dist/context-builder/secrets.js +1651 -0
  428. package/dist/context-builder/secrets.js.map +1 -0
  429. package/dist/context-builder/selection.d.ts +56 -0
  430. package/dist/context-builder/selection.js +1111 -0
  431. package/dist/context-builder/selection.js.map +1 -0
  432. package/dist/context-builder/session-log-identity.d.ts +1 -0
  433. package/dist/context-builder/session-log-identity.js +66 -0
  434. package/dist/context-builder/session-log-identity.js.map +1 -0
  435. package/dist/context-builder/slice-range-math.d.ts +16 -0
  436. package/dist/context-builder/slice-range-math.js +137 -0
  437. package/dist/context-builder/slice-range-math.js.map +1 -0
  438. package/dist/context-builder/status.d.ts +66 -0
  439. package/dist/context-builder/status.js +160 -0
  440. package/dist/context-builder/status.js.map +1 -0
  441. package/dist/context-builder/storage.d.ts +118 -0
  442. package/dist/context-builder/storage.js +1003 -0
  443. package/dist/context-builder/storage.js.map +1 -0
  444. package/dist/context-builder/token-estimate.d.ts +19 -0
  445. package/dist/context-builder/token-estimate.js +90 -0
  446. package/dist/context-builder/token-estimate.js.map +1 -0
  447. package/dist/context-builder/versions.d.ts +29 -0
  448. package/dist/context-builder/versions.js +30 -0
  449. package/dist/context-builder/versions.js.map +1 -0
  450. package/dist/context-builder/workflow-runner.d.ts +69 -0
  451. package/dist/context-builder/workflow-runner.js +1051 -0
  452. package/dist/context-builder/workflow-runner.js.map +1 -0
  453. package/dist/context-builder/write-watchdog.d.ts +14 -0
  454. package/dist/context-builder/write-watchdog.js +38 -0
  455. package/dist/context-builder/write-watchdog.js.map +1 -0
  456. package/dist/dashboard-adapter-catalog.d.ts +9 -0
  457. package/dist/dashboard-adapter-catalog.js +46 -0
  458. package/dist/dashboard-adapter-catalog.js.map +1 -0
  459. package/dist/dashboard-cli.d.ts +79 -0
  460. package/dist/dashboard-cli.js +585 -0
  461. package/dist/dashboard-cli.js.map +1 -0
  462. package/dist/dashboard-companion/client.d.ts +36 -0
  463. package/dist/dashboard-companion/client.js +210 -0
  464. package/dist/dashboard-companion/client.js.map +1 -0
  465. package/dist/dashboard-companion/config.d.ts +8 -0
  466. package/dist/dashboard-companion/config.js +52 -0
  467. package/dist/dashboard-companion/config.js.map +1 -0
  468. package/dist/dashboard-companion/http-proxy.d.ts +10 -0
  469. package/dist/dashboard-companion/http-proxy.js +234 -0
  470. package/dist/dashboard-companion/http-proxy.js.map +1 -0
  471. package/dist/dashboard-companion/protocol.d.ts +80 -0
  472. package/dist/dashboard-companion/protocol.js +455 -0
  473. package/dist/dashboard-companion/protocol.js.map +1 -0
  474. package/dist/dashboard-companion/standalone-assets.d.ts +12 -0
  475. package/dist/dashboard-companion/standalone-assets.js +72 -0
  476. package/dist/dashboard-companion/standalone-assets.js.map +1 -0
  477. package/dist/dashboard-companion/standalone-entry.d.ts +1 -0
  478. package/dist/dashboard-companion/standalone-entry.js +17 -0
  479. package/dist/dashboard-companion/standalone-entry.js.map +1 -0
  480. package/dist/dashboard-gateway/config.d.ts +9 -0
  481. package/dist/dashboard-gateway/config.js +44 -0
  482. package/dist/dashboard-gateway/config.js.map +1 -0
  483. package/dist/dashboard-gateway/index.d.ts +11 -0
  484. package/dist/dashboard-gateway/index.js +755 -0
  485. package/dist/dashboard-gateway/index.js.map +1 -0
  486. package/dist/dashboard-gateway/main.d.ts +1 -0
  487. package/dist/dashboard-gateway/main.js +25 -0
  488. package/dist/dashboard-gateway/main.js.map +1 -0
  489. package/dist/dashboard-pairing-token.d.ts +1 -0
  490. package/dist/dashboard-pairing-token.js +5 -0
  491. package/dist/dashboard-pairing-token.js.map +1 -0
  492. package/dist/elaris/client.d.ts +73 -0
  493. package/dist/elaris/client.js +825 -0
  494. package/dist/elaris/client.js.map +1 -0
  495. package/dist/elaris/config.d.ts +18 -0
  496. package/dist/elaris/config.js +75 -0
  497. package/dist/elaris/config.js.map +1 -0
  498. package/dist/elaris/errors.d.ts +41 -0
  499. package/dist/elaris/errors.js +205 -0
  500. package/dist/elaris/errors.js.map +1 -0
  501. package/dist/elaris/github-repo.d.ts +18 -0
  502. package/dist/elaris/github-repo.js +89 -0
  503. package/dist/elaris/github-repo.js.map +1 -0
  504. package/dist/elaris/index.d.ts +10 -0
  505. package/dist/elaris/index.js +11 -0
  506. package/dist/elaris/index.js.map +1 -0
  507. package/dist/elaris/redact.d.ts +89 -0
  508. package/dist/elaris/redact.js +423 -0
  509. package/dist/elaris/redact.js.map +1 -0
  510. package/dist/elaris/run-id.d.ts +5 -0
  511. package/dist/elaris/run-id.js +20 -0
  512. package/dist/elaris/run-id.js.map +1 -0
  513. package/dist/elaris/status.d.ts +45 -0
  514. package/dist/elaris/status.js +122 -0
  515. package/dist/elaris/status.js.map +1 -0
  516. package/dist/elaris/tool-schemas.d.ts +314 -0
  517. package/dist/elaris/tool-schemas.js +208 -0
  518. package/dist/elaris/tool-schemas.js.map +1 -0
  519. package/dist/elaris/tools.d.ts +73 -0
  520. package/dist/elaris/tools.js +1065 -0
  521. package/dist/elaris/tools.js.map +1 -0
  522. package/dist/elaris/types.d.ts +1541 -0
  523. package/dist/elaris/types.js +252 -0
  524. package/dist/elaris/types.js.map +1 -0
  525. package/dist/errors.d.ts +16 -0
  526. package/dist/errors.js +19 -0
  527. package/dist/errors.js.map +1 -1
  528. package/dist/handler.d.ts +4 -0
  529. package/dist/handler.js +10 -1
  530. package/dist/handler.js.map +1 -1
  531. package/dist/index.d.ts +2 -1
  532. package/dist/index.js +13 -3
  533. package/dist/index.js.map +1 -1
  534. package/dist/local-clink-backend.d.ts +3 -0
  535. package/dist/local-clink-backend.js +4 -0
  536. package/dist/local-clink-backend.js.map +1 -1
  537. package/dist/package-info.d.ts +2 -0
  538. package/dist/package-info.js +18 -0
  539. package/dist/package-info.js.map +1 -0
  540. package/dist/parsers/codex-jsonl.js +48 -3
  541. package/dist/parsers/codex-jsonl.js.map +1 -1
  542. package/dist/parsers/extract.d.ts +10 -1
  543. package/dist/parsers/extract.js +11 -3
  544. package/dist/parsers/extract.js.map +1 -1
  545. package/dist/paths.d.ts +8 -0
  546. package/dist/paths.js +31 -43
  547. package/dist/paths.js.map +1 -1
  548. package/dist/pipeline.d.ts +51 -3
  549. package/dist/pipeline.js +264 -47
  550. package/dist/pipeline.js.map +1 -1
  551. package/dist/run-dir.d.ts +24 -0
  552. package/dist/run-dir.js +201 -2
  553. package/dist/run-dir.js.map +1 -1
  554. package/dist/runner.d.ts +13 -0
  555. package/dist/runner.js +184 -15
  556. package/dist/runner.js.map +1 -1
  557. package/dist/safety.d.ts +4 -4
  558. package/dist/safety.js +4 -4
  559. package/dist/schema.d.ts +7 -7
  560. package/dist/server.d.ts +2 -0
  561. package/dist/server.js +396 -24
  562. package/dist/server.js.map +1 -1
  563. package/dist/session-log-stream.d.ts +18 -0
  564. package/dist/session-log-stream.js +319 -0
  565. package/dist/session-log-stream.js.map +1 -0
  566. package/package.json +47 -5
  567. package/conf/adapters/gemini.json +0 -44
  568. package/conf/adapters/hapi/gemini.json +0 -47
  569. package/dist/artifacts.d.ts +0 -9
  570. package/dist/artifacts.js +0 -24
  571. package/dist/artifacts.js.map +0 -1
  572. package/dist/parsers/gemini-json.d.ts +0 -2
  573. package/dist/parsers/gemini-json.js +0 -72
  574. package/dist/parsers/gemini-json.js.map +0 -1
@@ -0,0 +1,776 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { closeSync, fsyncSync, lstatSync, openSync, readFileSync, renameSync, utimesSync, } from "node:fs";
3
+ import { lstat, mkdir, open, readFile, readdir, unlink, utimes, } from "node:fs/promises";
4
+ import { hostname } from "node:os";
5
+ import { join } from "node:path";
6
+ import { z } from "zod";
7
+ import { logger } from "../../logger.js";
8
+ const CREDENTIAL_STORE_VERSION = 1;
9
+ const CREDENTIAL_FILENAME = "credentials.json";
10
+ const CREDENTIAL_LOCK_FILENAME = ".credentials.lock";
11
+ const MAX_CREDENTIAL_FILE_BYTES = 256 * 1024;
12
+ const MAX_CREDENTIALS = 16;
13
+ const LOCK_HEARTBEAT_MS = 10_000;
14
+ const LOCK_STALE_MS = 60_000;
15
+ const MAX_DIAGNOSTIC_CAUSES = 8;
16
+ const MAX_DIAGNOSTIC_NAME_LENGTH = 80;
17
+ const MAX_DIAGNOSTIC_MESSAGE_LENGTH = 512;
18
+ function canonicalBase64Url(value, expectedBytes) {
19
+ if (value === "" || !/^[A-Za-z0-9_-]+$/.test(value))
20
+ return false;
21
+ const decoded = Buffer.from(value, "base64url");
22
+ return (expectedBytes == null || decoded.byteLength === expectedBytes)
23
+ && decoded.toString("base64url") === value;
24
+ }
25
+ const Base64UrlSchema = z.string().refine((value) => canonicalBase64Url(value), "must be canonical base64url");
26
+ const TransportSchema = z.enum([
27
+ "ble",
28
+ "cable",
29
+ "hybrid",
30
+ "internal",
31
+ "nfc",
32
+ "smart-card",
33
+ "usb",
34
+ ]);
35
+ const StoredCredentialSchema = z.object({
36
+ id: Base64UrlSchema,
37
+ publicKey: Base64UrlSchema,
38
+ counter: z.number().int().nonnegative().safe(),
39
+ transports: z.array(TransportSchema).max(7),
40
+ label: z.string().trim().min(1).max(120).optional(),
41
+ createdAt: z.string().refine((value) => Number.isFinite(Date.parse(value)), "must be an ISO timestamp"),
42
+ }).strict();
43
+ const CredentialDocumentSchema = z.object({
44
+ version: z.literal(CREDENTIAL_STORE_VERSION),
45
+ userHandle: z.string().refine((value) => canonicalBase64Url(value, 16), "must encode exactly 16 bytes as canonical base64url"),
46
+ rpId: z.string().min(1),
47
+ credentials: z.array(StoredCredentialSchema).max(MAX_CREDENTIALS),
48
+ }).strict().superRefine((document, context) => {
49
+ const seen = new Set();
50
+ for (const [index, credential] of document.credentials.entries()) {
51
+ if (seen.has(credential.id)) {
52
+ context.addIssue({
53
+ code: z.ZodIssueCode.custom,
54
+ message: "duplicate credential id",
55
+ path: ["credentials", index, "id"],
56
+ });
57
+ }
58
+ seen.add(credential.id);
59
+ }
60
+ });
61
+ function createCredentialLockRecord() {
62
+ return {
63
+ version: 1,
64
+ pid: process.pid,
65
+ hostname: hostname(),
66
+ token: randomBytes(16).toString("base64url"),
67
+ startedAt: new Date().toISOString(),
68
+ };
69
+ }
70
+ async function reclaimCredentialTransitionIfOwnerless(transitionPath) {
71
+ let raw;
72
+ let transitionStat;
73
+ try {
74
+ transitionStat = await lstat(transitionPath);
75
+ }
76
+ catch (error) {
77
+ if (error.code === "ENOENT")
78
+ return true;
79
+ throw error;
80
+ }
81
+ if (transitionStat.isSymbolicLink()
82
+ || !transitionStat.isFile()
83
+ || (transitionStat.mode & 0o777) !== 0o600) {
84
+ throw new Error("dashboard credential lock transition ownership is unknown");
85
+ }
86
+ try {
87
+ raw = await readFile(transitionPath, "utf8");
88
+ }
89
+ catch (error) {
90
+ if (error.code === "ENOENT")
91
+ return true;
92
+ throw error;
93
+ }
94
+ let value;
95
+ try {
96
+ value = JSON.parse(raw);
97
+ }
98
+ catch {
99
+ value = undefined;
100
+ }
101
+ const recordValue = isCredentialLockRecord(value) ? value : undefined;
102
+ const validRecord = recordValue != null;
103
+ const provablyOwnerless = Date.now() - transitionStat.mtimeMs > LOCK_STALE_MS;
104
+ if (!provablyOwnerless) {
105
+ if (!validRecord) {
106
+ throw new Error("dashboard credential lock transition ownership is unknown");
107
+ }
108
+ return false;
109
+ }
110
+ const identity = { dev: transitionStat.dev, ino: transitionStat.ino };
111
+ if (recordValue == null) {
112
+ await assertUnchangedRegularFile(transitionPath, identity, raw, "dashboard credential lock transition");
113
+ }
114
+ else {
115
+ await assertOwnedLockFile(transitionPath, recordValue, identity, "dashboard credential lock transition");
116
+ }
117
+ await unlink(transitionPath);
118
+ return true;
119
+ }
120
+ async function withCredentialLockTransition(lockPath, operation) {
121
+ const transitionPath = `${lockPath}.reclaim`;
122
+ const record = createCredentialLockRecord();
123
+ for (let attempt = 0; attempt < 2; attempt += 1) {
124
+ let transitionHandle;
125
+ let transitionIdentity;
126
+ let transitionRecordWritten = false;
127
+ try {
128
+ transitionHandle = await open(transitionPath, "wx", 0o600);
129
+ const openedStat = await transitionHandle.stat();
130
+ transitionIdentity = { dev: openedStat.dev, ino: openedStat.ino };
131
+ await transitionHandle.writeFile(`${JSON.stringify(record)}\n`, "utf8");
132
+ transitionRecordWritten = true;
133
+ await transitionHandle.sync();
134
+ await transitionHandle.close();
135
+ transitionHandle = undefined;
136
+ }
137
+ catch (error) {
138
+ await transitionHandle?.close().catch(() => { });
139
+ if (error.code !== "EEXIST") {
140
+ if (transitionIdentity != null && transitionRecordWritten) {
141
+ await assertOwnedLockFile(transitionPath, record, transitionIdentity, "dashboard credential lock transition").then(() => unlink(transitionPath), () => undefined).catch(() => { });
142
+ }
143
+ throw error;
144
+ }
145
+ if (attempt > 0
146
+ || !(await reclaimCredentialTransitionIfOwnerless(transitionPath))) {
147
+ return { entered: false };
148
+ }
149
+ continue;
150
+ }
151
+ if (transitionIdentity == null) {
152
+ throw new Error("dashboard credential lock transition ownership is unknown");
153
+ }
154
+ let heartbeatError;
155
+ let heartbeatTail = Promise.resolve();
156
+ const heartbeat = setInterval(() => {
157
+ heartbeatTail = heartbeatTail.then(async () => {
158
+ if (heartbeatError != null)
159
+ return;
160
+ await assertOwnedLockFile(transitionPath, record, transitionIdentity, "dashboard credential lock transition", () => heartbeatError);
161
+ const now = new Date();
162
+ await utimes(transitionPath, now, now);
163
+ await assertOwnedLockFile(transitionPath, record, transitionIdentity, "dashboard credential lock transition", () => heartbeatError);
164
+ }).catch((error) => {
165
+ heartbeatError = error instanceof Error ? error : new Error(String(error));
166
+ });
167
+ }, LOCK_HEARTBEAT_MS);
168
+ heartbeat.unref();
169
+ try {
170
+ await assertOwnedLockFile(transitionPath, record, transitionIdentity, "dashboard credential lock transition", () => heartbeatError);
171
+ const value = await operation({
172
+ assertHealthy: async () => {
173
+ await assertOwnedLockFile(transitionPath, record, transitionIdentity, "dashboard credential lock transition", () => heartbeatError);
174
+ },
175
+ runCritical: (criticalOperation) => {
176
+ if (heartbeatError != null)
177
+ throw heartbeatError;
178
+ assertOwnedLockFileSync(transitionPath, record, transitionIdentity, "dashboard credential lock transition");
179
+ const now = new Date();
180
+ utimesSync(transitionPath, now, now);
181
+ assertOwnedLockFileSync(transitionPath, record, transitionIdentity, "dashboard credential lock transition");
182
+ return criticalOperation();
183
+ },
184
+ });
185
+ await assertOwnedLockFile(transitionPath, record, transitionIdentity, "dashboard credential lock transition", () => heartbeatError);
186
+ return { entered: true, value };
187
+ }
188
+ finally {
189
+ clearInterval(heartbeat);
190
+ await heartbeatTail.catch(() => { });
191
+ try {
192
+ await assertOwnedLockFile(transitionPath, record, transitionIdentity, "dashboard credential lock transition", () => heartbeatError);
193
+ await unlink(transitionPath);
194
+ }
195
+ catch (error) {
196
+ if (error.code !== "ENOENT")
197
+ throw error;
198
+ }
199
+ }
200
+ }
201
+ return { entered: false };
202
+ }
203
+ function cloneDocument(document) {
204
+ return structuredClone(document);
205
+ }
206
+ function parseDocument(value, expectedRPID) {
207
+ const parsed = CredentialDocumentSchema.parse(value);
208
+ if (parsed.rpId !== expectedRPID) {
209
+ throw new Error(`dashboard credential store RP ID mismatch: expected ${JSON.stringify(expectedRPID)}`);
210
+ }
211
+ return parsed;
212
+ }
213
+ const CREDENTIAL_TEMP_FILENAME = /^\.credentials\.json\.[1-9]\d*\.[0-9a-f]{16}\.tmp$/;
214
+ /**
215
+ * Deployment-only state classification. This intentionally does not compare
216
+ * RP IDs; DashboardCredentialStore.open remains the sole RP authority.
217
+ */
218
+ export async function inspectDashboardCredentialEnrollmentState(directory) {
219
+ const entries = await readdir(directory, { withFileTypes: true });
220
+ for (const entry of entries) {
221
+ const recognized = entry.name === CREDENTIAL_FILENAME
222
+ || entry.name === CREDENTIAL_LOCK_FILENAME
223
+ || entry.name === `${CREDENTIAL_LOCK_FILENAME}.reclaim`
224
+ || CREDENTIAL_TEMP_FILENAME.test(entry.name);
225
+ if (!recognized) {
226
+ throw new Error(`unexpected credential directory entry ${JSON.stringify(entry.name)}`);
227
+ }
228
+ const entryStat = await lstat(join(directory, entry.name));
229
+ if (entryStat.isSymbolicLink() || !entryStat.isFile()) {
230
+ throw new Error(`credential directory entry ${JSON.stringify(entry.name)} must be a regular file`);
231
+ }
232
+ }
233
+ const filePath = join(directory, CREDENTIAL_FILENAME);
234
+ let raw;
235
+ try {
236
+ raw = await readFile(filePath);
237
+ }
238
+ catch (error) {
239
+ if (error.code === "ENOENT")
240
+ return "absent";
241
+ throw error;
242
+ }
243
+ if (raw.byteLength > MAX_CREDENTIAL_FILE_BYTES) {
244
+ throw new Error("dashboard credential store exceeds the 256 KiB limit");
245
+ }
246
+ const document = CredentialDocumentSchema.parse(JSON.parse(raw.toString("utf8")));
247
+ return document.credentials.length === 0 ? "zero" : "nonzero";
248
+ }
249
+ async function assertSecureDirectory(directory) {
250
+ let entry;
251
+ try {
252
+ entry = await lstat(directory);
253
+ }
254
+ catch (error) {
255
+ if (error.code !== "ENOENT")
256
+ throw error;
257
+ await mkdir(directory, { recursive: true, mode: 0o700 });
258
+ entry = await lstat(directory);
259
+ }
260
+ if (entry.isSymbolicLink() || !entry.isDirectory()) {
261
+ throw new Error("dashboard credential directory must be a real directory");
262
+ }
263
+ const mode = entry.mode & 0o777;
264
+ if ((mode & 0o077) !== 0 || (mode & 0o700) !== 0o700) {
265
+ throw new Error("dashboard credential directory permissions must be 0700");
266
+ }
267
+ }
268
+ async function acquireCredentialDirectoryLock(directory, testHooks = {}) {
269
+ const lockPath = join(directory, CREDENTIAL_LOCK_FILENAME);
270
+ const record = createCredentialLockRecord();
271
+ let acquiredIdentity;
272
+ for (let attempt = 0; attempt < 2; attempt += 1) {
273
+ const transition = await withCredentialLockTransition(lockPath, async () => {
274
+ let handle;
275
+ let identity;
276
+ let recordWritten = false;
277
+ try {
278
+ handle = await open(lockPath, "wx", 0o600);
279
+ const openedStat = await handle.stat();
280
+ identity = { dev: openedStat.dev, ino: openedStat.ino };
281
+ await handle.writeFile(`${JSON.stringify(record)}\n`, "utf8");
282
+ recordWritten = true;
283
+ await handle.sync();
284
+ await handle.close();
285
+ handle = undefined;
286
+ return identity;
287
+ }
288
+ catch (error) {
289
+ await handle?.close().catch(() => { });
290
+ if (error.code === "EEXIST")
291
+ return false;
292
+ if (identity != null && recordWritten) {
293
+ await assertOwnedLockFile(lockPath, record, identity, "dashboard credential lock").then(() => unlink(lockPath), () => undefined).catch(() => { });
294
+ }
295
+ throw error;
296
+ }
297
+ });
298
+ if (!transition.entered) {
299
+ throw new Error("dashboard credential lock transition is held by another process");
300
+ }
301
+ if (transition.value !== false && transition.value != null) {
302
+ acquiredIdentity = transition.value;
303
+ break;
304
+ }
305
+ if (attempt > 0 || !(await reclaimCredentialLockIfOwnerless(lockPath))) {
306
+ throw new Error("dashboard credential directory is locked by another process");
307
+ }
308
+ }
309
+ if (acquiredIdentity == null) {
310
+ throw new Error("dashboard credential lock ownership is unknown");
311
+ }
312
+ const identity = acquiredIdentity;
313
+ await assertOwnedLockFile(lockPath, record, identity, "dashboard credential lock");
314
+ let released = false;
315
+ let heartbeatError;
316
+ let heartbeatTail = Promise.resolve();
317
+ const heartbeat = setInterval(() => {
318
+ heartbeatTail = heartbeatTail.then(async () => {
319
+ if (released || heartbeatError != null)
320
+ return;
321
+ await assertOwnedLockFile(lockPath, record, identity, "dashboard credential lock", () => heartbeatError);
322
+ const now = new Date();
323
+ await utimes(lockPath, now, now);
324
+ await assertOwnedLockFile(lockPath, record, identity, "dashboard credential lock", () => heartbeatError);
325
+ }).catch((error) => {
326
+ heartbeatError = error instanceof Error ? error : new Error(String(error));
327
+ });
328
+ }, LOCK_HEARTBEAT_MS);
329
+ heartbeat.unref();
330
+ return {
331
+ assertHealthy: async () => {
332
+ await assertOwnedLockFile(lockPath, record, identity, "dashboard credential lock", () => heartbeatError);
333
+ },
334
+ publish: async (prepared, afterRename) => {
335
+ let publicationCommitted = false;
336
+ let committedOutcome;
337
+ let transition;
338
+ try {
339
+ transition = await withCredentialLockTransition(lockPath, async (ownedTransition) => {
340
+ await testHooks.beforePublicationCriticalSection?.();
341
+ await ownedTransition.assertHealthy();
342
+ await assertOwnedLockFile(lockPath, record, identity, "dashboard credential lock", () => heartbeatError);
343
+ return ownedTransition.runCritical(() => {
344
+ if (heartbeatError != null)
345
+ throw heartbeatError;
346
+ testHooks.onPublicationCriticalSection?.("transition-renewed");
347
+ assertOwnedLockFileSync(lockPath, record, identity, "dashboard credential lock");
348
+ testHooks.onPublicationCriticalSection?.("credential-asserted");
349
+ committedOutcome = publishPreparedDocumentSync(directory, prepared, () => {
350
+ try {
351
+ afterRename();
352
+ }
353
+ finally {
354
+ publicationCommitted = true;
355
+ }
356
+ }, testHooks);
357
+ return committedOutcome;
358
+ });
359
+ });
360
+ }
361
+ catch (error) {
362
+ if (!publicationCommitted)
363
+ throw error;
364
+ return {
365
+ postPublicationError: combinePostPublicationErrors(committedOutcome?.postPublicationError, error),
366
+ };
367
+ }
368
+ if (!transition.entered) {
369
+ throw new Error("dashboard credential lock transition is busy during publication");
370
+ }
371
+ return transition.value;
372
+ },
373
+ release: async () => {
374
+ if (released)
375
+ return;
376
+ released = true;
377
+ clearInterval(heartbeat);
378
+ await heartbeatTail;
379
+ await assertOwnedLockFile(lockPath, record, identity, "dashboard credential lock", () => heartbeatError);
380
+ await unlink(lockPath);
381
+ },
382
+ };
383
+ }
384
+ function isCredentialLockRecord(value) {
385
+ if (typeof value !== "object" || value == null || Array.isArray(value))
386
+ return false;
387
+ const candidate = value;
388
+ return candidate.version === 1
389
+ && Number.isSafeInteger(candidate.pid)
390
+ && candidate.pid > 0
391
+ && typeof candidate.hostname === "string"
392
+ && candidate.hostname !== ""
393
+ && typeof candidate.token === "string"
394
+ && canonicalBase64Url(candidate.token, 16)
395
+ && typeof candidate.startedAt === "string"
396
+ && Number.isFinite(Date.parse(candidate.startedAt));
397
+ }
398
+ function assertOwnedLockFileSync(filePath, record, identity, label) {
399
+ const entry = lstatSync(filePath);
400
+ if (entry.isSymbolicLink()
401
+ || !entry.isFile()
402
+ || (entry.mode & 0o777) !== 0o600
403
+ || entry.dev !== identity.dev
404
+ || entry.ino !== identity.ino) {
405
+ throw new Error(`${label} ownership changed`);
406
+ }
407
+ let current;
408
+ try {
409
+ current = JSON.parse(readFileSync(filePath, "utf8"));
410
+ }
411
+ catch {
412
+ throw new Error(`${label} ownership changed`);
413
+ }
414
+ if (!isCredentialLockRecord(current) || current.token !== record.token) {
415
+ throw new Error(`${label} ownership changed`);
416
+ }
417
+ }
418
+ async function assertOwnedLockFile(filePath, record, identity, label, heartbeatFailure) {
419
+ const assertHeartbeatHealthy = () => {
420
+ const failure = heartbeatFailure?.();
421
+ if (failure != null)
422
+ throw failure;
423
+ };
424
+ assertHeartbeatHealthy();
425
+ try {
426
+ const before = await lstat(filePath);
427
+ if (before.isSymbolicLink()
428
+ || !before.isFile()
429
+ || (before.mode & 0o777) !== 0o600
430
+ || before.dev !== identity.dev
431
+ || before.ino !== identity.ino) {
432
+ throw new Error(`${label} ownership changed`);
433
+ }
434
+ const raw = await readFile(filePath, "utf8");
435
+ const after = await lstat(filePath);
436
+ if (after.isSymbolicLink()
437
+ || !after.isFile()
438
+ || (after.mode & 0o777) !== 0o600
439
+ || after.dev !== identity.dev
440
+ || after.ino !== identity.ino) {
441
+ throw new Error(`${label} ownership changed`);
442
+ }
443
+ let current;
444
+ try {
445
+ current = JSON.parse(raw);
446
+ }
447
+ catch {
448
+ throw new Error(`${label} ownership changed`);
449
+ }
450
+ if (!isCredentialLockRecord(current) || current.token !== record.token) {
451
+ throw new Error(`${label} ownership changed`);
452
+ }
453
+ }
454
+ catch (error) {
455
+ if (error instanceof Error && error.message === `${label} ownership changed`) {
456
+ throw error;
457
+ }
458
+ throw new Error(`${label} ownership changed`);
459
+ }
460
+ assertHeartbeatHealthy();
461
+ }
462
+ async function assertUnchangedRegularFile(filePath, identity, expectedRaw, label) {
463
+ try {
464
+ const before = await lstat(filePath);
465
+ if (before.isSymbolicLink()
466
+ || !before.isFile()
467
+ || (before.mode & 0o777) !== 0o600
468
+ || before.dev !== identity.dev
469
+ || before.ino !== identity.ino) {
470
+ throw new Error(`${label} ownership changed`);
471
+ }
472
+ const raw = await readFile(filePath, "utf8");
473
+ const after = await lstat(filePath);
474
+ if (raw !== expectedRaw
475
+ || after.isSymbolicLink()
476
+ || !after.isFile()
477
+ || (after.mode & 0o777) !== 0o600
478
+ || after.dev !== identity.dev
479
+ || after.ino !== identity.ino) {
480
+ throw new Error(`${label} ownership changed`);
481
+ }
482
+ }
483
+ catch (error) {
484
+ if (error instanceof Error && error.message === `${label} ownership changed`) {
485
+ throw error;
486
+ }
487
+ throw new Error(`${label} ownership changed`);
488
+ }
489
+ }
490
+ async function reclaimCredentialLockIfOwnerless(lockPath) {
491
+ const transition = await withCredentialLockTransition(lockPath, async () => {
492
+ let raw;
493
+ let lockStat;
494
+ try {
495
+ lockStat = await lstat(lockPath);
496
+ }
497
+ catch (error) {
498
+ if (error.code === "ENOENT")
499
+ return true;
500
+ throw error;
501
+ }
502
+ if (lockStat.isSymbolicLink()
503
+ || !lockStat.isFile()
504
+ || (lockStat.mode & 0o777) !== 0o600) {
505
+ throw new Error("dashboard credential lock ownership is unknown");
506
+ }
507
+ try {
508
+ raw = await readFile(lockPath, "utf8");
509
+ }
510
+ catch (error) {
511
+ if (error.code === "ENOENT")
512
+ return true;
513
+ throw error;
514
+ }
515
+ let value;
516
+ try {
517
+ value = JSON.parse(raw);
518
+ }
519
+ catch {
520
+ throw new Error("dashboard credential lock ownership is unknown");
521
+ }
522
+ if (!isCredentialLockRecord(value)) {
523
+ throw new Error("dashboard credential lock ownership is unknown");
524
+ }
525
+ const provablyOwnerless = Date.now() - lockStat.mtimeMs > LOCK_STALE_MS;
526
+ if (!provablyOwnerless)
527
+ return false;
528
+ await assertOwnedLockFile(lockPath, value, { dev: lockStat.dev, ino: lockStat.ino }, "dashboard credential lock");
529
+ await unlink(lockPath);
530
+ return true;
531
+ });
532
+ return transition.entered && transition.value === true;
533
+ }
534
+ async function assertSecureCredentialFile(filePath) {
535
+ const entry = await lstat(filePath);
536
+ if (entry.isSymbolicLink() || !entry.isFile()) {
537
+ throw new Error("dashboard credential store must be a regular file");
538
+ }
539
+ if ((entry.mode & 0o777) !== 0o600) {
540
+ throw new Error("dashboard credential store permissions must be 0600");
541
+ }
542
+ if (entry.size > MAX_CREDENTIAL_FILE_BYTES) {
543
+ throw new Error("dashboard credential store exceeds the 256 KiB limit");
544
+ }
545
+ }
546
+ async function prepareDocumentPublication(directory, document) {
547
+ const parsed = CredentialDocumentSchema.parse(document);
548
+ const serialized = `${JSON.stringify(parsed, null, 2)}\n`;
549
+ if (Buffer.byteLength(serialized, "utf8") > MAX_CREDENTIAL_FILE_BYTES) {
550
+ throw new Error("dashboard credential store exceeds the 256 KiB limit");
551
+ }
552
+ const filePath = join(directory, CREDENTIAL_FILENAME);
553
+ const temporaryPath = join(directory, `.${CREDENTIAL_FILENAME}.${String(process.pid)}.${randomBytes(8).toString("hex")}.tmp`);
554
+ const handle = await open(temporaryPath, "wx", 0o600);
555
+ try {
556
+ await handle.writeFile(serialized, "utf8");
557
+ await handle.sync();
558
+ }
559
+ catch (error) {
560
+ await handle.close().catch(() => { });
561
+ await unlink(temporaryPath).catch(() => { });
562
+ throw error;
563
+ }
564
+ await handle.close();
565
+ return { filePath, temporaryPath };
566
+ }
567
+ function publishPreparedDocumentSync(directory, prepared, afterRename, testHooks) {
568
+ renameSync(prepared.temporaryPath, prepared.filePath);
569
+ testHooks.onPublicationCriticalSection?.("renamed");
570
+ const errors = [];
571
+ try {
572
+ afterRename();
573
+ }
574
+ catch (error) {
575
+ errors.push(error);
576
+ }
577
+ testHooks.onPublicationCriticalSection?.("after-commit");
578
+ let descriptor;
579
+ try {
580
+ descriptor = (testHooks.openDirectorySync ?? ((path) => openSync(path, "r")))(directory);
581
+ testHooks.onPublicationCriticalSection?.("directory-opened");
582
+ try {
583
+ (testHooks.fsyncDirectorySync ?? fsyncSync)(descriptor);
584
+ testHooks.onPublicationCriticalSection?.("directory-fsynced");
585
+ }
586
+ catch (error) {
587
+ errors.push(error);
588
+ }
589
+ }
590
+ catch (error) {
591
+ errors.push(error);
592
+ }
593
+ finally {
594
+ if (descriptor != null) {
595
+ try {
596
+ (testHooks.closeDirectorySync ?? closeSync)(descriptor);
597
+ testHooks.onPublicationCriticalSection?.("directory-closed");
598
+ }
599
+ catch (error) {
600
+ errors.push(error);
601
+ }
602
+ }
603
+ }
604
+ if (errors.length === 0)
605
+ return {};
606
+ return {
607
+ postPublicationError: combinePostPublicationErrors(...errors),
608
+ };
609
+ }
610
+ function flattenPostPublicationError(error) {
611
+ if (error instanceof AggregateError) {
612
+ return Array.from(error.errors).flatMap(flattenPostPublicationError);
613
+ }
614
+ return [error];
615
+ }
616
+ function combinePostPublicationErrors(...errors) {
617
+ const flattened = errors.flatMap((error) => error == null
618
+ ? []
619
+ : flattenPostPublicationError(error));
620
+ if (flattened.length === 0)
621
+ return undefined;
622
+ if (flattened.length === 1)
623
+ return flattened[0];
624
+ return new AggregateError(flattened, "dashboard credential publication had multiple failures");
625
+ }
626
+ async function publishDocument(lock, directory, document, afterRename) {
627
+ const prepared = await prepareDocumentPublication(directory, document);
628
+ try {
629
+ return await lock.publish(prepared, afterRename);
630
+ }
631
+ catch (error) {
632
+ await unlink(prepared.temporaryPath).catch(() => { });
633
+ throw error;
634
+ }
635
+ }
636
+ function boundedDiagnosticText(value, limit) {
637
+ return value
638
+ .slice(0, limit)
639
+ .replace(/[A-Za-z0-9_-]{16,}/g, "[redacted]")
640
+ .replace(/\bcounter\s*(?:[:=]\s*)?\d+\b/gi, "counter [redacted]");
641
+ }
642
+ function safeDiagnosticCause(error) {
643
+ if (!(error instanceof Error)) {
644
+ return { name: "UnknownError", message: "non-Error failure" };
645
+ }
646
+ return {
647
+ name: boundedDiagnosticText(error.name, MAX_DIAGNOSTIC_NAME_LENGTH),
648
+ message: boundedDiagnosticText(error.message, MAX_DIAGNOSTIC_MESSAGE_LENGTH),
649
+ };
650
+ }
651
+ function safeDiagnosticError(error) {
652
+ const root = safeDiagnosticCause(error);
653
+ if (!(error instanceof AggregateError))
654
+ return root;
655
+ return {
656
+ ...root,
657
+ causes: Array.from(error.errors)
658
+ .slice(0, MAX_DIAGNOSTIC_CAUSES)
659
+ .map(safeDiagnosticCause),
660
+ };
661
+ }
662
+ function emitPostPublicationDiagnostic(error, testHooks) {
663
+ const diagnostic = {
664
+ code: "dashboard_credential_store_post_publication_failure",
665
+ error: safeDiagnosticError(error),
666
+ };
667
+ try {
668
+ if (testHooks.onPostPublicationDiagnostic != null) {
669
+ testHooks.onPostPublicationDiagnostic(diagnostic);
670
+ return;
671
+ }
672
+ logger.error({
673
+ code: diagnostic.code,
674
+ error: diagnostic.error,
675
+ }, "dashboard credential store entered post-publication failure; mutations are disabled until process restart/reopen");
676
+ }
677
+ catch {
678
+ // Diagnostics must not replace the captured publication failure.
679
+ }
680
+ }
681
+ export class DashboardCredentialStore {
682
+ #directory;
683
+ #expectedRPID;
684
+ #lock;
685
+ #testHooks;
686
+ #document;
687
+ #writeTail = Promise.resolve();
688
+ #postPublicationFailure = false;
689
+ #closed = false;
690
+ constructor(options, lock, document) {
691
+ this.#directory = options.directory;
692
+ this.#expectedRPID = options.expectedRPID;
693
+ this.#lock = lock;
694
+ this.#testHooks = options.testHooks ?? {};
695
+ this.#document = document;
696
+ }
697
+ static async open(options) {
698
+ await assertSecureDirectory(options.directory);
699
+ const lock = await acquireCredentialDirectoryLock(options.directory, options.testHooks);
700
+ try {
701
+ const filePath = join(options.directory, CREDENTIAL_FILENAME);
702
+ let document;
703
+ try {
704
+ await assertSecureCredentialFile(filePath);
705
+ const raw = await readFile(filePath);
706
+ if (raw.byteLength > MAX_CREDENTIAL_FILE_BYTES) {
707
+ throw new Error("dashboard credential store exceeds the 256 KiB limit");
708
+ }
709
+ document = parseDocument(JSON.parse(raw.toString("utf8")), options.expectedRPID);
710
+ }
711
+ catch (error) {
712
+ if (error.code !== "ENOENT")
713
+ throw error;
714
+ document = {
715
+ version: CREDENTIAL_STORE_VERSION,
716
+ userHandle: randomBytes(16).toString("base64url"),
717
+ rpId: options.expectedRPID,
718
+ credentials: [],
719
+ };
720
+ const publication = await publishDocument(lock, options.directory, document, () => { });
721
+ if (publication.postPublicationError != null) {
722
+ throw publication.postPublicationError;
723
+ }
724
+ }
725
+ return new DashboardCredentialStore(options, lock, document);
726
+ }
727
+ catch (error) {
728
+ await lock.release().catch(() => { });
729
+ throw error;
730
+ }
731
+ }
732
+ read() {
733
+ if (this.#closed)
734
+ throw new Error("dashboard credential store is closed");
735
+ return cloneDocument(this.#document);
736
+ }
737
+ mutate(operation) {
738
+ if (this.#closed) {
739
+ return Promise.reject(new Error("dashboard credential store is closed"));
740
+ }
741
+ if (this.#postPublicationFailure) {
742
+ return Promise.reject(this.#postPublicationFailureError());
743
+ }
744
+ const run = this.#writeTail.then(async () => {
745
+ if (this.#postPublicationFailure) {
746
+ throw this.#postPublicationFailureError();
747
+ }
748
+ await this.#lock.assertHealthy();
749
+ const mutation = await operation(cloneDocument(this.#document));
750
+ const next = parseDocument(mutation.document, this.#expectedRPID);
751
+ const publication = await publishDocument(this.#lock, this.#directory, next, () => {
752
+ this.#document = next;
753
+ mutation.afterCommit?.();
754
+ });
755
+ if (publication.postPublicationError != null) {
756
+ this.#postPublicationFailure = true;
757
+ emitPostPublicationDiagnostic(publication.postPublicationError, this.#testHooks);
758
+ throw publication.postPublicationError;
759
+ }
760
+ return mutation.result;
761
+ });
762
+ this.#writeTail = run.then(() => { }, () => { });
763
+ return run;
764
+ }
765
+ #postPublicationFailureError() {
766
+ return new Error("dashboard credential store is disabled after a post-publication failure; process restart/reopen is required");
767
+ }
768
+ async close() {
769
+ if (this.#closed)
770
+ return;
771
+ this.#closed = true;
772
+ await this.#writeTail;
773
+ await this.#lock.release();
774
+ }
775
+ }
776
+ //# sourceMappingURL=credential-store.js.map