@actsecurity/iam-lens 0.1.156

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 (383) hide show
  1. package/LICENSE.txt +661 -0
  2. package/README.md +203 -0
  3. package/dist/cjs/cli.d.ts +3 -0
  4. package/dist/cjs/cli.d.ts.map +1 -0
  5. package/dist/cjs/cli.js +206 -0
  6. package/dist/cjs/cli.js.map +1 -0
  7. package/dist/cjs/collect/client.d.ts +550 -0
  8. package/dist/cjs/collect/client.d.ts.map +1 -0
  9. package/dist/cjs/collect/client.js +1119 -0
  10. package/dist/cjs/collect/client.js.map +1 -0
  11. package/dist/cjs/collect/collect.d.ts +44 -0
  12. package/dist/cjs/collect/collect.d.ts.map +1 -0
  13. package/dist/cjs/collect/collect.js +55 -0
  14. package/dist/cjs/collect/collect.js.map +1 -0
  15. package/dist/cjs/collect/inMemoryClient.d.ts +6 -0
  16. package/dist/cjs/collect/inMemoryClient.d.ts.map +1 -0
  17. package/dist/cjs/collect/inMemoryClient.js +11 -0
  18. package/dist/cjs/collect/inMemoryClient.js.map +1 -0
  19. package/dist/cjs/index.d.ts +13 -0
  20. package/dist/cjs/index.d.ts.map +1 -0
  21. package/dist/cjs/index.js +28 -0
  22. package/dist/cjs/index.js.map +1 -0
  23. package/dist/cjs/package.json +3 -0
  24. package/dist/cjs/principalCan/permission.d.ts +125 -0
  25. package/dist/cjs/principalCan/permission.d.ts.map +1 -0
  26. package/dist/cjs/principalCan/permission.js +1229 -0
  27. package/dist/cjs/principalCan/permission.js.map +1 -0
  28. package/dist/cjs/principalCan/permissionSet.d.ts +140 -0
  29. package/dist/cjs/principalCan/permissionSet.d.ts.map +1 -0
  30. package/dist/cjs/principalCan/permissionSet.js +437 -0
  31. package/dist/cjs/principalCan/permissionSet.js.map +1 -0
  32. package/dist/cjs/principalCan/principalCan.d.ts +26 -0
  33. package/dist/cjs/principalCan/principalCan.d.ts.map +1 -0
  34. package/dist/cjs/principalCan/principalCan.js +195 -0
  35. package/dist/cjs/principalCan/principalCan.js.map +1 -0
  36. package/dist/cjs/principalCan/principalConstraints.d.ts +147 -0
  37. package/dist/cjs/principalCan/principalConstraints.d.ts.map +1 -0
  38. package/dist/cjs/principalCan/principalConstraints.js +472 -0
  39. package/dist/cjs/principalCan/principalConstraints.js.map +1 -0
  40. package/dist/cjs/principalCan/resources/actions.d.ts +9 -0
  41. package/dist/cjs/principalCan/resources/actions.d.ts.map +1 -0
  42. package/dist/cjs/principalCan/resources/actions.js +27 -0
  43. package/dist/cjs/principalCan/resources/actions.js.map +1 -0
  44. package/dist/cjs/principalCan/resources/resourceTypes/iamRoles.d.ts +31 -0
  45. package/dist/cjs/principalCan/resources/resourceTypes/iamRoles.d.ts.map +1 -0
  46. package/dist/cjs/principalCan/resources/resourceTypes/iamRoles.js +114 -0
  47. package/dist/cjs/principalCan/resources/resourceTypes/iamRoles.js.map +1 -0
  48. package/dist/cjs/principalCan/resources/resourceTypes/kmsKeys.d.ts +30 -0
  49. package/dist/cjs/principalCan/resources/resourceTypes/kmsKeys.d.ts.map +1 -0
  50. package/dist/cjs/principalCan/resources/resourceTypes/kmsKeys.js +110 -0
  51. package/dist/cjs/principalCan/resources/resourceTypes/kmsKeys.js.map +1 -0
  52. package/dist/cjs/principalCan/resources/resourceTypes/s3Buckets.d.ts +18 -0
  53. package/dist/cjs/principalCan/resources/resourceTypes/s3Buckets.d.ts.map +1 -0
  54. package/dist/cjs/principalCan/resources/resourceTypes/s3Buckets.js +123 -0
  55. package/dist/cjs/principalCan/resources/resourceTypes/s3Buckets.js.map +1 -0
  56. package/dist/cjs/principalCan/resources/statements.d.ts +27 -0
  57. package/dist/cjs/principalCan/resources/statements.d.ts.map +1 -0
  58. package/dist/cjs/principalCan/resources/statements.js +119 -0
  59. package/dist/cjs/principalCan/resources/statements.js.map +1 -0
  60. package/dist/cjs/principalIndex/makePrincipalIndex.d.ts +8 -0
  61. package/dist/cjs/principalIndex/makePrincipalIndex.d.ts.map +1 -0
  62. package/dist/cjs/principalIndex/makePrincipalIndex.js +105 -0
  63. package/dist/cjs/principalIndex/makePrincipalIndex.js.map +1 -0
  64. package/dist/cjs/principals.d.ts +54 -0
  65. package/dist/cjs/principals.d.ts.map +1 -0
  66. package/dist/cjs/principals.js +143 -0
  67. package/dist/cjs/principals.js.map +1 -0
  68. package/dist/cjs/resources.d.ts +32 -0
  69. package/dist/cjs/resources.d.ts.map +1 -0
  70. package/dist/cjs/resources.js +71 -0
  71. package/dist/cjs/resources.js.map +1 -0
  72. package/dist/cjs/simulate/contextKeys.d.ts +68 -0
  73. package/dist/cjs/simulate/contextKeys.d.ts.map +1 -0
  74. package/dist/cjs/simulate/contextKeys.js +293 -0
  75. package/dist/cjs/simulate/contextKeys.js.map +1 -0
  76. package/dist/cjs/simulate/simulate.d.ts +72 -0
  77. package/dist/cjs/simulate/simulate.d.ts.map +1 -0
  78. package/dist/cjs/simulate/simulate.js +296 -0
  79. package/dist/cjs/simulate/simulate.js.map +1 -0
  80. package/dist/cjs/test-datasets/testClient.d.ts +17 -0
  81. package/dist/cjs/test-datasets/testClient.d.ts.map +1 -0
  82. package/dist/cjs/test-datasets/testClient.js +58 -0
  83. package/dist/cjs/test-datasets/testClient.js.map +1 -0
  84. package/dist/cjs/utils/arn.d.ts +22 -0
  85. package/dist/cjs/utils/arn.d.ts.map +1 -0
  86. package/dist/cjs/utils/arn.js +49 -0
  87. package/dist/cjs/utils/arn.js.map +1 -0
  88. package/dist/cjs/utils/bitset.d.ts +45 -0
  89. package/dist/cjs/utils/bitset.d.ts.map +1 -0
  90. package/dist/cjs/utils/bitset.js +149 -0
  91. package/dist/cjs/utils/bitset.js.map +1 -0
  92. package/dist/cjs/utils/dynamicImport.d.ts +31 -0
  93. package/dist/cjs/utils/dynamicImport.d.ts.map +1 -0
  94. package/dist/cjs/utils/dynamicImport.js +64 -0
  95. package/dist/cjs/utils/dynamicImport.js.map +1 -0
  96. package/dist/cjs/utils/packageVersion.d.ts +5 -0
  97. package/dist/cjs/utils/packageVersion.d.ts.map +1 -0
  98. package/dist/cjs/utils/packageVersion.js +25 -0
  99. package/dist/cjs/utils/packageVersion.js.map +1 -0
  100. package/dist/cjs/utils/readPackageFile.d.ts +3 -0
  101. package/dist/cjs/utils/readPackageFile.d.ts.map +1 -0
  102. package/dist/cjs/utils/readPackageFile.js +16 -0
  103. package/dist/cjs/utils/readPackageFile.js.map +1 -0
  104. package/dist/cjs/utils/s3Abac.d.ts +3 -0
  105. package/dist/cjs/utils/s3Abac.d.ts.map +1 -0
  106. package/dist/cjs/utils/s3Abac.js +5 -0
  107. package/dist/cjs/utils/s3Abac.js.map +1 -0
  108. package/dist/cjs/utils/stringOrFileArgument.d.ts +9 -0
  109. package/dist/cjs/utils/stringOrFileArgument.d.ts.map +1 -0
  110. package/dist/cjs/utils/stringOrFileArgument.js +25 -0
  111. package/dist/cjs/utils/stringOrFileArgument.js.map +1 -0
  112. package/dist/cjs/utils/sts.d.ts +2 -0
  113. package/dist/cjs/utils/sts.d.ts.map +1 -0
  114. package/dist/cjs/utils/sts.js +9 -0
  115. package/dist/cjs/utils/sts.js.map +1 -0
  116. package/dist/cjs/utils/testUtils.d.ts +56 -0
  117. package/dist/cjs/utils/testUtils.d.ts.map +1 -0
  118. package/dist/cjs/utils/testUtils.js +95 -0
  119. package/dist/cjs/utils/testUtils.js.map +1 -0
  120. package/dist/cjs/utils/workerScript.d.ts +8 -0
  121. package/dist/cjs/utils/workerScript.d.ts.map +1 -0
  122. package/dist/cjs/utils/workerScript.js +23 -0
  123. package/dist/cjs/utils/workerScript.js.map +1 -0
  124. package/dist/cjs/whoCan/WhoCanMainThreadWorker.d.ts +73 -0
  125. package/dist/cjs/whoCan/WhoCanMainThreadWorker.d.ts.map +1 -0
  126. package/dist/cjs/whoCan/WhoCanMainThreadWorker.js +80 -0
  127. package/dist/cjs/whoCan/WhoCanMainThreadWorker.js.map +1 -0
  128. package/dist/cjs/whoCan/WhoCanProcessor.d.ts +400 -0
  129. package/dist/cjs/whoCan/WhoCanProcessor.d.ts.map +1 -0
  130. package/dist/cjs/whoCan/WhoCanProcessor.js +1088 -0
  131. package/dist/cjs/whoCan/WhoCanProcessor.js.map +1 -0
  132. package/dist/cjs/whoCan/WhoCanWorker.d.ts +87 -0
  133. package/dist/cjs/whoCan/WhoCanWorker.d.ts.map +1 -0
  134. package/dist/cjs/whoCan/WhoCanWorker.js +201 -0
  135. package/dist/cjs/whoCan/WhoCanWorker.js.map +1 -0
  136. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.d.ts +2 -0
  137. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.d.ts.map +1 -0
  138. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.js +189 -0
  139. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.js.map +1 -0
  140. package/dist/cjs/whoCan/principalArnFilter.d.ts +84 -0
  141. package/dist/cjs/whoCan/principalArnFilter.d.ts.map +1 -0
  142. package/dist/cjs/whoCan/principalArnFilter.js +258 -0
  143. package/dist/cjs/whoCan/principalArnFilter.js.map +1 -0
  144. package/dist/cjs/whoCan/principalScope.d.ts +35 -0
  145. package/dist/cjs/whoCan/principalScope.d.ts.map +1 -0
  146. package/dist/cjs/whoCan/principalScope.js +104 -0
  147. package/dist/cjs/whoCan/principalScope.js.map +1 -0
  148. package/dist/cjs/whoCan/requestAnalysis.d.ts +73 -0
  149. package/dist/cjs/whoCan/requestAnalysis.d.ts.map +1 -0
  150. package/dist/cjs/whoCan/requestAnalysis.js +87 -0
  151. package/dist/cjs/whoCan/requestAnalysis.js.map +1 -0
  152. package/dist/cjs/whoCan/untrustingActions.d.ts +7 -0
  153. package/dist/cjs/whoCan/untrustingActions.d.ts.map +1 -0
  154. package/dist/cjs/whoCan/untrustingActions.js +30 -0
  155. package/dist/cjs/whoCan/untrustingActions.js.map +1 -0
  156. package/dist/cjs/whoCan/whoCan.d.ts +295 -0
  157. package/dist/cjs/whoCan/whoCan.d.ts.map +1 -0
  158. package/dist/cjs/whoCan/whoCan.js +574 -0
  159. package/dist/cjs/whoCan/whoCan.js.map +1 -0
  160. package/dist/cjs/whoCan/workerBootstrapPlugin.d.ts +17 -0
  161. package/dist/cjs/whoCan/workerBootstrapPlugin.d.ts.map +1 -0
  162. package/dist/cjs/whoCan/workerBootstrapPlugin.js +3 -0
  163. package/dist/cjs/whoCan/workerBootstrapPlugin.js.map +1 -0
  164. package/dist/cjs/workers/ArrayStreamingWorkQueue.d.ts +15 -0
  165. package/dist/cjs/workers/ArrayStreamingWorkQueue.d.ts.map +1 -0
  166. package/dist/cjs/workers/ArrayStreamingWorkQueue.js +35 -0
  167. package/dist/cjs/workers/ArrayStreamingWorkQueue.js.map +1 -0
  168. package/dist/cjs/workers/JobRunner.d.ts +47 -0
  169. package/dist/cjs/workers/JobRunner.d.ts.map +1 -0
  170. package/dist/cjs/workers/JobRunner.js +101 -0
  171. package/dist/cjs/workers/JobRunner.js.map +1 -0
  172. package/dist/cjs/workers/RingQueue.d.ts +14 -0
  173. package/dist/cjs/workers/RingQueue.d.ts.map +1 -0
  174. package/dist/cjs/workers/RingQueue.js +43 -0
  175. package/dist/cjs/workers/RingQueue.js.map +1 -0
  176. package/dist/cjs/workers/SharedArrayBufferMainCache.d.ts +10 -0
  177. package/dist/cjs/workers/SharedArrayBufferMainCache.d.ts.map +1 -0
  178. package/dist/cjs/workers/SharedArrayBufferMainCache.js +37 -0
  179. package/dist/cjs/workers/SharedArrayBufferMainCache.js.map +1 -0
  180. package/dist/cjs/workers/SharedArrayBufferWorkerCache.d.ts +10 -0
  181. package/dist/cjs/workers/SharedArrayBufferWorkerCache.d.ts.map +1 -0
  182. package/dist/cjs/workers/SharedArrayBufferWorkerCache.js +49 -0
  183. package/dist/cjs/workers/SharedArrayBufferWorkerCache.js.map +1 -0
  184. package/dist/cjs/workers/StreamingWorkQueue.d.ts +18 -0
  185. package/dist/cjs/workers/StreamingWorkQueue.d.ts.map +1 -0
  186. package/dist/cjs/workers/StreamingWorkQueue.js +67 -0
  187. package/dist/cjs/workers/StreamingWorkQueue.js.map +1 -0
  188. package/dist/cjs/workers/buffers.d.ts +4 -0
  189. package/dist/cjs/workers/buffers.d.ts.map +1 -0
  190. package/dist/cjs/workers/buffers.js +26 -0
  191. package/dist/cjs/workers/buffers.js.map +1 -0
  192. package/dist/esm/cli.d.ts +3 -0
  193. package/dist/esm/cli.d.ts.map +1 -0
  194. package/dist/esm/cli.js +204 -0
  195. package/dist/esm/cli.js.map +1 -0
  196. package/dist/esm/collect/client.d.ts +550 -0
  197. package/dist/esm/collect/client.d.ts.map +1 -0
  198. package/dist/esm/collect/client.js +1114 -0
  199. package/dist/esm/collect/client.js.map +1 -0
  200. package/dist/esm/collect/collect.d.ts +44 -0
  201. package/dist/esm/collect/collect.d.ts.map +1 -0
  202. package/dist/esm/collect/collect.js +51 -0
  203. package/dist/esm/collect/collect.js.map +1 -0
  204. package/dist/esm/collect/inMemoryClient.d.ts +6 -0
  205. package/dist/esm/collect/inMemoryClient.d.ts.map +1 -0
  206. package/dist/esm/collect/inMemoryClient.js +8 -0
  207. package/dist/esm/collect/inMemoryClient.js.map +1 -0
  208. package/dist/esm/index.d.ts +13 -0
  209. package/dist/esm/index.d.ts.map +1 -0
  210. package/dist/esm/index.js +11 -0
  211. package/dist/esm/index.js.map +1 -0
  212. package/dist/esm/package.json +3 -0
  213. package/dist/esm/principalCan/permission.d.ts +125 -0
  214. package/dist/esm/principalCan/permission.d.ts.map +1 -0
  215. package/dist/esm/principalCan/permission.js +1212 -0
  216. package/dist/esm/principalCan/permission.js.map +1 -0
  217. package/dist/esm/principalCan/permissionSet.d.ts +140 -0
  218. package/dist/esm/principalCan/permissionSet.d.ts.map +1 -0
  219. package/dist/esm/principalCan/permissionSet.js +429 -0
  220. package/dist/esm/principalCan/permissionSet.js.map +1 -0
  221. package/dist/esm/principalCan/principalCan.d.ts +26 -0
  222. package/dist/esm/principalCan/principalCan.d.ts.map +1 -0
  223. package/dist/esm/principalCan/principalCan.js +193 -0
  224. package/dist/esm/principalCan/principalCan.js.map +1 -0
  225. package/dist/esm/principalCan/principalConstraints.d.ts +147 -0
  226. package/dist/esm/principalCan/principalConstraints.d.ts.map +1 -0
  227. package/dist/esm/principalCan/principalConstraints.js +456 -0
  228. package/dist/esm/principalCan/principalConstraints.js.map +1 -0
  229. package/dist/esm/principalCan/resources/actions.d.ts +9 -0
  230. package/dist/esm/principalCan/resources/actions.d.ts.map +1 -0
  231. package/dist/esm/principalCan/resources/actions.js +24 -0
  232. package/dist/esm/principalCan/resources/actions.js.map +1 -0
  233. package/dist/esm/principalCan/resources/resourceTypes/iamRoles.d.ts +31 -0
  234. package/dist/esm/principalCan/resources/resourceTypes/iamRoles.d.ts.map +1 -0
  235. package/dist/esm/principalCan/resources/resourceTypes/iamRoles.js +110 -0
  236. package/dist/esm/principalCan/resources/resourceTypes/iamRoles.js.map +1 -0
  237. package/dist/esm/principalCan/resources/resourceTypes/kmsKeys.d.ts +30 -0
  238. package/dist/esm/principalCan/resources/resourceTypes/kmsKeys.d.ts.map +1 -0
  239. package/dist/esm/principalCan/resources/resourceTypes/kmsKeys.js +106 -0
  240. package/dist/esm/principalCan/resources/resourceTypes/kmsKeys.js.map +1 -0
  241. package/dist/esm/principalCan/resources/resourceTypes/s3Buckets.d.ts +18 -0
  242. package/dist/esm/principalCan/resources/resourceTypes/s3Buckets.d.ts.map +1 -0
  243. package/dist/esm/principalCan/resources/resourceTypes/s3Buckets.js +120 -0
  244. package/dist/esm/principalCan/resources/resourceTypes/s3Buckets.js.map +1 -0
  245. package/dist/esm/principalCan/resources/statements.d.ts +27 -0
  246. package/dist/esm/principalCan/resources/statements.d.ts.map +1 -0
  247. package/dist/esm/principalCan/resources/statements.js +117 -0
  248. package/dist/esm/principalCan/resources/statements.js.map +1 -0
  249. package/dist/esm/principalIndex/makePrincipalIndex.d.ts +8 -0
  250. package/dist/esm/principalIndex/makePrincipalIndex.d.ts.map +1 -0
  251. package/dist/esm/principalIndex/makePrincipalIndex.js +104 -0
  252. package/dist/esm/principalIndex/makePrincipalIndex.js.map +1 -0
  253. package/dist/esm/principals.d.ts +54 -0
  254. package/dist/esm/principals.d.ts.map +1 -0
  255. package/dist/esm/principals.js +133 -0
  256. package/dist/esm/principals.js.map +1 -0
  257. package/dist/esm/resources.d.ts +32 -0
  258. package/dist/esm/resources.d.ts.map +1 -0
  259. package/dist/esm/resources.js +69 -0
  260. package/dist/esm/resources.js.map +1 -0
  261. package/dist/esm/simulate/contextKeys.d.ts +68 -0
  262. package/dist/esm/simulate/contextKeys.d.ts.map +1 -0
  263. package/dist/esm/simulate/contextKeys.js +287 -0
  264. package/dist/esm/simulate/contextKeys.js.map +1 -0
  265. package/dist/esm/simulate/simulate.d.ts +72 -0
  266. package/dist/esm/simulate/simulate.d.ts.map +1 -0
  267. package/dist/esm/simulate/simulate.js +295 -0
  268. package/dist/esm/simulate/simulate.js.map +1 -0
  269. package/dist/esm/test-datasets/testClient.d.ts +17 -0
  270. package/dist/esm/test-datasets/testClient.d.ts.map +1 -0
  271. package/dist/esm/test-datasets/testClient.js +56 -0
  272. package/dist/esm/test-datasets/testClient.js.map +1 -0
  273. package/dist/esm/utils/arn.d.ts +22 -0
  274. package/dist/esm/utils/arn.d.ts.map +1 -0
  275. package/dist/esm/utils/arn.js +43 -0
  276. package/dist/esm/utils/arn.js.map +1 -0
  277. package/dist/esm/utils/bitset.d.ts +45 -0
  278. package/dist/esm/utils/bitset.d.ts.map +1 -0
  279. package/dist/esm/utils/bitset.js +141 -0
  280. package/dist/esm/utils/bitset.js.map +1 -0
  281. package/dist/esm/utils/dynamicImport.d.ts +31 -0
  282. package/dist/esm/utils/dynamicImport.d.ts.map +1 -0
  283. package/dist/esm/utils/dynamicImport.js +60 -0
  284. package/dist/esm/utils/dynamicImport.js.map +1 -0
  285. package/dist/esm/utils/packageVersion.d.ts +5 -0
  286. package/dist/esm/utils/packageVersion.d.ts.map +1 -0
  287. package/dist/esm/utils/packageVersion.js +22 -0
  288. package/dist/esm/utils/packageVersion.js.map +1 -0
  289. package/dist/esm/utils/readPackageFile.d.ts +3 -0
  290. package/dist/esm/utils/readPackageFile.d.ts.map +1 -0
  291. package/dist/esm/utils/readPackageFile.js +15 -0
  292. package/dist/esm/utils/readPackageFile.js.map +1 -0
  293. package/dist/esm/utils/readPackageFileEsm.d.ts.map +1 -0
  294. package/dist/esm/utils/s3Abac.d.ts +3 -0
  295. package/dist/esm/utils/s3Abac.d.ts.map +1 -0
  296. package/dist/esm/utils/s3Abac.js +2 -0
  297. package/dist/esm/utils/s3Abac.js.map +1 -0
  298. package/dist/esm/utils/stringOrFileArgument.d.ts +9 -0
  299. package/dist/esm/utils/stringOrFileArgument.d.ts.map +1 -0
  300. package/dist/esm/utils/stringOrFileArgument.js +22 -0
  301. package/dist/esm/utils/stringOrFileArgument.js.map +1 -0
  302. package/dist/esm/utils/sts.d.ts +2 -0
  303. package/dist/esm/utils/sts.d.ts.map +1 -0
  304. package/dist/esm/utils/sts.js +6 -0
  305. package/dist/esm/utils/sts.js.map +1 -0
  306. package/dist/esm/utils/testUtils.d.ts +56 -0
  307. package/dist/esm/utils/testUtils.d.ts.map +1 -0
  308. package/dist/esm/utils/testUtils.js +90 -0
  309. package/dist/esm/utils/testUtils.js.map +1 -0
  310. package/dist/esm/utils/workerScript.d.ts +8 -0
  311. package/dist/esm/utils/workerScript.d.ts.map +1 -0
  312. package/dist/esm/utils/workerScript.js +18 -0
  313. package/dist/esm/utils/workerScript.js.map +1 -0
  314. package/dist/esm/utils/workerScriptEsm.d.ts.map +1 -0
  315. package/dist/esm/whoCan/WhoCanMainThreadWorker.d.ts +73 -0
  316. package/dist/esm/whoCan/WhoCanMainThreadWorker.d.ts.map +1 -0
  317. package/dist/esm/whoCan/WhoCanMainThreadWorker.js +81 -0
  318. package/dist/esm/whoCan/WhoCanMainThreadWorker.js.map +1 -0
  319. package/dist/esm/whoCan/WhoCanProcessor.d.ts +400 -0
  320. package/dist/esm/whoCan/WhoCanProcessor.d.ts.map +1 -0
  321. package/dist/esm/whoCan/WhoCanProcessor.js +1080 -0
  322. package/dist/esm/whoCan/WhoCanProcessor.js.map +1 -0
  323. package/dist/esm/whoCan/WhoCanWorker.d.ts +87 -0
  324. package/dist/esm/whoCan/WhoCanWorker.d.ts.map +1 -0
  325. package/dist/esm/whoCan/WhoCanWorker.js +198 -0
  326. package/dist/esm/whoCan/WhoCanWorker.js.map +1 -0
  327. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.d.ts +2 -0
  328. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.d.ts.map +1 -0
  329. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.js +193 -0
  330. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.js.map +1 -0
  331. package/dist/esm/whoCan/principalArnFilter.d.ts +84 -0
  332. package/dist/esm/whoCan/principalArnFilter.d.ts.map +1 -0
  333. package/dist/esm/whoCan/principalArnFilter.js +253 -0
  334. package/dist/esm/whoCan/principalArnFilter.js.map +1 -0
  335. package/dist/esm/whoCan/principalScope.d.ts +35 -0
  336. package/dist/esm/whoCan/principalScope.d.ts.map +1 -0
  337. package/dist/esm/whoCan/principalScope.js +102 -0
  338. package/dist/esm/whoCan/principalScope.js.map +1 -0
  339. package/dist/esm/whoCan/requestAnalysis.d.ts +73 -0
  340. package/dist/esm/whoCan/requestAnalysis.d.ts.map +1 -0
  341. package/dist/esm/whoCan/requestAnalysis.js +83 -0
  342. package/dist/esm/whoCan/requestAnalysis.js.map +1 -0
  343. package/dist/esm/whoCan/untrustingActions.d.ts +7 -0
  344. package/dist/esm/whoCan/untrustingActions.d.ts.map +1 -0
  345. package/dist/esm/whoCan/untrustingActions.js +27 -0
  346. package/dist/esm/whoCan/untrustingActions.js.map +1 -0
  347. package/dist/esm/whoCan/whoCan.d.ts +295 -0
  348. package/dist/esm/whoCan/whoCan.d.ts.map +1 -0
  349. package/dist/esm/whoCan/whoCan.js +571 -0
  350. package/dist/esm/whoCan/whoCan.js.map +1 -0
  351. package/dist/esm/whoCan/workerBootstrapPlugin.d.ts +17 -0
  352. package/dist/esm/whoCan/workerBootstrapPlugin.d.ts.map +1 -0
  353. package/dist/esm/whoCan/workerBootstrapPlugin.js +2 -0
  354. package/dist/esm/whoCan/workerBootstrapPlugin.js.map +1 -0
  355. package/dist/esm/workers/ArrayStreamingWorkQueue.d.ts +15 -0
  356. package/dist/esm/workers/ArrayStreamingWorkQueue.d.ts.map +1 -0
  357. package/dist/esm/workers/ArrayStreamingWorkQueue.js +31 -0
  358. package/dist/esm/workers/ArrayStreamingWorkQueue.js.map +1 -0
  359. package/dist/esm/workers/JobRunner.d.ts +47 -0
  360. package/dist/esm/workers/JobRunner.d.ts.map +1 -0
  361. package/dist/esm/workers/JobRunner.js +94 -0
  362. package/dist/esm/workers/JobRunner.js.map +1 -0
  363. package/dist/esm/workers/RingQueue.d.ts +14 -0
  364. package/dist/esm/workers/RingQueue.d.ts.map +1 -0
  365. package/dist/esm/workers/RingQueue.js +36 -0
  366. package/dist/esm/workers/RingQueue.js.map +1 -0
  367. package/dist/esm/workers/SharedArrayBufferMainCache.d.ts +10 -0
  368. package/dist/esm/workers/SharedArrayBufferMainCache.d.ts.map +1 -0
  369. package/dist/esm/workers/SharedArrayBufferMainCache.js +34 -0
  370. package/dist/esm/workers/SharedArrayBufferMainCache.js.map +1 -0
  371. package/dist/esm/workers/SharedArrayBufferWorkerCache.d.ts +10 -0
  372. package/dist/esm/workers/SharedArrayBufferWorkerCache.d.ts.map +1 -0
  373. package/dist/esm/workers/SharedArrayBufferWorkerCache.js +46 -0
  374. package/dist/esm/workers/SharedArrayBufferWorkerCache.js.map +1 -0
  375. package/dist/esm/workers/StreamingWorkQueue.d.ts +18 -0
  376. package/dist/esm/workers/StreamingWorkQueue.d.ts.map +1 -0
  377. package/dist/esm/workers/StreamingWorkQueue.js +61 -0
  378. package/dist/esm/workers/StreamingWorkQueue.js.map +1 -0
  379. package/dist/esm/workers/buffers.d.ts +4 -0
  380. package/dist/esm/workers/buffers.d.ts.map +1 -0
  381. package/dist/esm/workers/buffers.js +21 -0
  382. package/dist/esm/workers/buffers.js.map +1 -0
  383. package/package.json +132 -0
@@ -0,0 +1,1080 @@
1
+ import {} from '@actsecurity/iam-collect';
2
+ import {} from '@actsecurity/iam-policy';
3
+ import { numberOfCpus, StreamingJobQueue } from '@actsecurity/job';
4
+ import { Worker } from 'worker_threads';
5
+ import { getCollectClient } from '../collect/collect.js';
6
+ import { IamCollectClient } from '../collect/client.js';
7
+ import { getAccountIdForResource, getResourcePolicyForResource } from '../resources.js';
8
+ import { Arn } from '../utils/arn.js';
9
+ import {} from '../utils/s3Abac.js';
10
+ import { getWorkerScriptPath } from '../utils/workerScript.js';
11
+ import { SharedArrayBufferMainCache } from '../workers/SharedArrayBufferMainCache.js';
12
+ import { StreamingWorkQueue } from '../workers/StreamingWorkQueue.js';
13
+ import { createMainThreadStreamingWorkQueue } from './WhoCanMainThreadWorker.js';
14
+ import {} from './WhoCanWorker.js';
15
+ import { intersectWithPrincipalScope, resolvePrincipalScope } from './principalScope.js';
16
+ import {} from './requestAnalysis.js';
17
+ import { actionsForWhoCan, accountsToCheckBasedOnResourcePolicy, uniqueAccountsToCheck, sortWhoCanResults } from './whoCan.js';
18
+ import { isAssumedRoleArn, isIamRoleArn, isIamUserArn, isServicePrincipal } from '@actsecurity/iam-utils';
19
+ import { buildPrincipalArnFilter, principalMatchesFilter } from './principalArnFilter.js';
20
+ import { actionsThatDoNotAutomaticallyTrustTheCurrentAccount } from './untrustingActions.js';
21
+ import {} from './workerBootstrapPlugin.js';
22
+ import { log } from '@actsecurity/log';
23
+ // ──────────────────────────────────────────────────────────────────────────────
24
+ // Helpers
25
+ // ──────────────────────────────────────────────────────────────────────────────
26
+ let nextRequestId = 0;
27
+ /**
28
+ * Generates a unique request ID for a new request.
29
+ *
30
+ * @returns a unique string ID
31
+ */
32
+ function generateRequestId() {
33
+ return `req-${++nextRequestId}`;
34
+ }
35
+ /**
36
+ * Get the number of worker threads to use, defaulting to number of CPUs - 1.
37
+ *
38
+ * @param overrideValue the override value, if any
39
+ * @returns the override value if provided, otherwise number of CPUs - 1
40
+ */
41
+ function getNumberOfWorkers(overrideValue) {
42
+ if (typeof overrideValue === 'number' && overrideValue >= 0) {
43
+ return Math.floor(overrideValue);
44
+ }
45
+ return Math.max(0, numberOfCpus() - 1);
46
+ }
47
+ /**
48
+ * A queue-first bulk processor that accepts many whoCan requests, expands
49
+ * scenarios on the main thread, and feeds a shared simulation scheduler used
50
+ * by worker threads and an optional main-thread runner.
51
+ *
52
+ * Results are delivered through the {@link WhoCanProcessorConfig.onRequestSettled}
53
+ * callback as each request completes — they are not stored inside the processor.
54
+ *
55
+ * Use {@link enqueueWhoCan} to submit requests, then {@link waitForIdle} to
56
+ * wait for all work to complete. Call {@link shutdown} when done to terminate
57
+ * worker threads.
58
+ */
59
+ export class WhoCanProcessor {
60
+ constructor(workers, collectClient, config, preparationQueue) {
61
+ this.isShutdown = false;
62
+ this.workersDead = false;
63
+ // Admission state
64
+ this.pendingRequests = [];
65
+ this.activeRequestOrder = [];
66
+ this.requestStates = new Map();
67
+ this.admissionPumpRunning = false;
68
+ this.draining = false;
69
+ // Idle / drain tracking
70
+ this.idleWaiters = [];
71
+ this.workers = workers;
72
+ this.collectClient = collectClient;
73
+ this.config = config;
74
+ this.preparationQueue = preparationQueue;
75
+ }
76
+ /**
77
+ * Waits for every worker to post a `{ type: 'ready' }` message. If any
78
+ * worker fails (error, non-zero exit, or explicit `startupError` message)
79
+ * the remaining workers are terminated and the returned promise rejects.
80
+ *
81
+ * @param workers - The worker instances to wait on.
82
+ */
83
+ static async awaitWorkersReady(workers) {
84
+ // Each entry resolves on 'ready' or rejects on failure.
85
+ const perWorker = workers.map((worker) => new Promise((resolve, reject) => {
86
+ const onMessage = (msg) => {
87
+ if (msg.type === 'ready') {
88
+ cleanup();
89
+ resolve();
90
+ }
91
+ else if (msg.type === 'startupError') {
92
+ cleanup();
93
+ reject(new Error(`Worker startup failed: ${msg.error}`));
94
+ }
95
+ };
96
+ const onError = (err) => {
97
+ cleanup();
98
+ reject(new Error(`Worker error during startup: ${err.message}`));
99
+ };
100
+ const onExit = (code) => {
101
+ cleanup();
102
+ if (code !== 0) {
103
+ reject(new Error(`Worker exited with code ${code} during startup`));
104
+ }
105
+ };
106
+ const cleanup = () => {
107
+ worker.off('message', onMessage);
108
+ worker.off('error', onError);
109
+ worker.off('exit', onExit);
110
+ };
111
+ worker.on('message', onMessage);
112
+ worker.on('error', onError);
113
+ worker.on('exit', onExit);
114
+ }));
115
+ try {
116
+ await Promise.all(perWorker);
117
+ }
118
+ catch (err) {
119
+ // At least one worker failed — terminate all workers so none are
120
+ // left orphaned (no processor instance will be returned to the caller).
121
+ await Promise.allSettled(workers.map((w) => w.terminate()));
122
+ throw err;
123
+ }
124
+ }
125
+ /**
126
+ * Creates a new WhoCanProcessor with worker threads, a shared cache, and
127
+ * lifetime-scoped message routing. The processor is ready to accept requests
128
+ * immediately after creation.
129
+ *
130
+ * @param config - The configuration for the processor, including collect configs,
131
+ * partition, simulation options, tuning, and the onRequestSettled callback.
132
+ * @returns a new WhoCanProcessor instance
133
+ */
134
+ static async create(config) {
135
+ const numWorkers = getNumberOfWorkers(config.tuning?.workerThreads);
136
+ const perWorkerConcurrency = config.tuning?.perWorkerConcurrency ?? 50;
137
+ const mainThreadConcurrency = config.tuning?.mainThreadConcurrency ?? 50;
138
+ const workerPath = getWorkerScriptPath('whoCan/WhoCanWorkerThreadWorker.js');
139
+ if ((!workerPath || numWorkers === 0) && mainThreadConcurrency <= 0) {
140
+ throw new Error('WhoCanProcessor: no worker script found and mainThreadConcurrency is 0 — no work can be processed');
141
+ }
142
+ const workers = !workerPath
143
+ ? []
144
+ : new Array(numWorkers).fill(undefined).map(() => {
145
+ return new Worker(workerPath, {
146
+ workerData: {
147
+ collectConfigs: config.collectConfigs,
148
+ partition: config.partition,
149
+ concurrency: perWorkerConcurrency,
150
+ s3AbacOverride: config.s3AbacOverride,
151
+ collectGrantDetails: config.collectGrantDetails,
152
+ clientFactoryPlugin: config.clientFactoryPlugin,
153
+ workerBootstrapPlugin: config.workerBootstrapPlugin
154
+ }
155
+ });
156
+ });
157
+ // Install the shared-cache bridge before waiting for workers to become
158
+ // ready. Workers may issue getCache messages during their getCollectClient()
159
+ // call, which runs concurrently with the ready handshake. If the cache
160
+ // listeners are not installed yet those messages are dropped and the worker
161
+ // deadlocks waiting for a cache response.
162
+ const sharedCache = new SharedArrayBufferMainCache(workers);
163
+ // Wait for all workers to complete bootstrap and signal ready before
164
+ // proceeding. This ensures bootstrap failures are caught reliably and
165
+ // all workers are fully initialized before work is dispatched.
166
+ if (workers.length > 0) {
167
+ await WhoCanProcessor.awaitWorkersReady(workers);
168
+ }
169
+ const collectClient = await getCollectClient(config.collectConfigs, config.partition, {
170
+ cacheProvider: sharedCache,
171
+ clientFactoryPlugin: config.clientFactoryPlugin
172
+ });
173
+ const preparationConcurrency = config.tuning?.preparationConcurrency ?? Math.min(50, Math.max(1, numberOfCpus() * 2));
174
+ const preparationQueue = new StreamingJobQueue(preparationConcurrency, console, async () => { });
175
+ const processor = new WhoCanProcessor(workers, collectClient, config, preparationQueue);
176
+ processor.installLifetimeWorkerListeners();
177
+ // Signal workers to start pulling tasks. This must happen after
178
+ // installLifetimeWorkerListeners() so the main thread's requestTask
179
+ // handler is installed before the workers begin emitting requestTask
180
+ // messages.
181
+ for (const worker of workers) {
182
+ worker.postMessage({ type: 'start' });
183
+ }
184
+ processor.createMainThreadRunner();
185
+ return processor;
186
+ }
187
+ /**
188
+ * Enqueues a whoCan request for processing. Returns a unique request ID
189
+ * that will appear in the corresponding {@link WhoCanSettledEvent}.
190
+ *
191
+ * This method never activates a request directly — it appends to
192
+ * pendingRequests and signals the admission pump.
193
+ *
194
+ * @param request - The whoCan request parameters.
195
+ * @returns the unique request ID assigned to this request.
196
+ * @throws if the processor is shut down or draining via waitForIdle.
197
+ */
198
+ enqueueWhoCan(request) {
199
+ if (this.isShutdown) {
200
+ throw new Error('WhoCanProcessor has been shut down');
201
+ }
202
+ if (this.draining) {
203
+ throw new Error('Cannot enqueue while draining — waitForIdle() is in progress');
204
+ }
205
+ const requestId = generateRequestId();
206
+ this.pendingRequests.push({ requestId, request });
207
+ this.wakeAdmissionPump();
208
+ return requestId;
209
+ }
210
+ /**
211
+ * Returns a promise that resolves when all pending and active work has
212
+ * completed and all onRequestSettled callbacks have finished.
213
+ *
214
+ * While draining, new calls to {@link enqueueWhoCan} will throw. Once
215
+ * the drain completes, the processor re-opens for new enqueues.
216
+ *
217
+ * @returns a promise that resolves when idle, or rejects if a worker crashes.
218
+ */
219
+ async waitForIdle() {
220
+ if (this.isShutdown) {
221
+ throw new Error('WhoCanProcessor has been shut down');
222
+ }
223
+ // If already idle, return immediately
224
+ if (this.isIdle()) {
225
+ return;
226
+ }
227
+ this.draining = true;
228
+ try {
229
+ await new Promise((resolve, reject) => {
230
+ this.idleWaiters.push({ resolve, reject });
231
+ });
232
+ }
233
+ finally {
234
+ // Only clear draining when the last waiter has been notified
235
+ if (this.idleWaiters.length === 0) {
236
+ this.draining = false;
237
+ }
238
+ }
239
+ }
240
+ /**
241
+ * Shuts down the processor by rejecting all pending requests, waiting for
242
+ * active requests to settle, and terminating all worker threads.
243
+ *
244
+ * This method is idempotent — calling it multiple times is safe.
245
+ */
246
+ async shutdown() {
247
+ // If already shutting down or shut down, return the existing promise
248
+ if (this.shutdownPromise) {
249
+ return this.shutdownPromise;
250
+ }
251
+ this.shutdownPromise = this.executeShutdown();
252
+ return this.shutdownPromise;
253
+ }
254
+ /**
255
+ * Internal shutdown implementation. Rejects pending requests, waits for
256
+ * active requests to drain, then terminates workers.
257
+ */
258
+ async executeShutdown() {
259
+ this.isShutdown = true;
260
+ // Reject all pending requests that haven't been admitted
261
+ while (this.pendingRequests.length > 0) {
262
+ const submitted = this.pendingRequests.shift();
263
+ const event = {
264
+ status: 'rejected',
265
+ requestId: submitted.requestId,
266
+ request: submitted.request,
267
+ error: new Error('WhoCanProcessor was shut down before this request was processed')
268
+ };
269
+ try {
270
+ await this.config.onRequestSettled(event);
271
+ }
272
+ catch (err) {
273
+ await this.handleSettlementFailure(event, err);
274
+ }
275
+ }
276
+ // Wait for active requests to finish naturally (includes draining in-flight work)
277
+ if (this.activeRequestOrder.length > 0) {
278
+ await new Promise((resolve) => {
279
+ if (this.activeRequestOrder.length === 0) {
280
+ resolve();
281
+ }
282
+ else {
283
+ this.idleWaiters.push({ resolve, reject: () => resolve() });
284
+ }
285
+ });
286
+ }
287
+ if (this.workersDead) {
288
+ return;
289
+ }
290
+ // Drain main thread worker
291
+ if (this.mainThreadWorker) {
292
+ await this.mainThreadWorker.finishAllWork();
293
+ this.mainThreadWorker = undefined;
294
+ }
295
+ // Gracefully shut down workers
296
+ const workerPromises = this.workers.map((worker) => {
297
+ return new Promise((resolve) => {
298
+ worker.on('message', (msg) => {
299
+ if (msg.type === 'finished') {
300
+ worker.terminate().then(() => resolve());
301
+ }
302
+ });
303
+ worker.on('error', () => {
304
+ worker
305
+ .terminate()
306
+ .then(() => resolve())
307
+ .catch(() => resolve());
308
+ });
309
+ worker.postMessage({ type: 'finishWork' });
310
+ });
311
+ });
312
+ await Promise.all(workerPromises);
313
+ this.workersDead = true;
314
+ }
315
+ // ──────────────────────────────────────────────────────────────────────────
316
+ // Lifetime worker listeners
317
+ // ──────────────────────────────────────────────────────────────────────────
318
+ /**
319
+ * Installs lifetime-scoped message, error, and exit listeners on all workers.
320
+ * Message listeners route simulation results and deny-detail checks to the
321
+ * correct request state using requestId. Error/exit listeners detect crashes
322
+ * and mark the processor as fatally failed.
323
+ */
324
+ installLifetimeWorkerListeners() {
325
+ for (const worker of this.workers) {
326
+ worker.on('message', (msg) => {
327
+ this.handleWorkerMessage(msg, worker);
328
+ });
329
+ worker.on('error', (err) => {
330
+ if (!this.isShutdown) {
331
+ this.handleWorkerFailure(new Error(`Worker error: ${err.message}`));
332
+ }
333
+ });
334
+ worker.on('exit', (code) => {
335
+ if (!this.isShutdown && code !== 0) {
336
+ this.handleWorkerFailure(new Error(`Worker exited unexpectedly with code ${code}`));
337
+ }
338
+ });
339
+ }
340
+ }
341
+ /**
342
+ * Routes a message from a worker thread to the appropriate handler based
343
+ * on message type and requestId.
344
+ *
345
+ * @param msg - The message received from the worker.
346
+ * @param worker - The worker that sent the message.
347
+ */
348
+ handleWorkerMessage(msg, worker) {
349
+ if (msg.type === 'requestTask') {
350
+ const task = this.dequeueNextScenario();
351
+ worker.postMessage({ type: 'task', workerId: msg.workerId, task });
352
+ }
353
+ else if (msg.type === 'result') {
354
+ this.handleSimulationResult(msg.requestId, msg.result, !!msg.denyDetailsCheckWillFollow);
355
+ }
356
+ else if (msg.type === 'checkDenyDetails') {
357
+ this.handleCheckDenyDetails(msg.requestId, msg.checkId, msg.lightAnalysis, worker);
358
+ }
359
+ else if (msg.type === 'denyDetailsResult') {
360
+ this.handleDenyDetailsResult(msg.requestId, msg.denyDetail);
361
+ }
362
+ }
363
+ /**
364
+ * Creates the main-thread simulation runner if mainThreadConcurrency > 0.
365
+ * The runner pulls from the FIFO scheduler and routes results by requestId.
366
+ */
367
+ createMainThreadRunner() {
368
+ const mainThreadConcurrency = this.config.tuning?.mainThreadConcurrency ?? 50;
369
+ if (mainThreadConcurrency <= 0) {
370
+ return;
371
+ }
372
+ const { collectGrantDetails, s3AbacOverride } = this.config;
373
+ this.mainThreadWorker = createMainThreadStreamingWorkQueue(() => this.dequeueNextScenario(), (requestId, result) => this.handleSimulationResult(requestId, result), (requestId, lightAnalysis) => {
374
+ const state = this.requestStates.get(requestId);
375
+ if (state && !state.settled) {
376
+ return state.denyDetailsCallback?.(lightAnalysis) ?? false;
377
+ }
378
+ return false;
379
+ }, (requestId, detail) => this.handleDenyDetailsResult(requestId, detail), this.collectClient, s3AbacOverride, collectGrantDetails ?? false, mainThreadConcurrency);
380
+ }
381
+ // ──────────────────────────────────────────────────────────────────────────
382
+ // FIFO queue-of-queues scheduler
383
+ // ──────────────────────────────────────────────────────────────────────────
384
+ /**
385
+ * Dequeues the next simulation scenario using FIFO request priority.
386
+ * Prefers the oldest active request that has ready scenarios. If the oldest
387
+ * is temporarily empty (still preparing), falls back to the next request
388
+ * with ready scenarios so cores do not idle.
389
+ *
390
+ * @returns the next work item, or undefined if no scenarios are ready.
391
+ */
392
+ dequeueNextScenario() {
393
+ for (const requestId of this.activeRequestOrder) {
394
+ const state = this.requestStates.get(requestId);
395
+ if (!state || state.settled)
396
+ continue;
397
+ const item = state.scenarios.dequeue();
398
+ if (item) {
399
+ return { ...item, requestId };
400
+ }
401
+ }
402
+ return undefined;
403
+ }
404
+ /**
405
+ * Notifies all simulation consumers (workers and main thread) that new
406
+ * work may be available in the scheduler.
407
+ */
408
+ notifySimulationConsumers() {
409
+ this.mainThreadWorker?.notifyWorkAvailable();
410
+ for (const worker of this.workers) {
411
+ worker.postMessage({ type: 'workAvailable' });
412
+ }
413
+ }
414
+ // ──────────────────────────────────────────────────────────────────────────
415
+ // Admission pump
416
+ // ──────────────────────────────────────────────────────────────────────────
417
+ /**
418
+ * Wakes the admission pump to process pending requests. If the pump is
419
+ * already running, this is a no-op — the running pump will pick up new
420
+ * pending requests on its next iteration.
421
+ */
422
+ wakeAdmissionPump() {
423
+ if (this.admissionPumpRunning)
424
+ return;
425
+ this.admissionPumpRunning = true;
426
+ // Run asynchronously so enqueueWhoCan returns immediately
427
+ void this.runAdmissionPump();
428
+ }
429
+ /**
430
+ * The admission pump loop. Drains pendingRequests into active processing
431
+ * up to maxRequestsInProgress. Only one instance of this loop runs at a time,
432
+ * guarded by admissionPumpRunning.
433
+ */
434
+ async runAdmissionPump() {
435
+ const maxActive = this.config.tuning?.maxRequestsInProgress ?? 30;
436
+ try {
437
+ while (this.pendingRequests.length > 0 && this.activeRequestOrder.length < maxActive) {
438
+ if (this.isShutdown)
439
+ break;
440
+ const submitted = this.pendingRequests.shift();
441
+ const state = this.createRequestState(submitted);
442
+ this.requestStates.set(submitted.requestId, state);
443
+ this.activeRequestOrder.push(submitted.requestId);
444
+ // Enqueue the root preparation job for this request
445
+ this.enqueueRootPreparation(state);
446
+ }
447
+ }
448
+ finally {
449
+ this.admissionPumpRunning = false;
450
+ }
451
+ // After admitting, check if we became idle
452
+ this.checkIdle();
453
+ }
454
+ /**
455
+ * Creates a fresh RequestState for an admitted request.
456
+ *
457
+ * @param submitted - The submitted request to create state for.
458
+ * @returns the new RequestState.
459
+ */
460
+ createRequestState(submitted) {
461
+ return {
462
+ requestId: submitted.requestId,
463
+ request: submitted.request,
464
+ allScenariosCreated: false,
465
+ scenarios: new StreamingWorkQueue(),
466
+ created: 0,
467
+ completed: 0,
468
+ pendingPreparationJobs: 0,
469
+ allowed: [],
470
+ principalsNotFound: [],
471
+ accountsNotFound: [],
472
+ organizationsNotFound: [],
473
+ organizationalUnitsNotFound: [],
474
+ allAccountsChecked: false,
475
+ denyDetails: [],
476
+ simulationCount: 0,
477
+ denyDetailsCallback: submitted.request.denyDetailsCallback,
478
+ pendingDenyDetailsChecks: 0,
479
+ settled: false,
480
+ callbackInvoked: false,
481
+ simulationErrors: []
482
+ };
483
+ }
484
+ // ──────────────────────────────────────────────────────────────────────────
485
+ // Preparation
486
+ // ──────────────────────────────────────────────────────────────────────────
487
+ /**
488
+ * Enqueues the root preparation job for a request. This job performs resource
489
+ * account resolution, resource policy lookup, action expansion, principal scope
490
+ * handling, and then enqueues follow-up preparation jobs to enumerate principals.
491
+ *
492
+ * @param state - The request state to prepare.
493
+ */
494
+ enqueueRootPreparation(state) {
495
+ state.pendingPreparationJobs++;
496
+ this.preparationQueue.enqueue({
497
+ properties: {},
498
+ execute: async () => {
499
+ try {
500
+ await this.executeRootPreparation(state);
501
+ }
502
+ catch (err) {
503
+ this.settleRequestAsError(state, err instanceof Error ? err : new Error(String(err)));
504
+ }
505
+ finally {
506
+ state.pendingPreparationJobs--;
507
+ this.checkRequestCompletion(state);
508
+ }
509
+ }
510
+ });
511
+ }
512
+ /**
513
+ * Executes the root preparation for a request: resolves the resource account,
514
+ * fetches the resource policy, expands actions, determines which accounts and
515
+ * principals to check, and enqueues follow-up preparation jobs.
516
+ *
517
+ * @param state - The request state to prepare.
518
+ */
519
+ async executeRootPreparation(state) {
520
+ if (state.settled)
521
+ return;
522
+ const { request } = state;
523
+ const { resource } = request;
524
+ const collectClient = this.collectClient;
525
+ if (!request.resourceAccount && !request.resource) {
526
+ throw new Error('Either resourceAccount or resource must be provided in the request.');
527
+ }
528
+ const resourceAccount = request.resourceAccount || (await getAccountIdForResource(collectClient, resource));
529
+ if (!resourceAccount) {
530
+ throw new Error(`Could not determine account ID for resource ${resource}. Please use a different ARN or specify resourceAccount.`);
531
+ }
532
+ const actions = await actionsForWhoCan({
533
+ actions: request.actions,
534
+ resource: request.resource
535
+ });
536
+ if (!actions || actions.length === 0) {
537
+ throw new Error('No valid actions provided or found for the resource.');
538
+ }
539
+ const untrustingActions = await actionsThatDoNotAutomaticallyTrustTheCurrentAccount();
540
+ let resourcePolicy = undefined;
541
+ if (resource) {
542
+ resourcePolicy = await getResourcePolicyForResource(collectClient, resource, resourceAccount);
543
+ const resourceArn = new Arn(resource);
544
+ if ((resourceArn.matches({ service: 'iam', resourceType: 'role' }) ||
545
+ resourceArn.matches({ service: 'kms', resourceType: 'key' })) &&
546
+ !resourcePolicy) {
547
+ throw new Error(`Unable to find resource policy for ${resource}. Cannot determine who can access the resource.`);
548
+ }
549
+ if (resourcePolicy && resourcePolicy.errors.length > 0) {
550
+ log.error({
551
+ iamLensResourcePolicyValidationErrors: true,
552
+ errors: resourcePolicy.errors,
553
+ resource: resource
554
+ });
555
+ throw new Error(`Resource policy for ${resource} has validation errors and cannot be used for simulation.`);
556
+ }
557
+ }
558
+ const accountsToCheck = await accountsToCheckBasedOnResourcePolicy(resourcePolicy, resourceAccount, collectClient);
559
+ const principalArnFilter = buildPrincipalArnFilter(resourcePolicy);
560
+ const uniqueAccounts = await uniqueAccountsToCheck(collectClient, accountsToCheck);
561
+ // Store not-found arrays on the request state
562
+ state.accountsNotFound = uniqueAccounts.accountsNotFound;
563
+ state.organizationsNotFound = uniqueAccounts.organizationsNotFound;
564
+ state.organizationalUnitsNotFound = uniqueAccounts.organizationalUnitsNotFound;
565
+ state.allAccountsChecked = request.principalScope ? false : accountsToCheck.allAccounts;
566
+ // The resource account is always a candidate for search — for non-untrusting
567
+ // actions same-account principals can access via identity policy alone. Include
568
+ // it in the base accounts list so the principalScope intersection can see it.
569
+ const baseAccounts = uniqueAccounts.accounts.includes(resourceAccount)
570
+ ? uniqueAccounts.accounts
571
+ : [...uniqueAccounts.accounts, resourceAccount];
572
+ let accountsForSearch = baseAccounts;
573
+ let principalsForSearch = accountsToCheck.specificPrincipals;
574
+ let scopeIncludesResourceAccount = true;
575
+ if (request.principalScope) {
576
+ const resolved = await resolvePrincipalScope(collectClient, request.principalScope);
577
+ const intersection = intersectWithPrincipalScope(baseAccounts, accountsToCheck.specificPrincipals, accountsToCheck.allAccounts, resolved.accounts, resolved.principals);
578
+ accountsForSearch = intersection.accounts;
579
+ principalsForSearch = intersection.principals;
580
+ scopeIncludesResourceAccount = resolved.accounts.has(resourceAccount);
581
+ }
582
+ // Principals explicitly named in the resource policy are enqueued via the
583
+ // specific-principals path (which skips the PrincipalArn filter). Track them
584
+ // so the account-enumeration paths can skip duplicates without needing to
585
+ // store all enumerated principals in memory.
586
+ const specificPrincipalSet = new Set(principalsForSearch);
587
+ // Enqueue follow-up preparation jobs for account/principal enumeration
588
+ const principalIndexExists = !this.config.ignorePrincipalIndex && (await collectClient.principalIndexExists());
589
+ if (principalIndexExists) {
590
+ // Use the principal index to find relevant principals directly
591
+ state.pendingPreparationJobs++;
592
+ this.preparationQueue.enqueue({
593
+ properties: {},
594
+ execute: async () => {
595
+ try {
596
+ if (state.settled)
597
+ return;
598
+ // Pre-compute an accounts list without the resource account for
599
+ // untrusting actions where the policy does not trust it.
600
+ const accountsWithoutResourceAccount = scopeIncludesResourceAccount && !accountsToCheck.resourceAccountTrustedByPolicy
601
+ ? accountsForSearch.filter((a) => a !== resourceAccount)
602
+ : accountsForSearch;
603
+ for (const action of actions) {
604
+ const isUntrusting = untrustingActions.has(action.toLowerCase());
605
+ const allFromAccount = scopeIncludesResourceAccount && accountsToCheck.checkAllFromResourceAccount
606
+ ? resourceAccount
607
+ : undefined;
608
+ const actionAccountsForSearch = isUntrusting
609
+ ? accountsWithoutResourceAccount
610
+ : accountsForSearch;
611
+ const indexedPrincipals = await collectClient.getPrincipalsWithActionAllowed(allFromAccount, actionAccountsForSearch, action);
612
+ for (const principal of indexedPrincipals || []) {
613
+ if (specificPrincipalSet.has(principal))
614
+ continue;
615
+ if (principalArnFilter &&
616
+ !isServicePrincipal(principal) &&
617
+ !principalMatchesFilter(principal, action, resourceAccount, principalArnFilter)) {
618
+ continue;
619
+ }
620
+ state.scenarios.enqueue({
621
+ resource,
622
+ action,
623
+ principal,
624
+ resourceAccount,
625
+ strictContextKeys: state.request.strictContextKeys,
626
+ collectDenyDetails: !!state.denyDetailsCallback
627
+ });
628
+ state.created++;
629
+ }
630
+ }
631
+ this.notifySimulationConsumers();
632
+ }
633
+ catch (err) {
634
+ this.settleRequestAsError(state, err instanceof Error ? err : new Error(String(err)));
635
+ }
636
+ finally {
637
+ state.pendingPreparationJobs--;
638
+ this.checkRequestCompletion(state);
639
+ }
640
+ }
641
+ });
642
+ }
643
+ else {
644
+ // No principal index — enumerate all principals per account
645
+ for (const account of accountsForSearch) {
646
+ state.pendingPreparationJobs++;
647
+ this.preparationQueue.enqueue({
648
+ properties: {},
649
+ execute: async () => {
650
+ try {
651
+ if (state.settled)
652
+ return;
653
+ const principals = await collectClient.getAllPrincipalsInAccount(account);
654
+ for (const principal of principals) {
655
+ if (specificPrincipalSet.has(principal))
656
+ continue;
657
+ const skipFilter = !principalArnFilter || isServicePrincipal(principal);
658
+ for (const action of actions) {
659
+ if (!skipFilter &&
660
+ !principalMatchesFilter(principal, action, resourceAccount, principalArnFilter)) {
661
+ continue;
662
+ }
663
+ state.scenarios.enqueue({
664
+ resource,
665
+ action,
666
+ principal,
667
+ resourceAccount,
668
+ strictContextKeys: state.request.strictContextKeys,
669
+ collectDenyDetails: !!state.denyDetailsCallback
670
+ });
671
+ state.created++;
672
+ }
673
+ }
674
+ this.notifySimulationConsumers();
675
+ }
676
+ catch (err) {
677
+ this.settleRequestAsError(state, err instanceof Error ? err : new Error(String(err)));
678
+ }
679
+ finally {
680
+ state.pendingPreparationJobs--;
681
+ this.checkRequestCompletion(state);
682
+ }
683
+ }
684
+ });
685
+ }
686
+ }
687
+ // Enqueue specific principals from resource policy (iterate the Set to
688
+ // deduplicate — the same principal can appear in the list more than once
689
+ // when multiple statements reference it, e.g. an explicit Principal element
690
+ // and a StringEquals aws:PrincipalArn condition).
691
+ for (const principal of specificPrincipalSet) {
692
+ state.pendingPreparationJobs++;
693
+ this.preparationQueue.enqueue({
694
+ properties: {},
695
+ execute: async () => {
696
+ try {
697
+ if (state.settled)
698
+ return;
699
+ if (isServicePrincipal(principal)) {
700
+ for (const action of actions) {
701
+ state.scenarios.enqueue({
702
+ resource,
703
+ action,
704
+ principal,
705
+ resourceAccount,
706
+ strictContextKeys: state.request.strictContextKeys,
707
+ collectDenyDetails: !!state.denyDetailsCallback
708
+ });
709
+ state.created++;
710
+ }
711
+ }
712
+ else if (isIamUserArn(principal) ||
713
+ isIamRoleArn(principal) ||
714
+ isAssumedRoleArn(principal)) {
715
+ const resolvedPrincipal = await collectClient.resolvePrincipalArn(principal);
716
+ if (!resolvedPrincipal) {
717
+ state.principalsNotFound.push(principal);
718
+ }
719
+ else {
720
+ for (const action of actions) {
721
+ state.scenarios.enqueue({
722
+ resource,
723
+ action,
724
+ principal,
725
+ resultPrincipal: resolvedPrincipal,
726
+ resourceAccount,
727
+ strictContextKeys: state.request.strictContextKeys,
728
+ collectDenyDetails: !!state.denyDetailsCallback
729
+ });
730
+ state.created++;
731
+ }
732
+ }
733
+ }
734
+ else {
735
+ state.principalsNotFound.push(principal);
736
+ }
737
+ this.notifySimulationConsumers();
738
+ }
739
+ catch (err) {
740
+ this.settleRequestAsError(state, err instanceof Error ? err : new Error(String(err)));
741
+ }
742
+ finally {
743
+ state.pendingPreparationJobs--;
744
+ this.checkRequestCompletion(state);
745
+ }
746
+ }
747
+ });
748
+ }
749
+ // All follow-up prep jobs have been enqueued. Mark scenarios as fully specified
750
+ // once the root prep and all follow-ups complete (tracked by pendingPreparationJobs).
751
+ state.allScenariosCreated = true;
752
+ // Notify consumers that scenarios may be available
753
+ this.notifySimulationConsumers();
754
+ }
755
+ // ──────────────────────────────────────────────────────────────────────────
756
+ // Simulation result handling
757
+ // ──────────────────────────────────────────────────────────────────────────
758
+ /**
759
+ * Handles a simulation result from a worker or the main thread runner.
760
+ * Routes the result to the correct request state and checks for completion.
761
+ *
762
+ * @param requestId - The ID of the request this result belongs to.
763
+ * @param result - The simulation job result.
764
+ */
765
+ handleSimulationResult(requestId, result, denyDetailsCheckWillFollow = false) {
766
+ const state = this.requestStates.get(requestId);
767
+ if (!state)
768
+ return;
769
+ state.completed++;
770
+ if (denyDetailsCheckWillFollow) {
771
+ state.pendingDenyDetailsChecks++;
772
+ }
773
+ if (state.settled) {
774
+ // Request already settled (e.g., failed). Still count the result so
775
+ // the drain check can fire, but discard the actual data.
776
+ this.checkRequestCompletion(state);
777
+ return;
778
+ }
779
+ state.simulationCount++;
780
+ if (result.status === 'fulfilled' && result.value) {
781
+ state.allowed.push(result.value);
782
+ }
783
+ else if (result.status === 'rejected') {
784
+ log.error('Error running simulation', { error: result.reason });
785
+ state.simulationErrors.push(result);
786
+ }
787
+ this.checkRequestCompletion(state);
788
+ }
789
+ /**
790
+ * Handles a checkDenyDetails request from a worker thread. Looks up the
791
+ * request's denyDetailsCallback and responds.
792
+ *
793
+ * @param requestId - The ID of the request.
794
+ * @param checkId - The unique check ID for this deny-details round trip.
795
+ * @param lightAnalysis - The light analysis to pass to the callback.
796
+ * @param worker - The worker to respond to.
797
+ */
798
+ handleCheckDenyDetails(requestId, checkId, lightAnalysis, worker) {
799
+ const state = this.requestStates.get(requestId);
800
+ const shouldInclude = state && !state.settled ? (state.denyDetailsCallback?.(lightAnalysis) ?? false) : false;
801
+ if (!shouldInclude && state) {
802
+ // No denyDetailsResult message will follow — decrement the counter
803
+ state.pendingDenyDetailsChecks--;
804
+ this.checkRequestCompletion(state);
805
+ }
806
+ worker.postMessage({
807
+ type: 'denyDetailsCheckResult',
808
+ checkId,
809
+ shouldInclude
810
+ });
811
+ }
812
+ /**
813
+ * Handles a deny details result from a worker thread. Decrements the
814
+ * pending deny-details counter and checks for request completion.
815
+ *
816
+ * @param requestId - The ID of the request.
817
+ * @param denyDetail - The deny detail to store.
818
+ */
819
+ handleDenyDetailsResult(requestId, denyDetail) {
820
+ const state = this.requestStates.get(requestId);
821
+ if (!state)
822
+ return;
823
+ if (state.pendingDenyDetailsChecks > 0) {
824
+ state.pendingDenyDetailsChecks--;
825
+ }
826
+ if (!state.settled) {
827
+ state.denyDetails.push(denyDetail);
828
+ }
829
+ this.checkRequestCompletion(state);
830
+ }
831
+ // ──────────────────────────────────────────────────────────────────────────
832
+ // Request completion and settlement
833
+ // ──────────────────────────────────────────────────────────────────────────
834
+ /**
835
+ * Checks whether a request has completed all preparation and simulation work.
836
+ * If so, settles the request as successful.
837
+ *
838
+ * @param state - The request state to check.
839
+ */
840
+ checkRequestCompletion(state) {
841
+ if (state.settled) {
842
+ this.checkRequestDrain(state);
843
+ return;
844
+ }
845
+ if (!state.allScenariosCreated)
846
+ return;
847
+ if (state.pendingPreparationJobs > 0)
848
+ return;
849
+ if (state.created !== state.completed)
850
+ return;
851
+ if (state.pendingDenyDetailsChecks > 0)
852
+ return;
853
+ // All work done — settle as success
854
+ if (state.simulationErrors.length > 0) {
855
+ this.settleRequestAsError(state, new Error(`Completed with ${state.simulationErrors.length} simulation errors. See previous logs.`));
856
+ }
857
+ else {
858
+ this.settleRequestAsSuccess(state);
859
+ }
860
+ }
861
+ /**
862
+ * Settles a request as successful: builds the WhoCanResponse, awaits
863
+ * onRequestSettled, removes the request from active state, and wakes
864
+ * the admission pump.
865
+ *
866
+ * @param state - The request state to settle.
867
+ */
868
+ settleRequestAsSuccess(state) {
869
+ if (state.settled)
870
+ return;
871
+ state.settled = true;
872
+ const result = {
873
+ simulationCount: state.simulationCount,
874
+ allowed: state.allowed,
875
+ allAccountsChecked: state.allAccountsChecked,
876
+ accountsNotFound: state.accountsNotFound,
877
+ organizationsNotFound: state.organizationsNotFound,
878
+ organizationalUnitsNotFound: state.organizationalUnitsNotFound,
879
+ principalsNotFound: state.principalsNotFound,
880
+ denyDetails: state.denyDetailsCallback ? state.denyDetails : undefined
881
+ };
882
+ if (state.request.sort) {
883
+ sortWhoCanResults(result);
884
+ }
885
+ void this.invokeSettledCallbackAndCleanup(state, {
886
+ status: 'fulfilled',
887
+ requestId: state.requestId,
888
+ request: state.request,
889
+ result
890
+ });
891
+ }
892
+ /**
893
+ * Settles a request as failed: invokes onRequestSettled with the error
894
+ * immediately, but keeps the request in active state until all in-flight
895
+ * work drains (created === completed). Late results for settled requests
896
+ * are discarded but still counted so the drain completes.
897
+ *
898
+ * @param state - The request state to settle.
899
+ * @param error - The error that caused the failure.
900
+ */
901
+ settleRequestAsError(state, error) {
902
+ if (state.settled)
903
+ return;
904
+ state.settled = true;
905
+ // Await the callback (backpressure), then mark it done so checkRequestDrain
906
+ // can free the slot once all in-flight work also completes.
907
+ void (async () => {
908
+ await this.invokeSettledCallback({
909
+ status: 'rejected',
910
+ requestId: state.requestId,
911
+ request: state.request,
912
+ error
913
+ });
914
+ state.callbackInvoked = true;
915
+ this.checkRequestDrain(state);
916
+ })();
917
+ }
918
+ /**
919
+ * Invokes the onRequestSettled callback and routes any errors through
920
+ * {@link handleSettlementFailure}.
921
+ *
922
+ * @param event - The settlement event to deliver.
923
+ */
924
+ async invokeSettledCallback(event) {
925
+ try {
926
+ await this.config.onRequestSettled(event);
927
+ }
928
+ catch (err) {
929
+ await this.handleSettlementFailure(event, err);
930
+ }
931
+ }
932
+ /**
933
+ * Awaits the onRequestSettled callback, then removes the request from
934
+ * active state and wakes the admission pump. Used for successful settlements
935
+ * where all work is already complete.
936
+ *
937
+ * @param state - The request state being settled.
938
+ * @param event - The settlement event to deliver.
939
+ */
940
+ async invokeSettledCallbackAndCleanup(state, event) {
941
+ await this.invokeSettledCallback(event);
942
+ this.removeFromActiveState(state);
943
+ }
944
+ /**
945
+ * Checks whether a settled request has fully drained: the onRequestSettled
946
+ * callback has been awaited, all preparation jobs have finished, all
947
+ * simulation results have been received, and all deny-detail round trips
948
+ * have completed. Only then is the request removed from active state.
949
+ *
950
+ * @param state - The request state to check.
951
+ */
952
+ checkRequestDrain(state) {
953
+ if (!state.settled)
954
+ return;
955
+ if (!state.callbackInvoked)
956
+ return;
957
+ if (state.pendingPreparationJobs > 0)
958
+ return;
959
+ if (state.created !== state.completed)
960
+ return;
961
+ if (state.pendingDenyDetailsChecks > 0)
962
+ return;
963
+ this.removeFromActiveState(state);
964
+ }
965
+ /**
966
+ * Removes a request from active state, wakes the admission pump to fill
967
+ * the freed slot, and checks if the processor is now idle.
968
+ *
969
+ * @param state - The request state to remove.
970
+ */
971
+ removeFromActiveState(state) {
972
+ const idx = this.activeRequestOrder.indexOf(state.requestId);
973
+ if (idx !== -1) {
974
+ this.activeRequestOrder.splice(idx, 1);
975
+ }
976
+ this.requestStates.delete(state.requestId);
977
+ this.wakeAdmissionPump();
978
+ this.checkIdle();
979
+ }
980
+ // ──────────────────────────────────────────────────────────────────────────
981
+ // Idle checking
982
+ // ──────────────────────────────────────────────────────────────────────────
983
+ /**
984
+ * Returns true if the processor has no pending, active, or in-flight work.
985
+ *
986
+ * @returns true if fully idle.
987
+ */
988
+ isIdle() {
989
+ return this.pendingRequests.length === 0 && this.activeRequestOrder.length === 0;
990
+ }
991
+ /**
992
+ * Checks whether the processor has become idle and resolves or rejects the
993
+ * waitForIdle promise if so.
994
+ */
995
+ checkIdle() {
996
+ if (!this.isIdle())
997
+ return;
998
+ if (this.idleWaiters.length === 0)
999
+ return;
1000
+ const waiters = this.idleWaiters.splice(0);
1001
+ if (this.fatalError) {
1002
+ for (const waiter of waiters) {
1003
+ waiter.reject(this.fatalError);
1004
+ }
1005
+ }
1006
+ else {
1007
+ for (const waiter of waiters) {
1008
+ waiter.resolve();
1009
+ }
1010
+ }
1011
+ }
1012
+ /**
1013
+ * Handles an error thrown by the `onRequestSettled` callback. If the
1014
+ * `onSettlementFailure` callback is defined, it is invoked with the event
1015
+ * and error; any error it throws is silently ignored. If not defined, a
1016
+ * warning is logged.
1017
+ *
1018
+ * @param event - The settlement event that was being delivered.
1019
+ * @param err - The raw error thrown by the `onRequestSettled` callback.
1020
+ */
1021
+ async handleSettlementFailure(event, err) {
1022
+ const error = err instanceof Error ? err : new Error(String(err));
1023
+ if (this.config.onSettlementFailure) {
1024
+ try {
1025
+ await this.config.onSettlementFailure(event, error);
1026
+ }
1027
+ catch {
1028
+ // onSettlementFailure itself failed — silently ignored
1029
+ }
1030
+ }
1031
+ else {
1032
+ log.warn('onRequestSettled callback failed and no onSettlementFailure handler is defined', {
1033
+ requestId: event.requestId,
1034
+ error
1035
+ });
1036
+ }
1037
+ }
1038
+ /**
1039
+ * Handles an unexpected worker failure by marking the processor as dead,
1040
+ * terminating remaining workers, and rejecting all active and pending requests.
1041
+ *
1042
+ * @param error - The error that caused the worker failure.
1043
+ */
1044
+ handleWorkerFailure(error) {
1045
+ this.workersDead = true;
1046
+ this.isShutdown = true;
1047
+ this.fatalError = error;
1048
+ // Terminate remaining workers (fire-and-forget)
1049
+ for (const worker of this.workers) {
1050
+ worker.terminate().catch(() => { });
1051
+ }
1052
+ // Settle all active requests as failed
1053
+ for (const requestId of [...this.activeRequestOrder]) {
1054
+ const state = this.requestStates.get(requestId);
1055
+ if (state && !state.settled) {
1056
+ this.settleRequestAsError(state, error);
1057
+ }
1058
+ }
1059
+ // Reject all pending requests
1060
+ while (this.pendingRequests.length > 0) {
1061
+ const submitted = this.pendingRequests.shift();
1062
+ const event = {
1063
+ status: 'rejected',
1064
+ requestId: submitted.requestId,
1065
+ request: submitted.request,
1066
+ error
1067
+ };
1068
+ void this.config
1069
+ .onRequestSettled(event)
1070
+ .catch((err) => this.handleSettlementFailure(event, err))
1071
+ .catch(() => { });
1072
+ }
1073
+ // Reject all idle waiters
1074
+ const waiters = this.idleWaiters.splice(0);
1075
+ for (const waiter of waiters) {
1076
+ waiter.reject(error);
1077
+ }
1078
+ }
1079
+ }
1080
+ //# sourceMappingURL=WhoCanProcessor.js.map