@uapkg/cli 1.3.0 → 1.3.1

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 (412) hide show
  1. package/dist/app/CompositionRoot.d.ts +36 -33
  2. package/dist/app/CompositionRoot.d.ts.map +1 -1
  3. package/dist/app/CompositionRoot.js +91 -109
  4. package/dist/app/CompositionRoot.js.map +1 -1
  5. package/dist/app/UAPKGApplication.d.ts +6 -3
  6. package/dist/app/UAPKGApplication.d.ts.map +1 -1
  7. package/dist/app/UAPKGApplication.js +155 -169
  8. package/dist/app/UAPKGApplication.js.map +1 -1
  9. package/dist/build/BuildMetadata.d.ts +9 -6
  10. package/dist/build/BuildMetadata.d.ts.map +1 -1
  11. package/dist/build/BuildMetadata.js +2 -2
  12. package/dist/cli/UAPKGCommandLine.d.ts +259 -257
  13. package/dist/cli/UAPKGCommandLine.d.ts.map +1 -1
  14. package/dist/cli/UAPKGCommandLine.js +248 -239
  15. package/dist/cli/UAPKGCommandLine.js.map +1 -1
  16. package/dist/cli/parseCommandLine.d.ts +5 -1
  17. package/dist/cli/parseCommandLine.d.ts.map +1 -1
  18. package/dist/cli/parseCommandLine.js +8 -3
  19. package/dist/cli/parseCommandLine.js.map +1 -1
  20. package/dist/cli/parsing/UAPKGCommandLineParser.d.ts +9 -6
  21. package/dist/cli/parsing/UAPKGCommandLineParser.d.ts.map +1 -1
  22. package/dist/cli/parsing/UAPKGCommandLineParser.js +23 -31
  23. package/dist/cli/parsing/UAPKGCommandLineParser.js.map +1 -1
  24. package/dist/cli/parsing/UAPKGParserRegistry.d.ts +12 -9
  25. package/dist/cli/parsing/UAPKGParserRegistry.d.ts.map +1 -1
  26. package/dist/cli/parsing/UAPKGParserRegistry.js +53 -50
  27. package/dist/cli/parsing/UAPKGParserRegistry.js.map +1 -1
  28. package/dist/cli/parsing/contracts/UAPKGCommandModule.d.ts +9 -6
  29. package/dist/cli/parsing/contracts/UAPKGCommandModule.d.ts.map +1 -1
  30. package/dist/cli/parsing/contracts/UAPKGCommandModule.js +1 -2
  31. package/dist/cli/parsing/modules/AddCommandModule.d.ts +8 -5
  32. package/dist/cli/parsing/modules/AddCommandModule.d.ts.map +1 -1
  33. package/dist/cli/parsing/modules/AddCommandModule.js +49 -36
  34. package/dist/cli/parsing/modules/AddCommandModule.js.map +1 -1
  35. package/dist/cli/parsing/modules/ConfigCommandModule.d.ts +8 -5
  36. package/dist/cli/parsing/modules/ConfigCommandModule.d.ts.map +1 -1
  37. package/dist/cli/parsing/modules/ConfigCommandModule.js +87 -83
  38. package/dist/cli/parsing/modules/ConfigCommandModule.js.map +1 -1
  39. package/dist/cli/parsing/modules/InitCommandModule.d.ts +8 -5
  40. package/dist/cli/parsing/modules/InitCommandModule.d.ts.map +1 -1
  41. package/dist/cli/parsing/modules/InitCommandModule.js +25 -22
  42. package/dist/cli/parsing/modules/InitCommandModule.js.map +1 -1
  43. package/dist/cli/parsing/modules/InstallCommandModule.d.ts +8 -5
  44. package/dist/cli/parsing/modules/InstallCommandModule.d.ts.map +1 -1
  45. package/dist/cli/parsing/modules/InstallCommandModule.js +36 -28
  46. package/dist/cli/parsing/modules/InstallCommandModule.js.map +1 -1
  47. package/dist/cli/parsing/modules/LifecycleCommandModule.d.ts +8 -5
  48. package/dist/cli/parsing/modules/LifecycleCommandModule.d.ts.map +1 -1
  49. package/dist/cli/parsing/modules/LifecycleCommandModule.js +78 -50
  50. package/dist/cli/parsing/modules/LifecycleCommandModule.js.map +1 -1
  51. package/dist/cli/parsing/modules/ListCommandModule.d.ts +8 -5
  52. package/dist/cli/parsing/modules/ListCommandModule.d.ts.map +1 -1
  53. package/dist/cli/parsing/modules/ListCommandModule.js +26 -15
  54. package/dist/cli/parsing/modules/ListCommandModule.js.map +1 -1
  55. package/dist/cli/parsing/modules/LoginCommandModule.d.ts +8 -5
  56. package/dist/cli/parsing/modules/LoginCommandModule.d.ts.map +1 -1
  57. package/dist/cli/parsing/modules/LoginCommandModule.js +34 -33
  58. package/dist/cli/parsing/modules/LoginCommandModule.js.map +1 -1
  59. package/dist/cli/parsing/modules/LogoutCommandModule.d.ts +8 -5
  60. package/dist/cli/parsing/modules/LogoutCommandModule.d.ts.map +1 -1
  61. package/dist/cli/parsing/modules/LogoutCommandModule.js +30 -28
  62. package/dist/cli/parsing/modules/LogoutCommandModule.js.map +1 -1
  63. package/dist/cli/parsing/modules/OutdatedCommandModule.d.ts +8 -5
  64. package/dist/cli/parsing/modules/OutdatedCommandModule.d.ts.map +1 -1
  65. package/dist/cli/parsing/modules/OutdatedCommandModule.js +21 -16
  66. package/dist/cli/parsing/modules/OutdatedCommandModule.js.map +1 -1
  67. package/dist/cli/parsing/modules/PackCommandModule.d.ts +8 -5
  68. package/dist/cli/parsing/modules/PackCommandModule.d.ts.map +1 -1
  69. package/dist/cli/parsing/modules/PackCommandModule.js +30 -28
  70. package/dist/cli/parsing/modules/PackCommandModule.js.map +1 -1
  71. package/dist/cli/parsing/modules/ProjectGetNameCommandModule.d.ts +8 -5
  72. package/dist/cli/parsing/modules/ProjectGetNameCommandModule.d.ts.map +1 -1
  73. package/dist/cli/parsing/modules/ProjectGetNameCommandModule.js +14 -11
  74. package/dist/cli/parsing/modules/ProjectGetNameCommandModule.js.map +1 -1
  75. package/dist/cli/parsing/modules/PublishCommandModule.d.ts +8 -5
  76. package/dist/cli/parsing/modules/PublishCommandModule.d.ts.map +1 -1
  77. package/dist/cli/parsing/modules/PublishCommandModule.js +63 -47
  78. package/dist/cli/parsing/modules/PublishCommandModule.js.map +1 -1
  79. package/dist/cli/parsing/modules/RegistryCommandModule.d.ts +8 -5
  80. package/dist/cli/parsing/modules/RegistryCommandModule.d.ts.map +1 -1
  81. package/dist/cli/parsing/modules/RegistryCommandModule.js +117 -120
  82. package/dist/cli/parsing/modules/RegistryCommandModule.js.map +1 -1
  83. package/dist/cli/parsing/modules/RemoveCommandModule.d.ts +8 -5
  84. package/dist/cli/parsing/modules/RemoveCommandModule.d.ts.map +1 -1
  85. package/dist/cli/parsing/modules/RemoveCommandModule.js +25 -14
  86. package/dist/cli/parsing/modules/RemoveCommandModule.js.map +1 -1
  87. package/dist/cli/parsing/modules/RequestsCommandModule.d.ts +8 -5
  88. package/dist/cli/parsing/modules/RequestsCommandModule.d.ts.map +1 -1
  89. package/dist/cli/parsing/modules/RequestsCommandModule.js +56 -60
  90. package/dist/cli/parsing/modules/RequestsCommandModule.js.map +1 -1
  91. package/dist/cli/parsing/modules/UpdateCommandModule.d.ts +8 -5
  92. package/dist/cli/parsing/modules/UpdateCommandModule.d.ts.map +1 -1
  93. package/dist/cli/parsing/modules/UpdateCommandModule.js +38 -25
  94. package/dist/cli/parsing/modules/UpdateCommandModule.js.map +1 -1
  95. package/dist/cli/parsing/modules/WhoamiCommandModule.d.ts +8 -5
  96. package/dist/cli/parsing/modules/WhoamiCommandModule.d.ts.map +1 -1
  97. package/dist/cli/parsing/modules/WhoamiCommandModule.js +30 -28
  98. package/dist/cli/parsing/modules/WhoamiCommandModule.js.map +1 -1
  99. package/dist/cli/parsing/modules/WhyCommandModule.d.ts +8 -5
  100. package/dist/cli/parsing/modules/WhyCommandModule.d.ts.map +1 -1
  101. package/dist/cli/parsing/modules/WhyCommandModule.js +25 -14
  102. package/dist/cli/parsing/modules/WhyCommandModule.js.map +1 -1
  103. package/dist/cli/parsing/modules/sharedOptions.d.ts +8 -5
  104. package/dist/cli/parsing/modules/sharedOptions.d.ts.map +1 -1
  105. package/dist/cli/parsing/modules/sharedOptions.js +18 -23
  106. package/dist/cli/parsing/modules/sharedOptions.js.map +1 -1
  107. package/dist/cli/runUAPKGCLI.d.ts +4 -1
  108. package/dist/cli/runUAPKGCLI.d.ts.map +1 -1
  109. package/dist/cli/runUAPKGCLI.js +10 -5
  110. package/dist/cli/runUAPKGCLI.js.map +1 -1
  111. package/dist/cli-bootstrap.d.ts +1 -2
  112. package/dist/cli-bootstrap.js +15 -12
  113. package/dist/cli-bootstrap.js.map +1 -1
  114. package/dist/commands/AddCommand.d.ts +19 -16
  115. package/dist/commands/AddCommand.d.ts.map +1 -1
  116. package/dist/commands/AddCommand.js +49 -53
  117. package/dist/commands/AddCommand.js.map +1 -1
  118. package/dist/commands/Command.d.ts +5 -2
  119. package/dist/commands/Command.d.ts.map +1 -1
  120. package/dist/commands/Command.js +1 -2
  121. package/dist/commands/ConfigCommand.d.ts +28 -25
  122. package/dist/commands/ConfigCommand.d.ts.map +1 -1
  123. package/dist/commands/ConfigCommand.js +165 -186
  124. package/dist/commands/ConfigCommand.js.map +1 -1
  125. package/dist/commands/InitCommand.d.ts +19 -16
  126. package/dist/commands/InitCommand.d.ts.map +1 -1
  127. package/dist/commands/InitCommand.js +65 -60
  128. package/dist/commands/InitCommand.js.map +1 -1
  129. package/dist/commands/InstallCommand.d.ts +16 -13
  130. package/dist/commands/InstallCommand.d.ts.map +1 -1
  131. package/dist/commands/InstallCommand.js +118 -110
  132. package/dist/commands/InstallCommand.js.map +1 -1
  133. package/dist/commands/ListCommand.d.ts +13 -10
  134. package/dist/commands/ListCommand.d.ts.map +1 -1
  135. package/dist/commands/ListCommand.js +76 -81
  136. package/dist/commands/ListCommand.js.map +1 -1
  137. package/dist/commands/LoginCommand.d.ts +17 -14
  138. package/dist/commands/LoginCommand.d.ts.map +1 -1
  139. package/dist/commands/LoginCommand.js +66 -72
  140. package/dist/commands/LoginCommand.js.map +1 -1
  141. package/dist/commands/LogoutCommand.d.ts +15 -12
  142. package/dist/commands/LogoutCommand.d.ts.map +1 -1
  143. package/dist/commands/LogoutCommand.js +36 -37
  144. package/dist/commands/LogoutCommand.js.map +1 -1
  145. package/dist/commands/OutdatedCommand.d.ts +12 -9
  146. package/dist/commands/OutdatedCommand.d.ts.map +1 -1
  147. package/dist/commands/OutdatedCommand.js +41 -40
  148. package/dist/commands/OutdatedCommand.js.map +1 -1
  149. package/dist/commands/PackCommand.d.ts +13 -10
  150. package/dist/commands/PackCommand.d.ts.map +1 -1
  151. package/dist/commands/PackCommand.js +26 -21
  152. package/dist/commands/PackCommand.js.map +1 -1
  153. package/dist/commands/PackageLifecycleCommand.d.ts +23 -19
  154. package/dist/commands/PackageLifecycleCommand.d.ts.map +1 -1
  155. package/dist/commands/PackageLifecycleCommand.js +144 -138
  156. package/dist/commands/PackageLifecycleCommand.js.map +1 -1
  157. package/dist/commands/PostinstallCandidateBuilder.d.ts +11 -8
  158. package/dist/commands/PostinstallCandidateBuilder.d.ts.map +1 -1
  159. package/dist/commands/PostinstallCandidateBuilder.js +42 -42
  160. package/dist/commands/PostinstallCandidateBuilder.js.map +1 -1
  161. package/dist/commands/ProjectGetNameCommand.d.ts +10 -7
  162. package/dist/commands/ProjectGetNameCommand.d.ts.map +1 -1
  163. package/dist/commands/ProjectGetNameCommand.js +25 -25
  164. package/dist/commands/ProjectGetNameCommand.js.map +1 -1
  165. package/dist/commands/PublishCommand.d.ts +29 -23
  166. package/dist/commands/PublishCommand.d.ts.map +1 -1
  167. package/dist/commands/PublishCommand.js +243 -254
  168. package/dist/commands/PublishCommand.js.map +1 -1
  169. package/dist/commands/RegistryCommand.d.ts +38 -35
  170. package/dist/commands/RegistryCommand.d.ts.map +1 -1
  171. package/dist/commands/RegistryCommand.js +195 -223
  172. package/dist/commands/RegistryCommand.js.map +1 -1
  173. package/dist/commands/RemoveCommand.d.ts +14 -11
  174. package/dist/commands/RemoveCommand.d.ts.map +1 -1
  175. package/dist/commands/RemoveCommand.js +47 -54
  176. package/dist/commands/RemoveCommand.js.map +1 -1
  177. package/dist/commands/RequestsCommand.d.ts +21 -18
  178. package/dist/commands/RequestsCommand.d.ts.map +1 -1
  179. package/dist/commands/RequestsCommand.js +82 -95
  180. package/dist/commands/RequestsCommand.js.map +1 -1
  181. package/dist/commands/UpdateCommand.d.ts +29 -26
  182. package/dist/commands/UpdateCommand.d.ts.map +1 -1
  183. package/dist/commands/UpdateCommand.js +111 -111
  184. package/dist/commands/UpdateCommand.js.map +1 -1
  185. package/dist/commands/WhoamiCommand.d.ts +30 -27
  186. package/dist/commands/WhoamiCommand.d.ts.map +1 -1
  187. package/dist/commands/WhoamiCommand.js +63 -72
  188. package/dist/commands/WhoamiCommand.js.map +1 -1
  189. package/dist/commands/WhyCommand.d.ts +13 -10
  190. package/dist/commands/WhyCommand.d.ts.map +1 -1
  191. package/dist/commands/WhyCommand.js +45 -44
  192. package/dist/commands/WhyCommand.js.map +1 -1
  193. package/dist/commands/add/DependencyAddResolver.d.ts +14 -11
  194. package/dist/commands/add/DependencyAddResolver.d.ts.map +1 -1
  195. package/dist/commands/add/DependencyAddResolver.js +36 -36
  196. package/dist/commands/add/DependencyAddResolver.js.map +1 -1
  197. package/dist/control-plane/AccountManager.d.ts +96 -94
  198. package/dist/control-plane/AccountManager.d.ts.map +1 -1
  199. package/dist/control-plane/AccountManager.js +775 -967
  200. package/dist/control-plane/AccountManager.js.map +1 -1
  201. package/dist/control-plane/ArtifactObserver.d.ts +19 -16
  202. package/dist/control-plane/ArtifactObserver.d.ts.map +1 -1
  203. package/dist/control-plane/ArtifactObserver.js +73 -59
  204. package/dist/control-plane/ArtifactObserver.js.map +1 -1
  205. package/dist/control-plane/AuthMetadataStore.d.ts +16 -13
  206. package/dist/control-plane/AuthMetadataStore.d.ts.map +1 -1
  207. package/dist/control-plane/AuthMetadataStore.js +111 -113
  208. package/dist/control-plane/AuthMetadataStore.js.map +1 -1
  209. package/dist/control-plane/AuthStoragePaths.d.ts +7 -4
  210. package/dist/control-plane/AuthStoragePaths.d.ts.map +1 -1
  211. package/dist/control-plane/AuthStoragePaths.js +19 -14
  212. package/dist/control-plane/AuthStoragePaths.js.map +1 -1
  213. package/dist/control-plane/AuthenticationSelector.d.ts +21 -18
  214. package/dist/control-plane/AuthenticationSelector.d.ts.map +1 -1
  215. package/dist/control-plane/AuthenticationSelector.js +69 -63
  216. package/dist/control-plane/AuthenticationSelector.js.map +1 -1
  217. package/dist/control-plane/ControlPlaneClient.d.ts +37 -28
  218. package/dist/control-plane/ControlPlaneClient.d.ts.map +1 -1
  219. package/dist/control-plane/ControlPlaneClient.js +265 -254
  220. package/dist/control-plane/ControlPlaneClient.js.map +1 -1
  221. package/dist/control-plane/ControlPlaneEndpoints.d.ts +9 -6
  222. package/dist/control-plane/ControlPlaneEndpoints.d.ts.map +1 -1
  223. package/dist/control-plane/ControlPlaneEndpoints.js +17 -12
  224. package/dist/control-plane/ControlPlaneEndpoints.js.map +1 -1
  225. package/dist/control-plane/ControlPlaneTypes.d.ts +176 -152
  226. package/dist/control-plane/ControlPlaneTypes.d.ts.map +1 -1
  227. package/dist/control-plane/ControlPlaneTypes.js +88 -81
  228. package/dist/control-plane/ControlPlaneTypes.js.map +1 -1
  229. package/dist/control-plane/CredentialStore.d.ts +20 -18
  230. package/dist/control-plane/CredentialStore.d.ts.map +1 -1
  231. package/dist/control-plane/CredentialStore.js +66 -83
  232. package/dist/control-plane/CredentialStore.js.map +1 -1
  233. package/dist/control-plane/DPoPKeyStore.d.ts +12 -9
  234. package/dist/control-plane/DPoPKeyStore.d.ts.map +1 -1
  235. package/dist/control-plane/DPoPKeyStore.js +57 -53
  236. package/dist/control-plane/DPoPKeyStore.js.map +1 -1
  237. package/dist/control-plane/GitHubActionsOidcCredentialProvider.d.ts +37 -4
  238. package/dist/control-plane/GitHubActionsOidcCredentialProvider.d.ts.map +1 -1
  239. package/dist/control-plane/GitHubActionsOidcCredentialProvider.js +197 -63
  240. package/dist/control-plane/GitHubActionsOidcCredentialProvider.js.map +1 -1
  241. package/dist/control-plane/PublishIdempotencyStore.d.ts +25 -9
  242. package/dist/control-plane/PublishIdempotencyStore.d.ts.map +1 -1
  243. package/dist/control-plane/PublishIdempotencyStore.js +97 -68
  244. package/dist/control-plane/PublishIdempotencyStore.js.map +1 -1
  245. package/dist/control-plane/PublishRequestErrorMapper.d.ts +155 -0
  246. package/dist/control-plane/PublishRequestErrorMapper.d.ts.map +1 -0
  247. package/dist/control-plane/PublishRequestErrorMapper.js +597 -0
  248. package/dist/control-plane/PublishRequestErrorMapper.js.map +1 -0
  249. package/dist/control-plane/RegistryGrantLock.d.ts +29 -26
  250. package/dist/control-plane/RegistryGrantLock.d.ts.map +1 -1
  251. package/dist/control-plane/RegistryGrantLock.js +149 -185
  252. package/dist/control-plane/RegistryGrantLock.js.map +1 -1
  253. package/dist/control-plane/RegistryTrustResolver.d.ts +13 -10
  254. package/dist/control-plane/RegistryTrustResolver.d.ts.map +1 -1
  255. package/dist/control-plane/RegistryTrustResolver.js +97 -132
  256. package/dist/control-plane/RegistryTrustResolver.js.map +1 -1
  257. package/dist/index.d.ts +62 -39
  258. package/dist/index.js +60 -53
  259. package/dist/postinstall/api/PostinstallDsl.d.ts +24 -21
  260. package/dist/postinstall/api/PostinstallDsl.d.ts.map +1 -1
  261. package/dist/postinstall/api/PostinstallDsl.js +32 -35
  262. package/dist/postinstall/api/PostinstallDsl.js.map +1 -1
  263. package/dist/postinstall/api/definePostinstall.d.ts +5 -2
  264. package/dist/postinstall/api/definePostinstall.d.ts.map +1 -1
  265. package/dist/postinstall/api/definePostinstall.js +20 -16
  266. package/dist/postinstall/api/definePostinstall.js.map +1 -1
  267. package/dist/postinstall/index.d.ts +25 -26
  268. package/dist/postinstall/index.js +25 -37
  269. package/dist/postinstall/loader/EntryResolver.d.ts +11 -9
  270. package/dist/postinstall/loader/EntryResolver.d.ts.map +1 -1
  271. package/dist/postinstall/loader/EntryResolver.js +36 -32
  272. package/dist/postinstall/loader/EntryResolver.js.map +1 -1
  273. package/dist/postinstall/loader/EsbuildTranspiler.d.ts +6 -3
  274. package/dist/postinstall/loader/EsbuildTranspiler.d.ts.map +1 -1
  275. package/dist/postinstall/loader/EsbuildTranspiler.js +52 -56
  276. package/dist/postinstall/loader/EsbuildTranspiler.js.map +1 -1
  277. package/dist/postinstall/loader/ExportValidator.d.ts +8 -5
  278. package/dist/postinstall/loader/ExportValidator.d.ts.map +1 -1
  279. package/dist/postinstall/loader/ExportValidator.js +36 -32
  280. package/dist/postinstall/loader/ExportValidator.js.map +1 -1
  281. package/dist/postinstall/loader/ModuleImporter.d.ts +17 -14
  282. package/dist/postinstall/loader/ModuleImporter.d.ts.map +1 -1
  283. package/dist/postinstall/loader/ModuleImporter.js +50 -58
  284. package/dist/postinstall/loader/ModuleImporter.js.map +1 -1
  285. package/dist/postinstall/loader/PostinstallLoader.d.ts +22 -19
  286. package/dist/postinstall/loader/PostinstallLoader.d.ts.map +1 -1
  287. package/dist/postinstall/loader/PostinstallLoader.js +62 -58
  288. package/dist/postinstall/loader/PostinstallLoader.js.map +1 -1
  289. package/dist/postinstall/markers/MarkerBlockEditor.d.ts +19 -16
  290. package/dist/postinstall/markers/MarkerBlockEditor.d.ts.map +1 -1
  291. package/dist/postinstall/markers/MarkerBlockEditor.js +48 -44
  292. package/dist/postinstall/markers/MarkerBlockEditor.js.map +1 -1
  293. package/dist/postinstall/markers/MarkerBlockService.d.ts +10 -7
  294. package/dist/postinstall/markers/MarkerBlockService.d.ts.map +1 -1
  295. package/dist/postinstall/markers/MarkerBlockService.js +44 -44
  296. package/dist/postinstall/markers/MarkerBlockService.js.map +1 -1
  297. package/dist/postinstall/markers/MarkerIntegrityValidator.d.ts +12 -9
  298. package/dist/postinstall/markers/MarkerIntegrityValidator.d.ts.map +1 -1
  299. package/dist/postinstall/markers/MarkerIntegrityValidator.js +47 -52
  300. package/dist/postinstall/markers/MarkerIntegrityValidator.js.map +1 -1
  301. package/dist/postinstall/policy/PostinstallPolicyGate.d.ts +25 -23
  302. package/dist/postinstall/policy/PostinstallPolicyGate.d.ts.map +1 -1
  303. package/dist/postinstall/policy/PostinstallPolicyGate.js +63 -52
  304. package/dist/postinstall/policy/PostinstallPolicyGate.js.map +1 -1
  305. package/dist/postinstall/runner/PostinstallOrchestrator.d.ts +48 -45
  306. package/dist/postinstall/runner/PostinstallOrchestrator.d.ts.map +1 -1
  307. package/dist/postinstall/runner/PostinstallOrchestrator.js +172 -170
  308. package/dist/postinstall/runner/PostinstallOrchestrator.js.map +1 -1
  309. package/dist/postinstall/unreal/BuildCsInjector.d.ts +16 -13
  310. package/dist/postinstall/unreal/BuildCsInjector.d.ts.map +1 -1
  311. package/dist/postinstall/unreal/BuildCsInjector.js +58 -53
  312. package/dist/postinstall/unreal/BuildCsInjector.js.map +1 -1
  313. package/dist/postinstall/unreal/CSharpInjectionEngine.d.ts +13 -10
  314. package/dist/postinstall/unreal/CSharpInjectionEngine.d.ts.map +1 -1
  315. package/dist/postinstall/unreal/CSharpInjectionEngine.js +56 -59
  316. package/dist/postinstall/unreal/CSharpInjectionEngine.js.map +1 -1
  317. package/dist/postinstall/unreal/CSharpStructureAnalyzer.d.ts +11 -8
  318. package/dist/postinstall/unreal/CSharpStructureAnalyzer.d.ts.map +1 -1
  319. package/dist/postinstall/unreal/CSharpStructureAnalyzer.js +123 -127
  320. package/dist/postinstall/unreal/CSharpStructureAnalyzer.js.map +1 -1
  321. package/dist/postinstall/unreal/CSharpStructures.d.ts +18 -15
  322. package/dist/postinstall/unreal/CSharpStructures.d.ts.map +1 -1
  323. package/dist/postinstall/unreal/CSharpStructures.js +1 -2
  324. package/dist/postinstall/unreal/CSharpWrapperFactory.d.ts +7 -4
  325. package/dist/postinstall/unreal/CSharpWrapperFactory.d.ts.map +1 -1
  326. package/dist/postinstall/unreal/CSharpWrapperFactory.js +54 -58
  327. package/dist/postinstall/unreal/CSharpWrapperFactory.js.map +1 -1
  328. package/dist/postinstall/unreal/PluginHash.d.ts +5 -2
  329. package/dist/postinstall/unreal/PluginHash.d.ts.map +1 -1
  330. package/dist/postinstall/unreal/PluginHash.js +13 -8
  331. package/dist/postinstall/unreal/PluginHash.js.map +1 -1
  332. package/dist/postinstall/unreal/PrettyParseError.d.ts +8 -5
  333. package/dist/postinstall/unreal/PrettyParseError.d.ts.map +1 -1
  334. package/dist/postinstall/unreal/PrettyParseError.js +37 -37
  335. package/dist/postinstall/unreal/PrettyParseError.js.map +1 -1
  336. package/dist/postinstall/unreal/ProjectFileLocator.d.ts +12 -9
  337. package/dist/postinstall/unreal/ProjectFileLocator.d.ts.map +1 -1
  338. package/dist/postinstall/unreal/ProjectFileLocator.js +49 -51
  339. package/dist/postinstall/unreal/ProjectFileLocator.js.map +1 -1
  340. package/dist/postinstall/unreal/TargetCsInjector.d.ts +16 -13
  341. package/dist/postinstall/unreal/TargetCsInjector.d.ts.map +1 -1
  342. package/dist/postinstall/unreal/TargetCsInjector.js +58 -53
  343. package/dist/postinstall/unreal/TargetCsInjector.js.map +1 -1
  344. package/dist/postinstall/unreal/UProjectInjector.d.ts +6 -3
  345. package/dist/postinstall/unreal/UProjectInjector.d.ts.map +1 -1
  346. package/dist/postinstall/unreal/UProjectInjector.js +56 -52
  347. package/dist/postinstall/unreal/UProjectInjector.js.map +1 -1
  348. package/dist/postinstall/unreal/UProjectMetadataReader.d.ts +5 -2
  349. package/dist/postinstall/unreal/UProjectMetadataReader.d.ts.map +1 -1
  350. package/dist/postinstall/unreal/UProjectMetadataReader.js +22 -18
  351. package/dist/postinstall/unreal/UProjectMetadataReader.js.map +1 -1
  352. package/dist/postinstall/unreal/UnrealSourceCatalog.d.ts +17 -14
  353. package/dist/postinstall/unreal/UnrealSourceCatalog.d.ts.map +1 -1
  354. package/dist/postinstall/unreal/UnrealSourceCatalog.js +50 -50
  355. package/dist/postinstall/unreal/UnrealSourceCatalog.js.map +1 -1
  356. package/dist/prompts/InkPromptService.d.ts +10 -7
  357. package/dist/prompts/InkPromptService.d.ts.map +1 -1
  358. package/dist/prompts/InkPromptService.js +100 -71
  359. package/dist/prompts/InkPromptService.js.map +1 -1
  360. package/dist/prompts/ProjectContextDetector.d.ts +10 -7
  361. package/dist/prompts/ProjectContextDetector.d.ts.map +1 -1
  362. package/dist/prompts/ProjectContextDetector.js +32 -26
  363. package/dist/prompts/ProjectContextDetector.js.map +1 -1
  364. package/dist/prompts/PromptService.d.ts +11 -8
  365. package/dist/prompts/PromptService.d.ts.map +1 -1
  366. package/dist/prompts/PromptService.js +1 -8
  367. package/dist/reporting/DiagnosticDeduplicator.d.ts +8 -5
  368. package/dist/reporting/DiagnosticDeduplicator.d.ts.map +1 -1
  369. package/dist/reporting/DiagnosticDeduplicator.js +36 -35
  370. package/dist/reporting/DiagnosticDeduplicator.js.map +1 -1
  371. package/dist/reporting/DiagnosticRenderer.d.ts +11 -8
  372. package/dist/reporting/DiagnosticRenderer.d.ts.map +1 -1
  373. package/dist/reporting/DiagnosticRenderer.js +1 -2
  374. package/dist/reporting/DiagnosticReporter.d.ts +12 -9
  375. package/dist/reporting/DiagnosticReporter.d.ts.map +1 -1
  376. package/dist/reporting/DiagnosticReporter.js +40 -39
  377. package/dist/reporting/DiagnosticReporter.js.map +1 -1
  378. package/dist/reporting/InkDiagnosticRenderer.d.ts +12 -9
  379. package/dist/reporting/InkDiagnosticRenderer.d.ts.map +1 -1
  380. package/dist/reporting/InkDiagnosticRenderer.js +50 -42
  381. package/dist/reporting/InkDiagnosticRenderer.js.map +1 -1
  382. package/dist/reporting/InstallProgressReporter.d.ts +23 -20
  383. package/dist/reporting/InstallProgressReporter.d.ts.map +1 -1
  384. package/dist/reporting/InstallProgressReporter.js +48 -47
  385. package/dist/reporting/InstallProgressReporter.js.map +1 -1
  386. package/dist/reporting/JsonReporter.d.ts +16 -13
  387. package/dist/reporting/JsonReporter.d.ts.map +1 -1
  388. package/dist/reporting/JsonReporter.js +34 -20
  389. package/dist/reporting/JsonReporter.js.map +1 -1
  390. package/dist/reporting/RegistryRequestTerminalFormatter.d.ts +36 -0
  391. package/dist/reporting/RegistryRequestTerminalFormatter.d.ts.map +1 -0
  392. package/dist/reporting/RegistryRequestTerminalFormatter.js +90 -0
  393. package/dist/reporting/RegistryRequestTerminalFormatter.js.map +1 -0
  394. package/dist/reporting/TextDiagnosticRenderer.d.ts +11 -8
  395. package/dist/reporting/TextDiagnosticRenderer.d.ts.map +1 -1
  396. package/dist/reporting/TextDiagnosticRenderer.js +36 -28
  397. package/dist/reporting/TextDiagnosticRenderer.js.map +1 -1
  398. package/dist/reporting/TextSink.d.ts +14 -11
  399. package/dist/reporting/TextSink.d.ts.map +1 -1
  400. package/dist/reporting/TextSink.js +24 -20
  401. package/dist/reporting/TextSink.js.map +1 -1
  402. package/package.json +31 -32
  403. package/dist/cli/parsing/contracts/UAPKGCommandModule.js.map +0 -1
  404. package/dist/cli-bootstrap.d.ts.map +0 -1
  405. package/dist/commands/Command.js.map +0 -1
  406. package/dist/index.d.ts.map +0 -1
  407. package/dist/index.js.map +0 -1
  408. package/dist/postinstall/index.d.ts.map +0 -1
  409. package/dist/postinstall/index.js.map +0 -1
  410. package/dist/postinstall/unreal/CSharpStructures.js.map +0 -1
  411. package/dist/prompts/PromptService.js.map +0 -1
  412. package/dist/reporting/DiagnosticRenderer.js.map +0 -1
@@ -1,1014 +1,822 @@
1
- import { createServer } from 'node:http';
2
- import { hostname } from 'node:os';
3
- import { createControlPlaneCommandFailedDiagnostic, } from '@uapkg/diagnostics';
4
- import isCI from 'is-ci';
5
- import * as oauth from 'oauth4webapi';
6
- import { AuthMetadataStore } from './AuthMetadataStore.js';
7
- import { resolveAuthStoragePaths } from './AuthStoragePaths.js';
8
- import { ControlPlaneClient } from './ControlPlaneClient.js';
9
- import { ControlPlaneError, isUAPKGCliScope, OAuthScopeInsufficientError, OAuthScopeUnsupportedError, parseUAPKGCliScopeString, registryAudience, UAPKG_AUTHORIZATION_ISSUER, UAPKG_CLI_CLIENT_ID, UAPKG_CLI_SCOPES, UAPKG_CONTROL_PLANE_API, } from './ControlPlaneTypes.js';
10
- import { CredentialStore } from './CredentialStore.js';
11
- import { DPoPKeyStore } from './DPoPKeyStore.js';
12
- import { FileRegistryGrantLock } from './RegistryGrantLock.js';
13
- const INTERACTIVE_LOGIN_TIMEOUT_MS = 3 * 60 * 1000;
14
- const INTERACTIVE_LOGIN_FINALIZATION_TIMEOUT_MS = 60 * 1000;
15
- const CLI_LOGIN_RECONCILIATION_TIMEOUT_MS = 5 * 1000;
16
- const OAUTH_BACKCHANNEL_TIMEOUT_MS = 30 * 1000;
17
- const LOOPBACK_CALLBACK_PATH = '/callback';
18
- const ACCOUNT_COMPLETION_PATH = '/cli-login/complete';
1
+ import { resolveAuthStoragePaths } from "./AuthStoragePaths.js";
2
+ import { FileRegistryGrantLock } from "./RegistryGrantLock.js";
3
+ import { AuthMetadataStore } from "./AuthMetadataStore.js";
4
+ import { ControlPlaneError, OAuthScopeInsufficientError, OAuthScopeUnsupportedError, UAPKG_AUTHORIZATION_ISSUER, UAPKG_CLI_CLIENT_ID, UAPKG_CLI_SCOPES, UAPKG_CONTROL_PLANE_API, isUAPKGCliScope, parseUAPKGCliScopeString, registryAudience } from "./ControlPlaneTypes.js";
5
+ import { ControlPlaneClient } from "./ControlPlaneClient.js";
6
+ import { CredentialStore } from "./CredentialStore.js";
7
+ import { DPoPKeyStore } from "./DPoPKeyStore.js";
8
+ import { createControlPlaneCommandFailedDiagnostic } from "@uapkg/diagnostics";
9
+ import { createServer } from "node:http";
10
+ import { hostname } from "node:os";
11
+ import isCI from "is-ci";
12
+ import * as oauth from "oauth4webapi";
13
+
14
+ //#region src/control-plane/AccountManager.ts
15
+ const INTERACTIVE_LOGIN_TIMEOUT_MS = 18e4;
16
+ const INTERACTIVE_LOGIN_FINALIZATION_TIMEOUT_MS = 6e4;
17
+ const CLI_LOGIN_RECONCILIATION_TIMEOUT_MS = 5e3;
18
+ const OAUTH_BACKCHANNEL_TIMEOUT_MS = 3e4;
19
+ const LOOPBACK_CALLBACK_PATH = "/callback";
20
+ const ACCOUNT_COMPLETION_PATH = "/cli-login/complete";
19
21
  const CONTROL_PLANE_SERVER_CODE_PATTERN = /^[A-Z][A-Z0-9_]{0,127}$/;
20
- export class LoginError extends Error {
21
- code;
22
- oauthError;
23
- constructor(code, message, oauthError) {
24
- super(message);
25
- this.code = code;
26
- this.oauthError = oauthError;
27
- this.name = 'LoginError';
28
- }
29
- }
30
- export class AccountManager {
31
- metadata;
32
- credentials;
33
- openBrowser;
34
- isInteractiveLogin;
35
- interactiveLoginTimeoutMs;
36
- interactiveLoginFinalizationTimeoutMs;
37
- keyStore;
38
- accessTokenCache = new Map();
39
- grantOperationTails = new Map();
40
- grantLock;
41
- constructor(metadata = new AuthMetadataStore(), credentials = new CredentialStore(), openBrowser = async (url) => {
42
- const { default: open } = await import('open');
43
- await open(url, { wait: false });
44
- }, isInteractiveLogin = () => Boolean(process.stdin.isTTY && process.stdout.isTTY && !isCI), grantLock, interactiveLoginTimeoutMs = INTERACTIVE_LOGIN_TIMEOUT_MS, interactiveLoginFinalizationTimeoutMs = INTERACTIVE_LOGIN_FINALIZATION_TIMEOUT_MS) {
45
- this.metadata = metadata;
46
- this.credentials = credentials;
47
- this.openBrowser = openBrowser;
48
- this.isInteractiveLogin = isInteractiveLogin;
49
- this.interactiveLoginTimeoutMs = interactiveLoginTimeoutMs;
50
- this.interactiveLoginFinalizationTimeoutMs = interactiveLoginFinalizationTimeoutMs;
51
- this.keyStore = new DPoPKeyStore(credentials);
52
- const metadataPath = typeof metadata.path === 'string' ? metadata.path : undefined;
53
- this.grantLock = grantLock ?? new FileRegistryGrantLock(resolveAuthStoragePaths(metadataPath).locksDirectory);
54
- }
55
- async hasGrant(trust) {
56
- return Boolean(await this.metadata.find(trust.issuer, trust.registryId));
57
- }
58
- invalidateAccessCredentials(trust) {
59
- for (const key of this.accessTokenCache.keys()) {
60
- if (key.startsWith(`${trust.issuer}|${trust.registryId}|`)) {
61
- this.accessTokenCache.delete(key);
62
- }
63
- }
64
- }
65
- async login(trust, options = {}) {
66
- this.assertPinnedTrust(trust);
67
- this.assertInteractiveLogin();
68
- await this.credentials.assertAvailable();
69
- const previous = await this.metadata.find(trust.issuer, trust.registryId);
70
- if (previous && !options.reauthorize) {
71
- throw new Error(`This device already has a saved login for "${trust.alias}". Use \`uapkg login --registry ${trust.alias} --reauthorize\` to replace it.`);
72
- }
73
- emitLoginProgress(options.onProgress, { type: 'preparing', registryAlias: trust.alias });
74
- const issuer = new URL(trust.issuer);
75
- const as = await this.discover(issuer);
76
- this.validateAuthorizationServer(as);
77
- this.assertIssuerSupportsScopes(as, trust, UAPKG_CLI_SCOPES);
78
- const client = this.client();
79
- const keyPair = await this.keyStore.generate();
80
- const dpop = oauth.DPoP(client, keyPair);
81
- const publicKeyThumbprint = await dpop.calculateThumbprint();
82
- const receiver = await LoopbackAuthorizationReceiver.listen(issuer);
83
- let issuedRefreshToken;
84
- let retainedIssuedGrant = false;
85
- let preserveIssuedGrant = false;
86
- let callbackReceipt;
87
- let finalizationController;
88
- let finalizationTimeout;
89
- try {
90
- const codeVerifier = oauth.generateRandomCodeVerifier();
91
- const codeChallenge = await oauth.calculatePKCECodeChallenge(codeVerifier);
92
- const state = oauth.generateRandomState();
93
- const nonce = oauth.generateRandomNonce();
94
- const requestedScopes = ['openid', 'offline_access', ...UAPKG_CLI_SCOPES];
95
- const scope = requestedScopes.join(' ');
96
- const deviceName = normalizeDeviceName(options.deviceName);
97
- const parameters = new URLSearchParams({
98
- client_id: client.client_id,
99
- redirect_uri: receiver.redirectUri,
100
- response_type: 'code',
101
- code_challenge: codeChallenge,
102
- code_challenge_method: 'S256',
103
- state,
104
- nonce,
105
- scope,
106
- resource: trust.resource,
107
- dpop_jkt: publicKeyThumbprint,
108
- registry_id: trust.registryId,
109
- registry_source_fingerprint: trust.repositoryFingerprint,
110
- device_name: deviceName,
111
- max_age: '300',
112
- });
113
- if (requestedScopes.includes('offline_access')) {
114
- parameters.set('prompt', 'consent');
115
- }
116
- const expectedPredecessorGrantId = options.reauthorize && previous ? previous.grantId : null;
117
- if (expectedPredecessorGrantId) {
118
- parameters.set('replace_grant_id', expectedPredecessorGrantId);
119
- }
120
- const pushed = await this.withDPoPNonceRetry(() => oauth.pushedAuthorizationRequest(as, client, oauth.None(), parameters, {
121
- DPoP: dpop,
122
- signal: () => AbortSignal.timeout(OAUTH_BACKCHANNEL_TIMEOUT_MS),
123
- }), (response) => oauth.processPushedAuthorizationResponse(as, client, response));
124
- if (!as.authorization_endpoint) {
125
- throw new Error('The authorization server did not advertise an authorization endpoint.');
126
- }
127
- const authorizationUrl = new URL(as.authorization_endpoint);
128
- authorizationUrl.searchParams.set('client_id', client.client_id);
129
- authorizationUrl.searchParams.set('request_uri', pushed.request_uri);
130
- emitLoginProgress(options.onProgress, { type: 'opening-browser' });
131
- try {
132
- await this.openBrowser(authorizationUrl.href);
133
- }
134
- catch {
135
- emitLoginProgress(options.onProgress, {
136
- type: 'browser-open-failed',
137
- authorizationUrl: authorizationUrl.href,
138
- });
139
- }
140
- emitLoginProgress(options.onProgress, { type: 'waiting-for-decision' });
141
- callbackReceipt = await receiver.waitForCallback(this.interactiveLoginTimeoutMs, trust.alias);
142
- finalizationController = new AbortController();
143
- finalizationTimeout = setTimeout(() => {
144
- finalizationController?.abort(loginFinalizationTimeoutError(trust.alias));
145
- }, this.interactiveLoginFinalizationTimeoutMs);
146
- const finalizationSignal = finalizationController.signal;
147
- const callbackUrl = callbackReceipt.url;
148
- if (callbackUrl.searchParams.get('iss') !== trust.issuer) {
149
- throw new LoginError('LOGIN_AUTHORIZATION_RESPONSE_INVALID', 'The browser authorization response came from an unexpected issuer. Run `uapkg login` again.');
150
- }
151
- let callbackParameters;
152
- try {
153
- callbackParameters = oauth.validateAuthResponse(as, client, callbackUrl, state);
154
- }
155
- catch (error) {
156
- throw authorizationResponseLoginError(error);
157
- }
158
- emitLoginProgress(options.onProgress, { type: 'approval-received' });
159
- const tokens = await this.withDPoPNonceRetry(() => oauth.authorizationCodeGrantRequest(as, client, oauth.None(), callbackParameters, receiver.redirectUri, codeVerifier, { DPoP: dpop, signal: finalizationSignal }), (response) => oauth.processAuthorizationCodeResponse(as, client, response, {
160
- expectedNonce: nonce,
161
- maxAge: 300,
162
- requireIdToken: true,
163
- }));
164
- finalizationSignal.throwIfAborted();
165
- if (tokens.token_type !== 'dpop') {
166
- throw new Error('The authorization server did not issue a DPoP-bound access token.');
167
- }
168
- if (!tokens.refresh_token) {
169
- throw new Error('The authorization server did not issue a persistent registry grant.');
170
- }
171
- const refreshToken = tokens.refresh_token;
172
- issuedRefreshToken = refreshToken;
173
- const controlPlane = new ControlPlaneClient(trust.apiBaseUrl);
174
- const issuedCredential = {
175
- kind: 'dpop',
176
- accessToken: tokens.access_token,
177
- dpop,
178
- registryAlias: trust.alias,
179
- requestedScopes: UAPKG_CLI_SCOPES,
180
- };
181
- const self = await controlPlane.getCliLoginConfirmation(issuedCredential, finalizationSignal);
182
- finalizationSignal.throwIfAborted();
183
- if (self.grant.replacesGrantId !== expectedPredecessorGrantId) {
184
- throw loginReplacementBindingError(trust.alias);
185
- }
186
- if (self.registry.id !== trust.registryId) {
187
- throw new Error('The authorization server returned a registry grant for an unexpected registry.');
188
- }
189
- const missingScopes = UAPKG_CLI_SCOPES.filter((scope) => !self.grant.scopes.includes(scope));
190
- if (missingScopes.length > 0) {
191
- throw new Error(`The authorization server omitted required CLI capabilities: ${missingScopes.join(', ')}.`);
192
- }
193
- if (self.grant.status === 'pending' &&
194
- timestampFromIso(self.grant.activationExpiresAt) <= Math.floor(Date.now() / 1000)) {
195
- throw new LoginError('LOGIN_AUTHORIZATION_TIMEOUT', `Login approval expired before this device could confirm it. Run \`uapkg login --registry ${trust.alias}\` to try again.`);
196
- }
197
- const grantId = self.grant.id;
198
- const keyReference = this.credentials.createReference('dpop-key', trust.issuer, trust.registryId, grantId);
199
- const refreshTokenReference = this.credentials.createReference('grant', trust.issuer, trust.registryId, grantId);
200
- const metadata = {
201
- issuer: trust.issuer,
202
- registryId: trust.registryId,
203
- registryName: trust.registryName,
204
- grantId,
205
- clientId: client.client_id,
206
- keyReference,
207
- refreshTokenReference,
208
- publicKeyThumbprint,
209
- deviceName: self.grant.deviceName,
210
- repositoryFingerprint: trust.repositoryFingerprint,
211
- account: self.account,
212
- createdAt: Math.floor(Date.now() / 1000),
213
- idleExpiresAt: timestampFromIso(self.grant.idleExpiresAt),
214
- expiresAt: timestampFromIso(self.grant.absoluteExpiresAt),
215
- };
216
- let previousForCleanup;
217
- await this.serializeGrantOperation(trust, async () => {
218
- const currentPrevious = await this.metadata.find(trust.issuer, trust.registryId);
219
- if (!isSameRegistryGrant(previous, currentPrevious)) {
220
- if (options.reauthorize) {
221
- throw loginReauthorizationConflictError(trust.alias);
222
- }
223
- throw new Error(`This device already has a saved login for "${trust.alias}". Use \`uapkg login --registry ${trust.alias} --reauthorize\` to replace it.`);
224
- }
225
- if (currentPrevious && !options.reauthorize) {
226
- throw new Error(`This device already has a saved login for "${trust.alias}". Use \`uapkg login --registry ${trust.alias} --reauthorize\` to replace it.`);
227
- }
228
- emitLoginProgress(options.onProgress, { type: 'saving-local-credentials' });
229
- await this.persistPreparedGrant(metadata, keyPair, refreshToken, currentPrevious, finalizationSignal);
230
- if (self.grant.status === 'pending') {
231
- emitLoginProgress(options.onProgress, { type: 'confirming-with-service' });
232
- const activation = await this.activatePreparedGrant(controlPlane, issuedCredential, metadata.grantId, expectedPredecessorGrantId, finalizationSignal, trust.alias);
233
- if (activation.kind === 'rejected') {
234
- await this.rollbackPreparedGrant(metadata, currentPrevious);
235
- throw activation.error;
236
- }
237
- if (activation.kind === 'ambiguous') {
238
- preserveIssuedGrant = true;
239
- throw activation.error;
240
- }
241
- }
242
- retainedIssuedGrant = true;
243
- this.invalidateAccessCredentials(trust);
244
- if (finalizationTimeout) {
245
- clearTimeout(finalizationTimeout);
246
- finalizationTimeout = undefined;
247
- }
248
- previousForCleanup = currentPrevious;
249
- });
250
- await callbackReceipt.complete('success');
251
- let warnings = [];
252
- if (previousForCleanup) {
253
- try {
254
- warnings = await this.serializeGrantOperation(trust, () => this.cleanupPreviousLocalCredentials(metadata, previousForCleanup));
255
- }
256
- catch {
257
- warnings = [
258
- 'The new login is active, but UAPKG could not remove one or more old protected credential entries. Remove the stale UAPKG entries from the operating-system credential store.',
259
- ];
260
- }
261
- }
262
- return { grant: metadata, warnings };
263
- }
264
- catch (error) {
265
- if (finalizationTimeout) {
266
- clearTimeout(finalizationTimeout);
267
- finalizationTimeout = undefined;
268
- }
269
- const failure = error instanceof LoginError
270
- ? error
271
- : finalizationController?.signal.aborted && finalizationController.signal.reason instanceof LoginError
272
- ? finalizationController.signal.reason
273
- : error;
274
- if (issuedRefreshToken && !retainedIssuedGrant && !preserveIssuedGrant) {
275
- await this.revokeToken(as, client, issuedRefreshToken, dpop).catch(() => undefined);
276
- }
277
- const loginError = normalizeLoginError(failure);
278
- if (callbackReceipt) {
279
- const outcome = loginError.code === 'LOGIN_ACCESS_DENIED' ? 'denied' : 'failed';
280
- await callbackReceipt.complete(outcome).catch(() => undefined);
281
- }
282
- throw loginError;
283
- }
284
- finally {
285
- if (finalizationTimeout)
286
- clearTimeout(finalizationTimeout);
287
- receiver.close();
288
- }
289
- }
290
- async getAccessCredential(trust, scopes) {
291
- this.assertPinnedTrust(trust);
292
- const requestedScopes = [...new Set(scopes)].sort();
293
- if (requestedScopes.length === 0 || requestedScopes.some((scope) => !isUAPKGCliScope(scope))) {
294
- throw new Error('A control-plane operation requested an unsupported OAuth capability scope.');
295
- }
296
- const grant = await this.requireUsableGrant(trust);
297
- const as = await this.discover(new URL(trust.issuer));
298
- this.assertIssuerSupportsScopes(as, trust, requestedScopes);
299
- const cacheKey = this.accessTokenCacheKey(grant, requestedScopes);
300
- const cached = this.accessTokenCache.get(cacheKey);
301
- if (cached && cached.expiresAt > Date.now() + 15_000) {
302
- return {
303
- grant,
304
- credential: {
305
- kind: 'dpop',
306
- accessToken: cached.token,
307
- dpop: cached.dpop,
308
- registryAlias: trust.alias,
309
- requestedScopes,
310
- },
311
- };
312
- }
313
- return this.serializeGrantOperation(trust, async () => {
314
- // Another process may have replaced the grant or rotated its refresh
315
- // token while this process waited. Reload every persistent component
316
- // only after the cross-process lock has been acquired.
317
- const currentGrant = await this.requireUsableGrant(trust);
318
- const currentCacheKey = this.accessTokenCacheKey(currentGrant, requestedScopes);
319
- const refreshedCached = this.accessTokenCache.get(currentCacheKey);
320
- if (refreshedCached && refreshedCached.expiresAt > Date.now() + 15_000) {
321
- return {
322
- grant: currentGrant,
323
- credential: {
324
- kind: 'dpop',
325
- accessToken: refreshedCached.token,
326
- dpop: refreshedCached.dpop,
327
- registryAlias: trust.alias,
328
- requestedScopes,
329
- },
330
- };
331
- }
332
- const pair = await this.keyStore.load(currentGrant.keyReference);
333
- if (!pair)
334
- throw missingKeyError(trust);
335
- const client = this.client();
336
- const dpop = oauth.DPoP(client, pair);
337
- if ((await dpop.calculateThumbprint()) !== currentGrant.publicKeyThumbprint) {
338
- throw missingKeyError(trust);
339
- }
340
- // Refresh tokens rotate on every successful use. Read the current value
341
- // only after acquiring both the process-local and filesystem lock.
342
- const refreshToken = await this.credentials.get(currentGrant.refreshTokenReference);
343
- if (!refreshToken) {
344
- throw new Error(`The saved login for "${trust.alias}" is missing its protected registry grant. Run \`uapkg login --registry ${trust.alias}\` again.`);
345
- }
346
- let tokenResponse;
347
- try {
348
- tokenResponse = await this.withDPoPNonceRetry(() => oauth.refreshTokenGrantRequest(as, client, oauth.None(), refreshToken, {
349
- DPoP: dpop,
350
- additionalParameters: {
351
- resource: trust.resource,
352
- scope: requestedScopes.join(' '),
353
- },
354
- }), (response) => oauth.processRefreshTokenResponse(as, client, response));
355
- }
356
- catch (error) {
357
- if (error instanceof oauth.ResponseBodyError && error.error === 'invalid_scope') {
358
- const hintedScopes = parseUAPKGCliScopeString(error.cause.scope).filter((scope) => requestedScopes.includes(scope));
359
- const missingScopes = hintedScopes.length > 0 ? hintedScopes : requestedScopes;
360
- throw new OAuthScopeInsufficientError('The saved registry grant does not include every OAuth scope required by this operation.', trust.alias, requestedScopes, requestedScopes, missingScopes, 403, { cause: error });
361
- }
362
- if (error instanceof oauth.ResponseBodyError &&
363
- (error.error === 'invalid_grant' || error.error === 'invalid_token')) {
364
- throw new Error(`Your saved login for "${trust.alias}" is no longer valid. Run \`uapkg login --registry ${trust.alias} --reauthorize\` to authenticate again.`, { cause: error });
365
- }
366
- throw error;
367
- }
368
- if (tokenResponse.token_type !== 'dpop') {
369
- throw new Error('The authorization server returned an access token that is not DPoP-bound.');
370
- }
371
- if (tokenResponse.refresh_token && tokenResponse.refresh_token !== refreshToken) {
372
- await this.credentials.set(currentGrant.refreshTokenReference, tokenResponse.refresh_token);
373
- }
374
- const expiresAt = Date.now() + Math.max(1, tokenResponse.expires_in ?? 300) * 1000;
375
- this.accessTokenCache.set(currentCacheKey, { token: tokenResponse.access_token, expiresAt, dpop });
376
- return {
377
- grant: currentGrant,
378
- credential: {
379
- kind: 'dpop',
380
- accessToken: tokenResponse.access_token,
381
- dpop,
382
- registryAlias: trust.alias,
383
- requestedScopes,
384
- },
385
- };
386
- });
387
- }
388
- async logout(trust, localOnly = false) {
389
- this.assertPinnedTrust(trust);
390
- return this.serializeGrantOperation(trust, async () => {
391
- const grant = await this.metadata.find(trust.issuer, trust.registryId);
392
- if (!grant)
393
- return 'not-logged-in';
394
- if (!localOnly) {
395
- try {
396
- await this.revokeSavedGrant(grant);
397
- }
398
- catch (error) {
399
- throw new Error(`Unable to revoke the registry grant for "${trust.alias}". The local login was kept so you can retry. Use --local-only only if you accept that account-site revocation may still be required.`, { cause: error });
400
- }
401
- }
402
- await Promise.all([
403
- this.keyStore.delete(grant.keyReference),
404
- this.credentials.delete(grant.refreshTokenReference),
405
- ]);
406
- await this.metadata.remove(grant.issuer, grant.registryId);
407
- this.invalidateAccessCredentials(trust);
408
- return 'removed';
409
- });
410
- }
411
- async requireUsableGrant(trust) {
412
- const grant = await this.metadata.find(trust.issuer, trust.registryId);
413
- if (!grant) {
414
- throw new Error(`You are not logged in to "${trust.alias}". Run \`uapkg login --registry ${trust.alias}\`.`);
415
- }
416
- if (grant.repositoryFingerprint !== trust.repositoryFingerprint) {
417
- throw new Error(`The configured Git source for "${trust.alias}" does not match the source authorized by the saved login. Run \`uapkg login --registry ${trust.alias} --reauthorize\`.`);
418
- }
419
- const now = Math.floor(Date.now() / 1000);
420
- // The idle deadline advances whenever the grant is used. The saved value
421
- // is display metadata from login time, so the server remains authoritative
422
- // for idle expiry; the absolute deadline is stable and safe to reject
423
- // locally.
424
- if (grant.expiresAt && grant.expiresAt <= now) {
425
- throw new Error(`Your saved login for "${trust.alias}" has expired. Run \`uapkg login --registry ${trust.alias}\` again.`);
426
- }
427
- return grant;
428
- }
429
- async revokeSavedGrant(grant) {
430
- const refreshToken = await this.credentials.get(grant.refreshTokenReference);
431
- if (!refreshToken) {
432
- throw new Error('The registry grant cannot be revoked because its protected credential is missing.');
433
- }
434
- const pair = await this.keyStore.load(grant.keyReference);
435
- if (!pair)
436
- throw new Error('The registry grant cannot be revoked because its DPoP key is missing.');
437
- const dpop = oauth.DPoP(this.client(), pair);
438
- if ((await dpop.calculateThumbprint()) !== grant.publicKeyThumbprint) {
439
- throw new Error('The registry grant cannot be revoked because its DPoP key has changed.');
440
- }
441
- const as = await this.discover(new URL(grant.issuer));
442
- await this.revokeToken(as, this.client(), refreshToken, dpop);
443
- }
444
- async activatePreparedGrant(controlPlane, credential, expectedGrantId, expectedPredecessorGrantId, signal, registryAlias) {
445
- try {
446
- const confirmed = await controlPlane.confirmCliLogin(credential, signal);
447
- if (confirmed.id === expectedGrantId && confirmed.replacesGrantId === expectedPredecessorGrantId) {
448
- return { kind: 'active' };
449
- }
450
- return this.reconcilePreparedGrant(controlPlane, credential, expectedGrantId, expectedPredecessorGrantId, registryAlias);
451
- }
452
- catch (error) {
453
- if (isCliLoginReauthorizationConflict(error)) {
454
- return { kind: 'rejected', error: reauthorizationConflictLoginError(error) };
455
- }
456
- if (isDefinitiveCliLoginConfirmationRejection(error))
457
- return { kind: 'rejected', error };
458
- return this.reconcilePreparedGrant(controlPlane, credential, expectedGrantId, expectedPredecessorGrantId, registryAlias);
459
- }
460
- }
461
- async reconcilePreparedGrant(controlPlane, credential, expectedGrantId, expectedPredecessorGrantId, registryAlias) {
462
- const signal = AbortSignal.timeout(CLI_LOGIN_RECONCILIATION_TIMEOUT_MS);
463
- let retryActivation = true;
464
- try {
465
- const observed = await controlPlane.getCliLoginConfirmation(credential, signal);
466
- if (observed.grant.id !== expectedGrantId || observed.grant.replacesGrantId !== expectedPredecessorGrantId) {
467
- retryActivation = false;
468
- }
469
- else if (observed.grant.status === 'active') {
470
- return { kind: 'active' };
471
- }
472
- }
473
- catch {
474
- // An idempotent activation retry can still resolve a failed status read.
475
- }
476
- if (retryActivation) {
477
- try {
478
- const confirmed = await controlPlane.confirmCliLogin(credential, signal);
479
- if (confirmed.id === expectedGrantId && confirmed.replacesGrantId === expectedPredecessorGrantId) {
480
- return { kind: 'active' };
481
- }
482
- }
483
- catch {
484
- // Once the first activation outcome is ambiguous, even a later 4xx
485
- // cannot prove that the original request did not commit.
486
- }
487
- }
488
- try {
489
- const observed = await controlPlane.getCliLoginConfirmation(credential, signal);
490
- if (observed.grant.id === expectedGrantId &&
491
- observed.grant.replacesGrantId === expectedPredecessorGrantId &&
492
- observed.grant.status === 'active') {
493
- return { kind: 'active' };
494
- }
495
- }
496
- catch {
497
- // Fall through to the explicit ambiguous outcome below.
498
- }
499
- return { kind: 'ambiguous', error: loginConfirmationAmbiguousError(registryAlias) };
500
- }
501
- async persistPreparedGrant(metadata, keyPair, refreshToken, previous, signal) {
502
- let metadataWriteAttempted = false;
503
- try {
504
- signal?.throwIfAborted();
505
- await this.keyStore.save(metadata.keyReference, keyPair);
506
- signal?.throwIfAborted();
507
- await this.credentials.set(metadata.refreshTokenReference, refreshToken);
508
- signal?.throwIfAborted();
509
- metadataWriteAttempted = true;
510
- await this.metadata.upsert(metadata);
511
- signal?.throwIfAborted();
512
- }
513
- catch (error) {
514
- const cleanup = [
515
- this.keyStore.delete(metadata.keyReference),
516
- this.credentials.delete(metadata.refreshTokenReference),
517
- ];
518
- let metadataRollbackIndex;
519
- if (metadataWriteAttempted) {
520
- metadataRollbackIndex = cleanup.length;
521
- cleanup.push(previous ? this.metadata.upsert(previous) : this.metadata.remove(metadata.issuer, metadata.registryId));
522
- }
523
- const cleanupResults = await Promise.allSettled(cleanup);
524
- if (metadataRollbackIndex !== undefined && cleanupResults[metadataRollbackIndex]?.status === 'rejected') {
525
- throw new LoginError('LOGIN_FAILED', 'Login failed, and UAPKG could not roll back the local login metadata safely. Check `uapkg whoami --json` before retrying.');
526
- }
527
- throw error;
528
- }
529
- }
530
- async rollbackPreparedGrant(metadata, previous) {
531
- const cleanupResults = await Promise.allSettled([
532
- this.keyStore.delete(metadata.keyReference),
533
- this.credentials.delete(metadata.refreshTokenReference),
534
- previous ? this.metadata.upsert(previous) : this.metadata.remove(metadata.issuer, metadata.registryId),
535
- ]);
536
- if (cleanupResults.some(({ status }) => status === 'rejected')) {
537
- throw new LoginError('LOGIN_FAILED', 'Login confirmation failed, and UAPKG could not roll back the local login safely. Check `uapkg whoami --json` before retrying.');
538
- }
539
- }
540
- async cleanupPreviousLocalCredentials(metadata, previous) {
541
- if (!previous)
542
- return [];
543
- if (previous.grantId === metadata.grantId ||
544
- (previous.keyReference === metadata.keyReference &&
545
- previous.refreshTokenReference === metadata.refreshTokenReference)) {
546
- return [];
547
- }
548
- const cleanupResults = await Promise.allSettled([
549
- this.keyStore.delete(previous.keyReference),
550
- this.credentials.delete(previous.refreshTokenReference),
551
- ]);
552
- const warnings = [];
553
- if (cleanupResults.some(({ status }) => status === 'rejected')) {
554
- warnings.push('The previous registry grant was replaced, but one or more old protected credential entries could not be removed. Remove the stale UAPKG entries from the operating-system credential store.');
555
- }
556
- return warnings;
557
- }
558
- async revokeToken(as, client, refreshToken, dpop) {
559
- const signer = signingDPoPHandle(dpop);
560
- await this.withDPoPNonceRetry(() => oauth.revocationRequest(as, client, oauth.None(), refreshToken, {
561
- additionalParameters: { token_type_hint: 'refresh_token' },
562
- signal: AbortSignal.timeout(OAUTH_BACKCHANNEL_TIMEOUT_MS),
563
- [oauth.customFetch]: async (url, options) => {
564
- const endpoint = new URL(url);
565
- const headers = new Headers(options.headers);
566
- await signer.addProof(endpoint, headers, 'POST');
567
- const response = await fetch(url, { ...options, headers });
568
- signer.cacheNonce(response, endpoint);
569
- return response;
570
- },
571
- }), (response) => oauth.processRevocationResponse(response));
572
- }
573
- async discover(issuer) {
574
- const discoveryUrl = oidcDiscoveryUrl(issuer);
575
- let response;
576
- try {
577
- response = await oauth.discoveryRequest(issuer, {
578
- algorithm: 'oidc',
579
- signal: AbortSignal.timeout(OAUTH_BACKCHANNEL_TIMEOUT_MS),
580
- });
581
- }
582
- catch {
583
- throw new Error(`Unable to retrieve OAuth metadata for build-pinned issuer "${issuer.href}" from discovery URL "${discoveryUrl.href}".`);
584
- }
585
- try {
586
- return await oauth.processDiscoveryResponse(issuer, response);
587
- }
588
- catch {
589
- throw new Error(`Invalid OAuth metadata for build-pinned issuer "${issuer.href}" from discovery URL "${discoveryUrl.href}" (HTTP ${response.status}).`);
590
- }
591
- }
592
- validateAuthorizationServer(as) {
593
- if (!as.authorization_endpoint || !as.token_endpoint || !as.pushed_authorization_request_endpoint) {
594
- throw new Error('The UAPKG authorization server is missing required authorization, token, or PAR endpoints.');
595
- }
596
- if (!as.revocation_endpoint) {
597
- throw new Error('The UAPKG authorization server is missing its grant revocation endpoint.');
598
- }
599
- if (as.code_challenge_methods_supported && !as.code_challenge_methods_supported.includes('S256')) {
600
- throw new Error('The UAPKG authorization server does not support PKCE S256.');
601
- }
602
- if (as.dpop_signing_alg_values_supported && !as.dpop_signing_alg_values_supported.includes('ES256')) {
603
- throw new Error('The UAPKG authorization server does not support ES256 DPoP proofs.');
604
- }
605
- }
606
- assertIssuerSupportsScopes(as, trust, requestedScopes) {
607
- const advertisedScopes = new Set(Array.isArray(as.scopes_supported) ? as.scopes_supported : []);
608
- const unsupportedScopes = requestedScopes.filter((scope) => !advertisedScopes.has(scope));
609
- if (unsupportedScopes.length > 0) {
610
- throw new OAuthScopeUnsupportedError(trust.alias, requestedScopes, unsupportedScopes);
611
- }
612
- }
613
- client() {
614
- return {
615
- client_id: UAPKG_CLI_CLIENT_ID,
616
- token_endpoint_auth_method: 'none',
617
- };
618
- }
619
- assertPinnedTrust(trust) {
620
- if (trust.issuer !== UAPKG_AUTHORIZATION_ISSUER ||
621
- trust.apiBaseUrl !== UAPKG_CONTROL_PLANE_API ||
622
- trust.resource !== registryAudience(trust.registryId)) {
623
- throw new Error('UAPKG v1 does not accept project-configured authorization issuers or API URLs.');
624
- }
625
- }
626
- assertInteractiveLogin() {
627
- if (this.isInteractiveLogin())
628
- return;
629
- throw new Error([
630
- 'Unable to complete interactive login on this machine.',
631
- '',
632
- 'Persistent login is not supported in headless environments.',
633
- '',
634
- 'For automated publishing, configure a GitHub Actions OIDC trusted publisher.',
635
- 'For interactive publishing, run `uapkg login` from a trusted, browser-capable workstation.',
636
- ].join('\n'));
637
- }
638
- async withDPoPNonceRetry(request, processResponse) {
639
- try {
640
- return await processResponse(await request());
641
- }
642
- catch (error) {
643
- if (!oauth.isDPoPNonceError(error))
644
- throw error;
645
- return processResponse(await request());
646
- }
647
- }
648
- accessTokenCacheKey(grant, scopes) {
649
- return `${grant.issuer}|${grant.registryId}|${grant.grantId}|${scopes.join(' ')}`;
650
- }
651
- async serializeGrantOperation(trust, operation) {
652
- const key = `${trust.issuer}|${trust.registryId}`;
653
- const previous = this.grantOperationTails.get(key) ?? Promise.resolve();
654
- const result = previous.then(() => this.grantLock.withLock(trust.issuer, trust.registryId, operation));
655
- const tail = result.then(() => undefined, () => undefined);
656
- this.grantOperationTails.set(key, tail);
657
- try {
658
- return await result;
659
- }
660
- finally {
661
- if (this.grantOperationTails.get(key) === tail) {
662
- this.grantOperationTails.delete(key);
663
- }
664
- }
665
- }
666
- }
22
+ var LoginError = class extends Error {
23
+ code;
24
+ oauthError;
25
+ constructor(code, message, oauthError) {
26
+ super(message);
27
+ this.code = code;
28
+ this.oauthError = oauthError;
29
+ this.name = "LoginError";
30
+ }
31
+ };
32
+ var AccountManager = class {
33
+ metadata;
34
+ credentials;
35
+ openBrowser;
36
+ isInteractiveLogin;
37
+ interactiveLoginTimeoutMs;
38
+ interactiveLoginFinalizationTimeoutMs;
39
+ keyStore;
40
+ accessTokenCache = /* @__PURE__ */ new Map();
41
+ grantOperationTails = /* @__PURE__ */ new Map();
42
+ grantLock;
43
+ constructor(metadata = new AuthMetadataStore(), credentials = new CredentialStore(), openBrowser = async (url) => {
44
+ const { default: open } = await import("open");
45
+ await open(url, { wait: false });
46
+ }, isInteractiveLogin = () => Boolean(process.stdin.isTTY && process.stdout.isTTY && !isCI), grantLock, interactiveLoginTimeoutMs = INTERACTIVE_LOGIN_TIMEOUT_MS, interactiveLoginFinalizationTimeoutMs = INTERACTIVE_LOGIN_FINALIZATION_TIMEOUT_MS) {
47
+ this.metadata = metadata;
48
+ this.credentials = credentials;
49
+ this.openBrowser = openBrowser;
50
+ this.isInteractiveLogin = isInteractiveLogin;
51
+ this.interactiveLoginTimeoutMs = interactiveLoginTimeoutMs;
52
+ this.interactiveLoginFinalizationTimeoutMs = interactiveLoginFinalizationTimeoutMs;
53
+ this.keyStore = new DPoPKeyStore(credentials);
54
+ const metadataPath = typeof metadata.path === "string" ? metadata.path : void 0;
55
+ this.grantLock = grantLock ?? new FileRegistryGrantLock(resolveAuthStoragePaths(metadataPath).locksDirectory);
56
+ }
57
+ async hasGrant(trust) {
58
+ return Boolean(await this.metadata.find(trust.issuer, trust.registryId));
59
+ }
60
+ invalidateAccessCredentials(trust) {
61
+ for (const key of this.accessTokenCache.keys()) if (key.startsWith(`${trust.issuer}|${trust.registryId}|`)) this.accessTokenCache.delete(key);
62
+ }
63
+ async login(trust, options = {}) {
64
+ this.assertPinnedTrust(trust);
65
+ this.assertInteractiveLogin();
66
+ await this.credentials.assertAvailable();
67
+ const previous = await this.metadata.find(trust.issuer, trust.registryId);
68
+ if (previous && !options.reauthorize) throw new Error(`This device already has a saved login for "${trust.alias}". Use \`uapkg login --registry ${trust.alias} --reauthorize\` to replace it.`);
69
+ emitLoginProgress(options.onProgress, {
70
+ type: "preparing",
71
+ registryAlias: trust.alias
72
+ });
73
+ const issuer = new URL(trust.issuer);
74
+ const as = await this.discover(issuer);
75
+ this.validateAuthorizationServer(as);
76
+ this.assertIssuerSupportsScopes(as, trust, UAPKG_CLI_SCOPES);
77
+ const client = this.client();
78
+ const keyPair = await this.keyStore.generate();
79
+ const dpop = oauth.DPoP(client, keyPair);
80
+ const publicKeyThumbprint = await dpop.calculateThumbprint();
81
+ const receiver = await LoopbackAuthorizationReceiver.listen(issuer);
82
+ let issuedRefreshToken;
83
+ let retainedIssuedGrant = false;
84
+ let preserveIssuedGrant = false;
85
+ let callbackReceipt;
86
+ let finalizationController;
87
+ let finalizationTimeout;
88
+ try {
89
+ const codeVerifier = oauth.generateRandomCodeVerifier();
90
+ const codeChallenge = await oauth.calculatePKCECodeChallenge(codeVerifier);
91
+ const state = oauth.generateRandomState();
92
+ const nonce = oauth.generateRandomNonce();
93
+ const requestedScopes = [
94
+ "openid",
95
+ "offline_access",
96
+ ...UAPKG_CLI_SCOPES
97
+ ];
98
+ const scope = requestedScopes.join(" ");
99
+ const deviceName = normalizeDeviceName(options.deviceName);
100
+ const parameters = new URLSearchParams({
101
+ client_id: client.client_id,
102
+ redirect_uri: receiver.redirectUri,
103
+ response_type: "code",
104
+ code_challenge: codeChallenge,
105
+ code_challenge_method: "S256",
106
+ state,
107
+ nonce,
108
+ scope,
109
+ resource: trust.resource,
110
+ dpop_jkt: publicKeyThumbprint,
111
+ registry_id: trust.registryId,
112
+ registry_source_fingerprint: trust.repositoryFingerprint,
113
+ device_name: deviceName,
114
+ max_age: "300"
115
+ });
116
+ if (requestedScopes.includes("offline_access")) parameters.set("prompt", "consent");
117
+ const expectedPredecessorGrantId = options.reauthorize && previous ? previous.grantId : null;
118
+ if (expectedPredecessorGrantId) parameters.set("replace_grant_id", expectedPredecessorGrantId);
119
+ const pushed = await this.withDPoPNonceRetry(() => oauth.pushedAuthorizationRequest(as, client, oauth.None(), parameters, {
120
+ DPoP: dpop,
121
+ signal: () => AbortSignal.timeout(OAUTH_BACKCHANNEL_TIMEOUT_MS)
122
+ }), (response) => oauth.processPushedAuthorizationResponse(as, client, response));
123
+ if (!as.authorization_endpoint) throw new Error("The authorization server did not advertise an authorization endpoint.");
124
+ const authorizationUrl = new URL(as.authorization_endpoint);
125
+ authorizationUrl.searchParams.set("client_id", client.client_id);
126
+ authorizationUrl.searchParams.set("request_uri", pushed.request_uri);
127
+ emitLoginProgress(options.onProgress, { type: "opening-browser" });
128
+ try {
129
+ await this.openBrowser(authorizationUrl.href);
130
+ } catch {
131
+ emitLoginProgress(options.onProgress, {
132
+ type: "browser-open-failed",
133
+ authorizationUrl: authorizationUrl.href
134
+ });
135
+ }
136
+ emitLoginProgress(options.onProgress, { type: "waiting-for-decision" });
137
+ callbackReceipt = await receiver.waitForCallback(this.interactiveLoginTimeoutMs, trust.alias);
138
+ finalizationController = new AbortController();
139
+ finalizationTimeout = setTimeout(() => {
140
+ finalizationController?.abort(loginFinalizationTimeoutError(trust.alias));
141
+ }, this.interactiveLoginFinalizationTimeoutMs);
142
+ const finalizationSignal = finalizationController.signal;
143
+ const callbackUrl = callbackReceipt.url;
144
+ if (callbackUrl.searchParams.get("iss") !== trust.issuer) throw new LoginError("LOGIN_AUTHORIZATION_RESPONSE_INVALID", "The browser authorization response came from an unexpected issuer. Run `uapkg login` again.");
145
+ let callbackParameters;
146
+ try {
147
+ callbackParameters = oauth.validateAuthResponse(as, client, callbackUrl, state);
148
+ } catch (error) {
149
+ throw authorizationResponseLoginError(error);
150
+ }
151
+ emitLoginProgress(options.onProgress, { type: "approval-received" });
152
+ const tokens = await this.withDPoPNonceRetry(() => oauth.authorizationCodeGrantRequest(as, client, oauth.None(), callbackParameters, receiver.redirectUri, codeVerifier, {
153
+ DPoP: dpop,
154
+ signal: finalizationSignal
155
+ }), (response) => oauth.processAuthorizationCodeResponse(as, client, response, {
156
+ expectedNonce: nonce,
157
+ maxAge: 300,
158
+ requireIdToken: true
159
+ }));
160
+ finalizationSignal.throwIfAborted();
161
+ if (tokens.token_type !== "dpop") throw new Error("The authorization server did not issue a DPoP-bound access token.");
162
+ if (!tokens.refresh_token) throw new Error("The authorization server did not issue a persistent registry grant.");
163
+ const refreshToken = tokens.refresh_token;
164
+ issuedRefreshToken = refreshToken;
165
+ const controlPlane = new ControlPlaneClient(trust.apiBaseUrl);
166
+ const issuedCredential = {
167
+ kind: "dpop",
168
+ accessToken: tokens.access_token,
169
+ dpop,
170
+ registryAlias: trust.alias,
171
+ requestedScopes: UAPKG_CLI_SCOPES
172
+ };
173
+ const self = await controlPlane.getCliLoginConfirmation(issuedCredential, finalizationSignal);
174
+ finalizationSignal.throwIfAborted();
175
+ if (self.grant.replacesGrantId !== expectedPredecessorGrantId) throw loginReplacementBindingError(trust.alias);
176
+ if (self.registry.id !== trust.registryId) throw new Error("The authorization server returned a registry grant for an unexpected registry.");
177
+ const missingScopes = UAPKG_CLI_SCOPES.filter((scope) => !self.grant.scopes.includes(scope));
178
+ if (missingScopes.length > 0) throw new Error(`The authorization server omitted required CLI capabilities: ${missingScopes.join(", ")}.`);
179
+ if (self.grant.status === "pending" && timestampFromIso(self.grant.activationExpiresAt) <= Math.floor(Date.now() / 1e3)) throw new LoginError("LOGIN_AUTHORIZATION_TIMEOUT", `Login approval expired before this device could confirm it. Run \`uapkg login --registry ${trust.alias}\` to try again.`);
180
+ const grantId = self.grant.id;
181
+ const keyReference = this.credentials.createReference("dpop-key", trust.issuer, trust.registryId, grantId);
182
+ const refreshTokenReference = this.credentials.createReference("grant", trust.issuer, trust.registryId, grantId);
183
+ const metadata = {
184
+ issuer: trust.issuer,
185
+ registryId: trust.registryId,
186
+ registryName: trust.registryName,
187
+ grantId,
188
+ clientId: client.client_id,
189
+ keyReference,
190
+ refreshTokenReference,
191
+ publicKeyThumbprint,
192
+ deviceName: self.grant.deviceName,
193
+ repositoryFingerprint: trust.repositoryFingerprint,
194
+ account: self.account,
195
+ createdAt: Math.floor(Date.now() / 1e3),
196
+ idleExpiresAt: timestampFromIso(self.grant.idleExpiresAt),
197
+ expiresAt: timestampFromIso(self.grant.absoluteExpiresAt)
198
+ };
199
+ let previousForCleanup;
200
+ await this.serializeGrantOperation(trust, async () => {
201
+ const currentPrevious = await this.metadata.find(trust.issuer, trust.registryId);
202
+ if (!isSameRegistryGrant(previous, currentPrevious)) {
203
+ if (options.reauthorize) throw loginReauthorizationConflictError(trust.alias);
204
+ throw new Error(`This device already has a saved login for "${trust.alias}". Use \`uapkg login --registry ${trust.alias} --reauthorize\` to replace it.`);
205
+ }
206
+ if (currentPrevious && !options.reauthorize) throw new Error(`This device already has a saved login for "${trust.alias}". Use \`uapkg login --registry ${trust.alias} --reauthorize\` to replace it.`);
207
+ emitLoginProgress(options.onProgress, { type: "saving-local-credentials" });
208
+ await this.persistPreparedGrant(metadata, keyPair, refreshToken, currentPrevious, finalizationSignal);
209
+ if (self.grant.status === "pending") {
210
+ emitLoginProgress(options.onProgress, { type: "confirming-with-service" });
211
+ const activation = await this.activatePreparedGrant(controlPlane, issuedCredential, metadata.grantId, expectedPredecessorGrantId, finalizationSignal, trust.alias);
212
+ if (activation.kind === "rejected") {
213
+ await this.rollbackPreparedGrant(metadata, currentPrevious);
214
+ throw activation.error;
215
+ }
216
+ if (activation.kind === "ambiguous") {
217
+ preserveIssuedGrant = true;
218
+ throw activation.error;
219
+ }
220
+ }
221
+ retainedIssuedGrant = true;
222
+ this.invalidateAccessCredentials(trust);
223
+ if (finalizationTimeout) {
224
+ clearTimeout(finalizationTimeout);
225
+ finalizationTimeout = void 0;
226
+ }
227
+ previousForCleanup = currentPrevious;
228
+ });
229
+ await callbackReceipt.complete("success");
230
+ let warnings = [];
231
+ if (previousForCleanup) try {
232
+ warnings = await this.serializeGrantOperation(trust, () => this.cleanupPreviousLocalCredentials(metadata, previousForCleanup));
233
+ } catch {
234
+ warnings = ["The new login is active, but UAPKG could not remove one or more old protected credential entries. Remove the stale UAPKG entries from the operating-system credential store."];
235
+ }
236
+ return {
237
+ grant: metadata,
238
+ warnings
239
+ };
240
+ } catch (error) {
241
+ if (finalizationTimeout) {
242
+ clearTimeout(finalizationTimeout);
243
+ finalizationTimeout = void 0;
244
+ }
245
+ const failure = error instanceof LoginError ? error : finalizationController?.signal.aborted && finalizationController.signal.reason instanceof LoginError ? finalizationController.signal.reason : error;
246
+ if (issuedRefreshToken && !retainedIssuedGrant && !preserveIssuedGrant) await this.revokeToken(as, client, issuedRefreshToken, dpop).catch(() => void 0);
247
+ const loginError = normalizeLoginError(failure);
248
+ if (callbackReceipt) {
249
+ const outcome = loginError.code === "LOGIN_ACCESS_DENIED" ? "denied" : "failed";
250
+ await callbackReceipt.complete(outcome).catch(() => void 0);
251
+ }
252
+ throw loginError;
253
+ } finally {
254
+ if (finalizationTimeout) clearTimeout(finalizationTimeout);
255
+ receiver.close();
256
+ }
257
+ }
258
+ async getAccessCredential(trust, scopes) {
259
+ this.assertPinnedTrust(trust);
260
+ const requestedScopes = [...new Set(scopes)].sort();
261
+ if (requestedScopes.length === 0 || requestedScopes.some((scope) => !isUAPKGCliScope(scope))) throw new Error("A control-plane operation requested an unsupported OAuth capability scope.");
262
+ const grant = await this.requireUsableGrant(trust);
263
+ const as = await this.discover(new URL(trust.issuer));
264
+ this.assertIssuerSupportsScopes(as, trust, requestedScopes);
265
+ const cacheKey = this.accessTokenCacheKey(grant, requestedScopes);
266
+ const cached = this.accessTokenCache.get(cacheKey);
267
+ if (cached && cached.expiresAt > Date.now() + 15e3) return {
268
+ grant,
269
+ credential: {
270
+ kind: "dpop",
271
+ accessToken: cached.token,
272
+ dpop: cached.dpop,
273
+ registryAlias: trust.alias,
274
+ requestedScopes
275
+ }
276
+ };
277
+ return this.serializeGrantOperation(trust, async () => {
278
+ const currentGrant = await this.requireUsableGrant(trust);
279
+ const currentCacheKey = this.accessTokenCacheKey(currentGrant, requestedScopes);
280
+ const refreshedCached = this.accessTokenCache.get(currentCacheKey);
281
+ if (refreshedCached && refreshedCached.expiresAt > Date.now() + 15e3) return {
282
+ grant: currentGrant,
283
+ credential: {
284
+ kind: "dpop",
285
+ accessToken: refreshedCached.token,
286
+ dpop: refreshedCached.dpop,
287
+ registryAlias: trust.alias,
288
+ requestedScopes
289
+ }
290
+ };
291
+ const pair = await this.keyStore.load(currentGrant.keyReference);
292
+ if (!pair) throw missingKeyError(trust);
293
+ const client = this.client();
294
+ const dpop = oauth.DPoP(client, pair);
295
+ if (await dpop.calculateThumbprint() !== currentGrant.publicKeyThumbprint) throw missingKeyError(trust);
296
+ const refreshToken = await this.credentials.get(currentGrant.refreshTokenReference);
297
+ if (!refreshToken) throw new Error(`The saved login for "${trust.alias}" is missing its protected registry grant. Run \`uapkg login --registry ${trust.alias}\` again.`);
298
+ let tokenResponse;
299
+ try {
300
+ tokenResponse = await this.withDPoPNonceRetry(() => oauth.refreshTokenGrantRequest(as, client, oauth.None(), refreshToken, {
301
+ DPoP: dpop,
302
+ additionalParameters: {
303
+ resource: trust.resource,
304
+ scope: requestedScopes.join(" ")
305
+ }
306
+ }), (response) => oauth.processRefreshTokenResponse(as, client, response));
307
+ } catch (error) {
308
+ if (error instanceof oauth.ResponseBodyError && error.error === "invalid_scope") {
309
+ const hintedScopes = parseUAPKGCliScopeString(error.cause.scope).filter((scope) => requestedScopes.includes(scope));
310
+ const missingScopes = hintedScopes.length > 0 ? hintedScopes : requestedScopes;
311
+ throw new OAuthScopeInsufficientError("The saved registry grant does not include every OAuth scope required by this operation.", trust.alias, requestedScopes, requestedScopes, missingScopes, 403, { cause: error });
312
+ }
313
+ if (error instanceof oauth.ResponseBodyError && (error.error === "invalid_grant" || error.error === "invalid_token")) throw new Error(`Your saved login for "${trust.alias}" is no longer valid. Run \`uapkg login --registry ${trust.alias} --reauthorize\` to authenticate again.`, { cause: error });
314
+ throw error;
315
+ }
316
+ if (tokenResponse.token_type !== "dpop") throw new Error("The authorization server returned an access token that is not DPoP-bound.");
317
+ if (tokenResponse.refresh_token && tokenResponse.refresh_token !== refreshToken) await this.credentials.set(currentGrant.refreshTokenReference, tokenResponse.refresh_token);
318
+ const expiresAt = Date.now() + Math.max(1, tokenResponse.expires_in ?? 300) * 1e3;
319
+ this.accessTokenCache.set(currentCacheKey, {
320
+ token: tokenResponse.access_token,
321
+ expiresAt,
322
+ dpop
323
+ });
324
+ return {
325
+ grant: currentGrant,
326
+ credential: {
327
+ kind: "dpop",
328
+ accessToken: tokenResponse.access_token,
329
+ dpop,
330
+ registryAlias: trust.alias,
331
+ requestedScopes
332
+ }
333
+ };
334
+ });
335
+ }
336
+ async logout(trust, localOnly = false) {
337
+ this.assertPinnedTrust(trust);
338
+ return this.serializeGrantOperation(trust, async () => {
339
+ const grant = await this.metadata.find(trust.issuer, trust.registryId);
340
+ if (!grant) return "not-logged-in";
341
+ if (!localOnly) try {
342
+ await this.revokeSavedGrant(grant);
343
+ } catch (error) {
344
+ throw new Error(`Unable to revoke the registry grant for "${trust.alias}". The local login was kept so you can retry. Use --local-only only if you accept that account-site revocation may still be required.`, { cause: error });
345
+ }
346
+ await Promise.all([this.keyStore.delete(grant.keyReference), this.credentials.delete(grant.refreshTokenReference)]);
347
+ await this.metadata.remove(grant.issuer, grant.registryId);
348
+ this.invalidateAccessCredentials(trust);
349
+ return "removed";
350
+ });
351
+ }
352
+ async requireUsableGrant(trust) {
353
+ const grant = await this.metadata.find(trust.issuer, trust.registryId);
354
+ if (!grant) throw new Error(`You are not logged in to "${trust.alias}". Run \`uapkg login --registry ${trust.alias}\`.`);
355
+ if (grant.repositoryFingerprint !== trust.repositoryFingerprint) throw new Error(`The configured Git source for "${trust.alias}" does not match the source authorized by the saved login. Run \`uapkg login --registry ${trust.alias} --reauthorize\`.`);
356
+ const now = Math.floor(Date.now() / 1e3);
357
+ if (grant.expiresAt && grant.expiresAt <= now) throw new Error(`Your saved login for "${trust.alias}" has expired. Run \`uapkg login --registry ${trust.alias}\` again.`);
358
+ return grant;
359
+ }
360
+ async revokeSavedGrant(grant) {
361
+ const refreshToken = await this.credentials.get(grant.refreshTokenReference);
362
+ if (!refreshToken) throw new Error("The registry grant cannot be revoked because its protected credential is missing.");
363
+ const pair = await this.keyStore.load(grant.keyReference);
364
+ if (!pair) throw new Error("The registry grant cannot be revoked because its DPoP key is missing.");
365
+ const dpop = oauth.DPoP(this.client(), pair);
366
+ if (await dpop.calculateThumbprint() !== grant.publicKeyThumbprint) throw new Error("The registry grant cannot be revoked because its DPoP key has changed.");
367
+ const as = await this.discover(new URL(grant.issuer));
368
+ await this.revokeToken(as, this.client(), refreshToken, dpop);
369
+ }
370
+ async activatePreparedGrant(controlPlane, credential, expectedGrantId, expectedPredecessorGrantId, signal, registryAlias) {
371
+ try {
372
+ const confirmed = await controlPlane.confirmCliLogin(credential, signal);
373
+ if (confirmed.id === expectedGrantId && confirmed.replacesGrantId === expectedPredecessorGrantId) return { kind: "active" };
374
+ return this.reconcilePreparedGrant(controlPlane, credential, expectedGrantId, expectedPredecessorGrantId, registryAlias);
375
+ } catch (error) {
376
+ if (isCliLoginReauthorizationConflict(error)) return {
377
+ kind: "rejected",
378
+ error: reauthorizationConflictLoginError(error)
379
+ };
380
+ if (isDefinitiveCliLoginConfirmationRejection(error)) return {
381
+ kind: "rejected",
382
+ error
383
+ };
384
+ return this.reconcilePreparedGrant(controlPlane, credential, expectedGrantId, expectedPredecessorGrantId, registryAlias);
385
+ }
386
+ }
387
+ async reconcilePreparedGrant(controlPlane, credential, expectedGrantId, expectedPredecessorGrantId, registryAlias) {
388
+ const signal = AbortSignal.timeout(CLI_LOGIN_RECONCILIATION_TIMEOUT_MS);
389
+ let retryActivation = true;
390
+ try {
391
+ const observed = await controlPlane.getCliLoginConfirmation(credential, signal);
392
+ if (observed.grant.id !== expectedGrantId || observed.grant.replacesGrantId !== expectedPredecessorGrantId) retryActivation = false;
393
+ else if (observed.grant.status === "active") return { kind: "active" };
394
+ } catch {}
395
+ if (retryActivation) try {
396
+ const confirmed = await controlPlane.confirmCliLogin(credential, signal);
397
+ if (confirmed.id === expectedGrantId && confirmed.replacesGrantId === expectedPredecessorGrantId) return { kind: "active" };
398
+ } catch {}
399
+ try {
400
+ const observed = await controlPlane.getCliLoginConfirmation(credential, signal);
401
+ if (observed.grant.id === expectedGrantId && observed.grant.replacesGrantId === expectedPredecessorGrantId && observed.grant.status === "active") return { kind: "active" };
402
+ } catch {}
403
+ return {
404
+ kind: "ambiguous",
405
+ error: loginConfirmationAmbiguousError(registryAlias)
406
+ };
407
+ }
408
+ async persistPreparedGrant(metadata, keyPair, refreshToken, previous, signal) {
409
+ let metadataWriteAttempted = false;
410
+ try {
411
+ signal?.throwIfAborted();
412
+ await this.keyStore.save(metadata.keyReference, keyPair);
413
+ signal?.throwIfAborted();
414
+ await this.credentials.set(metadata.refreshTokenReference, refreshToken);
415
+ signal?.throwIfAborted();
416
+ metadataWriteAttempted = true;
417
+ await this.metadata.upsert(metadata);
418
+ signal?.throwIfAborted();
419
+ } catch (error) {
420
+ const cleanup = [this.keyStore.delete(metadata.keyReference), this.credentials.delete(metadata.refreshTokenReference)];
421
+ let metadataRollbackIndex;
422
+ if (metadataWriteAttempted) {
423
+ metadataRollbackIndex = cleanup.length;
424
+ cleanup.push(previous ? this.metadata.upsert(previous) : this.metadata.remove(metadata.issuer, metadata.registryId));
425
+ }
426
+ const cleanupResults = await Promise.allSettled(cleanup);
427
+ if (metadataRollbackIndex !== void 0 && cleanupResults[metadataRollbackIndex]?.status === "rejected") throw new LoginError("LOGIN_FAILED", "Login failed, and UAPKG could not roll back the local login metadata safely. Check `uapkg whoami --json` before retrying.");
428
+ throw error;
429
+ }
430
+ }
431
+ async rollbackPreparedGrant(metadata, previous) {
432
+ if ((await Promise.allSettled([
433
+ this.keyStore.delete(metadata.keyReference),
434
+ this.credentials.delete(metadata.refreshTokenReference),
435
+ previous ? this.metadata.upsert(previous) : this.metadata.remove(metadata.issuer, metadata.registryId)
436
+ ])).some(({ status }) => status === "rejected")) throw new LoginError("LOGIN_FAILED", "Login confirmation failed, and UAPKG could not roll back the local login safely. Check `uapkg whoami --json` before retrying.");
437
+ }
438
+ async cleanupPreviousLocalCredentials(metadata, previous) {
439
+ if (!previous) return [];
440
+ if (previous.grantId === metadata.grantId || previous.keyReference === metadata.keyReference && previous.refreshTokenReference === metadata.refreshTokenReference) return [];
441
+ const cleanupResults = await Promise.allSettled([this.keyStore.delete(previous.keyReference), this.credentials.delete(previous.refreshTokenReference)]);
442
+ const warnings = [];
443
+ if (cleanupResults.some(({ status }) => status === "rejected")) warnings.push("The previous registry grant was replaced, but one or more old protected credential entries could not be removed. Remove the stale UAPKG entries from the operating-system credential store.");
444
+ return warnings;
445
+ }
446
+ async revokeToken(as, client, refreshToken, dpop) {
447
+ const signer = signingDPoPHandle(dpop);
448
+ await this.withDPoPNonceRetry(() => oauth.revocationRequest(as, client, oauth.None(), refreshToken, {
449
+ additionalParameters: { token_type_hint: "refresh_token" },
450
+ signal: AbortSignal.timeout(OAUTH_BACKCHANNEL_TIMEOUT_MS),
451
+ [oauth.customFetch]: async (url, options) => {
452
+ const endpoint = new URL(url);
453
+ const headers = new Headers(options.headers);
454
+ await signer.addProof(endpoint, headers, "POST");
455
+ const response = await fetch(url, {
456
+ ...options,
457
+ headers
458
+ });
459
+ signer.cacheNonce(response, endpoint);
460
+ return response;
461
+ }
462
+ }), (response) => oauth.processRevocationResponse(response));
463
+ }
464
+ async discover(issuer) {
465
+ const discoveryUrl = oidcDiscoveryUrl(issuer);
466
+ let response;
467
+ try {
468
+ response = await oauth.discoveryRequest(issuer, {
469
+ algorithm: "oidc",
470
+ signal: AbortSignal.timeout(OAUTH_BACKCHANNEL_TIMEOUT_MS)
471
+ });
472
+ } catch {
473
+ throw new Error(`Unable to retrieve OAuth metadata for build-pinned issuer "${issuer.href}" from discovery URL "${discoveryUrl.href}".`);
474
+ }
475
+ try {
476
+ return await oauth.processDiscoveryResponse(issuer, response);
477
+ } catch {
478
+ throw new Error(`Invalid OAuth metadata for build-pinned issuer "${issuer.href}" from discovery URL "${discoveryUrl.href}" (HTTP ${response.status}).`);
479
+ }
480
+ }
481
+ validateAuthorizationServer(as) {
482
+ if (!as.authorization_endpoint || !as.token_endpoint || !as.pushed_authorization_request_endpoint) throw new Error("The UAPKG authorization server is missing required authorization, token, or PAR endpoints.");
483
+ if (!as.revocation_endpoint) throw new Error("The UAPKG authorization server is missing its grant revocation endpoint.");
484
+ if (as.code_challenge_methods_supported && !as.code_challenge_methods_supported.includes("S256")) throw new Error("The UAPKG authorization server does not support PKCE S256.");
485
+ if (as.dpop_signing_alg_values_supported && !as.dpop_signing_alg_values_supported.includes("ES256")) throw new Error("The UAPKG authorization server does not support ES256 DPoP proofs.");
486
+ }
487
+ assertIssuerSupportsScopes(as, trust, requestedScopes) {
488
+ const advertisedScopes = new Set(Array.isArray(as.scopes_supported) ? as.scopes_supported : []);
489
+ const unsupportedScopes = requestedScopes.filter((scope) => !advertisedScopes.has(scope));
490
+ if (unsupportedScopes.length > 0) throw new OAuthScopeUnsupportedError(trust.alias, requestedScopes, unsupportedScopes);
491
+ }
492
+ client() {
493
+ return {
494
+ client_id: UAPKG_CLI_CLIENT_ID,
495
+ token_endpoint_auth_method: "none"
496
+ };
497
+ }
498
+ assertPinnedTrust(trust) {
499
+ if (trust.issuer !== UAPKG_AUTHORIZATION_ISSUER || trust.apiBaseUrl !== UAPKG_CONTROL_PLANE_API || trust.resource !== registryAudience(trust.registryId)) throw new Error("UAPKG v1 does not accept project-configured authorization issuers or API URLs.");
500
+ }
501
+ assertInteractiveLogin() {
502
+ if (this.isInteractiveLogin()) return;
503
+ throw new Error([
504
+ "Unable to complete interactive login on this machine.",
505
+ "",
506
+ "Persistent login is not supported in headless environments.",
507
+ "",
508
+ "For automated publishing, configure a GitHub Actions OIDC trusted publisher.",
509
+ "For interactive publishing, run `uapkg login` from a trusted, browser-capable workstation."
510
+ ].join("\n"));
511
+ }
512
+ async withDPoPNonceRetry(request, processResponse) {
513
+ try {
514
+ return await processResponse(await request());
515
+ } catch (error) {
516
+ if (!oauth.isDPoPNonceError(error)) throw error;
517
+ return processResponse(await request());
518
+ }
519
+ }
520
+ accessTokenCacheKey(grant, scopes) {
521
+ return `${grant.issuer}|${grant.registryId}|${grant.grantId}|${scopes.join(" ")}`;
522
+ }
523
+ async serializeGrantOperation(trust, operation) {
524
+ const key = `${trust.issuer}|${trust.registryId}`;
525
+ const result = (this.grantOperationTails.get(key) ?? Promise.resolve()).then(() => this.grantLock.withLock(trust.issuer, trust.registryId, operation));
526
+ const tail = result.then(() => void 0, () => void 0);
527
+ this.grantOperationTails.set(key, tail);
528
+ try {
529
+ return await result;
530
+ } finally {
531
+ if (this.grantOperationTails.get(key) === tail) this.grantOperationTails.delete(key);
532
+ }
533
+ }
534
+ };
667
535
  function signingDPoPHandle(handle) {
668
- const signer = handle;
669
- if (typeof signer.addProof !== 'function' || typeof signer.cacheNonce !== 'function') {
670
- throw new Error('The installed OAuth implementation cannot sender-constrain grant revocation.');
671
- }
672
- return signer;
673
- }
674
- export class LoopbackAuthorizationReceiver {
675
- server;
676
- callbackPath;
677
- expectedHost;
678
- completionUrl;
679
- redirectUri;
680
- callbackPromise;
681
- callbackResolve;
682
- callbackReject;
683
- receivedReceipt;
684
- timeout;
685
- state = 'listening';
686
- terminalError;
687
- pendingResponse;
688
- completion;
689
- constructor(server, callbackPath, expectedHost, completionUrl, redirectUri) {
690
- this.server = server;
691
- this.callbackPath = callbackPath;
692
- this.expectedHost = expectedHost;
693
- this.completionUrl = completionUrl;
694
- this.redirectUri = redirectUri;
695
- }
696
- static async listen(issuer) {
697
- const callbackPath = LOOPBACK_CALLBACK_PATH;
698
- let receiver;
699
- const server = createServer((request, response) => {
700
- if (!receiver) {
701
- response.writeHead(503).end();
702
- return;
703
- }
704
- receiver.receive(request, response);
705
- });
706
- await new Promise((resolve, reject) => {
707
- server.once('error', reject);
708
- server.listen(0, '127.0.0.1', () => resolve());
709
- });
710
- const address = server.address();
711
- if (!address || typeof address === 'string') {
712
- server.close();
713
- throw new Error('Unable to determine the interactive login callback address.');
714
- }
715
- const expectedHost = `127.0.0.1:${address.port}`;
716
- receiver = new LoopbackAuthorizationReceiver(server, callbackPath, expectedHost, new URL(ACCOUNT_COMPLETION_PATH, issuer.origin), `http://${expectedHost}${callbackPath}`);
717
- return receiver;
718
- }
719
- async waitForCallback(timeoutMs, registryAlias) {
720
- if (this.receivedReceipt)
721
- return this.receivedReceipt;
722
- if (this.state === 'closed') {
723
- throw this.terminalError ?? new LoginError('LOGIN_FAILED', 'The browser authorization listener was closed.');
724
- }
725
- if (this.callbackPromise)
726
- return this.callbackPromise;
727
- this.callbackPromise = new Promise((resolve, reject) => {
728
- this.callbackResolve = resolve;
729
- this.callbackReject = reject;
730
- this.timeout = setTimeout(() => {
731
- if (this.state !== 'listening')
732
- return;
733
- this.terminate(new LoginError('LOGIN_AUTHORIZATION_TIMEOUT', registryAlias
734
- ? `Login timed out while waiting for browser authorization. Run \`uapkg login --registry ${registryAlias}\` to try again.`
735
- : 'Login timed out while waiting for browser authorization. Run `uapkg login` to try again.'));
736
- }, timeoutMs);
737
- });
738
- return this.callbackPromise;
739
- }
740
- close() {
741
- this.terminate(new LoginError('LOGIN_FAILED', 'The browser authorization listener was closed.'));
742
- }
743
- receive(request, response) {
744
- if (this.state !== 'listening' ||
745
- request.method !== 'GET' ||
746
- request.headers.host !== this.expectedHost ||
747
- (request.url !== this.callbackPath && !request.url?.startsWith(`${this.callbackPath}?`))) {
748
- rejectLoopbackRequest(response);
749
- return;
750
- }
751
- let url;
752
- try {
753
- url = new URL(request.url, this.redirectUri);
754
- }
755
- catch {
756
- rejectLoopbackRequest(response);
757
- return;
758
- }
759
- if (url.origin !== new URL(this.redirectUri).origin || url.pathname !== this.callbackPath) {
760
- rejectLoopbackRequest(response);
761
- return;
762
- }
763
- this.state = 'callback-accepted';
764
- if (this.timeout)
765
- clearTimeout(this.timeout);
766
- this.timeout = undefined;
767
- this.pendingResponse = response;
768
- const receipt = {
769
- url,
770
- complete: (outcome) => this.complete(response, outcome),
771
- };
772
- this.receivedReceipt = receipt;
773
- this.callbackResolve?.(receipt);
774
- this.callbackResolve = undefined;
775
- this.callbackReject = undefined;
776
- }
777
- complete(response, outcome) {
778
- if (this.completion)
779
- return this.completion;
780
- this.completion = new Promise((resolve) => {
781
- let settled = false;
782
- const finish = () => {
783
- if (settled)
784
- return;
785
- settled = true;
786
- this.pendingResponse = undefined;
787
- this.close();
788
- resolve();
789
- };
790
- response.once('finish', finish);
791
- response.once('close', finish);
792
- response.once('error', finish);
793
- if (response.destroyed || response.writableEnded) {
794
- finish();
795
- return;
796
- }
797
- const location = new URL(this.completionUrl);
798
- location.hash = new URLSearchParams({ result: outcome }).toString();
799
- try {
800
- response
801
- .writeHead(303, {
802
- location: location.href,
803
- 'cache-control': 'no-store',
804
- 'referrer-policy': 'no-referrer',
805
- 'content-length': '0',
806
- 'x-content-type-options': 'nosniff',
807
- connection: 'close',
808
- })
809
- .end();
810
- }
811
- catch {
812
- finish();
813
- }
814
- });
815
- return this.completion;
816
- }
817
- terminate(error) {
818
- if (this.state === 'closed')
819
- return;
820
- this.state = 'closed';
821
- this.terminalError = error;
822
- if (this.timeout)
823
- clearTimeout(this.timeout);
824
- this.timeout = undefined;
825
- this.callbackReject?.(error);
826
- this.callbackResolve = undefined;
827
- this.callbackReject = undefined;
828
- if (this.pendingResponse && !this.pendingResponse.writableEnded) {
829
- this.pendingResponse.destroy();
830
- }
831
- this.pendingResponse = undefined;
832
- this.server.close();
833
- }
536
+ const signer = handle;
537
+ if (typeof signer.addProof !== "function" || typeof signer.cacheNonce !== "function") throw new Error("The installed OAuth implementation cannot sender-constrain grant revocation.");
538
+ return signer;
834
539
  }
540
+ var LoopbackAuthorizationReceiver = class LoopbackAuthorizationReceiver {
541
+ server;
542
+ callbackPath;
543
+ expectedHost;
544
+ completionUrl;
545
+ redirectUri;
546
+ callbackPromise;
547
+ callbackResolve;
548
+ callbackReject;
549
+ receivedReceipt;
550
+ timeout;
551
+ state = "listening";
552
+ terminalError;
553
+ pendingResponse;
554
+ completion;
555
+ constructor(server, callbackPath, expectedHost, completionUrl, redirectUri) {
556
+ this.server = server;
557
+ this.callbackPath = callbackPath;
558
+ this.expectedHost = expectedHost;
559
+ this.completionUrl = completionUrl;
560
+ this.redirectUri = redirectUri;
561
+ }
562
+ static async listen(issuer) {
563
+ const callbackPath = LOOPBACK_CALLBACK_PATH;
564
+ let receiver;
565
+ const server = createServer((request, response) => {
566
+ if (!receiver) {
567
+ response.writeHead(503).end();
568
+ return;
569
+ }
570
+ receiver.receive(request, response);
571
+ });
572
+ await new Promise((resolve, reject) => {
573
+ server.once("error", reject);
574
+ server.listen(0, "127.0.0.1", () => resolve());
575
+ });
576
+ const address = server.address();
577
+ if (!address || typeof address === "string") {
578
+ server.close();
579
+ throw new Error("Unable to determine the interactive login callback address.");
580
+ }
581
+ const expectedHost = `127.0.0.1:${address.port}`;
582
+ receiver = new LoopbackAuthorizationReceiver(server, callbackPath, expectedHost, new URL(ACCOUNT_COMPLETION_PATH, issuer.origin), `http://${expectedHost}${callbackPath}`);
583
+ return receiver;
584
+ }
585
+ async waitForCallback(timeoutMs, registryAlias) {
586
+ if (this.receivedReceipt) return this.receivedReceipt;
587
+ if (this.state === "closed") throw this.terminalError ?? new LoginError("LOGIN_FAILED", "The browser authorization listener was closed.");
588
+ if (this.callbackPromise) return this.callbackPromise;
589
+ this.callbackPromise = new Promise((resolve, reject) => {
590
+ this.callbackResolve = resolve;
591
+ this.callbackReject = reject;
592
+ this.timeout = setTimeout(() => {
593
+ if (this.state !== "listening") return;
594
+ this.terminate(new LoginError("LOGIN_AUTHORIZATION_TIMEOUT", registryAlias ? `Login timed out while waiting for browser authorization. Run \`uapkg login --registry ${registryAlias}\` to try again.` : "Login timed out while waiting for browser authorization. Run `uapkg login` to try again."));
595
+ }, timeoutMs);
596
+ });
597
+ return this.callbackPromise;
598
+ }
599
+ close() {
600
+ this.terminate(new LoginError("LOGIN_FAILED", "The browser authorization listener was closed."));
601
+ }
602
+ receive(request, response) {
603
+ if (this.state !== "listening" || request.method !== "GET" || request.headers.host !== this.expectedHost || request.url !== this.callbackPath && !request.url?.startsWith(`${this.callbackPath}?`)) {
604
+ rejectLoopbackRequest(response);
605
+ return;
606
+ }
607
+ let url;
608
+ try {
609
+ url = new URL(request.url, this.redirectUri);
610
+ } catch {
611
+ rejectLoopbackRequest(response);
612
+ return;
613
+ }
614
+ if (url.origin !== new URL(this.redirectUri).origin || url.pathname !== this.callbackPath) {
615
+ rejectLoopbackRequest(response);
616
+ return;
617
+ }
618
+ this.state = "callback-accepted";
619
+ if (this.timeout) clearTimeout(this.timeout);
620
+ this.timeout = void 0;
621
+ this.pendingResponse = response;
622
+ const receipt = {
623
+ url,
624
+ complete: (outcome) => this.complete(response, outcome)
625
+ };
626
+ this.receivedReceipt = receipt;
627
+ this.callbackResolve?.(receipt);
628
+ this.callbackResolve = void 0;
629
+ this.callbackReject = void 0;
630
+ }
631
+ complete(response, outcome) {
632
+ if (this.completion) return this.completion;
633
+ this.completion = new Promise((resolve) => {
634
+ let settled = false;
635
+ const finish = () => {
636
+ if (settled) return;
637
+ settled = true;
638
+ this.pendingResponse = void 0;
639
+ this.close();
640
+ resolve();
641
+ };
642
+ response.once("finish", finish);
643
+ response.once("close", finish);
644
+ response.once("error", finish);
645
+ if (response.destroyed || response.writableEnded) {
646
+ finish();
647
+ return;
648
+ }
649
+ const location = new URL(this.completionUrl);
650
+ location.hash = new URLSearchParams({ result: outcome }).toString();
651
+ try {
652
+ response.writeHead(303, {
653
+ location: location.href,
654
+ "cache-control": "no-store",
655
+ "referrer-policy": "no-referrer",
656
+ "content-length": "0",
657
+ "x-content-type-options": "nosniff",
658
+ connection: "close"
659
+ }).end();
660
+ } catch {
661
+ finish();
662
+ }
663
+ });
664
+ return this.completion;
665
+ }
666
+ terminate(error) {
667
+ if (this.state === "closed") return;
668
+ this.state = "closed";
669
+ this.terminalError = error;
670
+ if (this.timeout) clearTimeout(this.timeout);
671
+ this.timeout = void 0;
672
+ this.callbackReject?.(error);
673
+ this.callbackResolve = void 0;
674
+ this.callbackReject = void 0;
675
+ if (this.pendingResponse && !this.pendingResponse.writableEnded) this.pendingResponse.destroy();
676
+ this.pendingResponse = void 0;
677
+ this.server.close();
678
+ }
679
+ };
835
680
  function rejectLoopbackRequest(response) {
836
- response
837
- .writeHead(404, {
838
- 'cache-control': 'no-store',
839
- 'content-type': 'text/plain; charset=utf-8',
840
- 'x-content-type-options': 'nosniff',
841
- })
842
- .end('Not found.');
681
+ response.writeHead(404, {
682
+ "cache-control": "no-store",
683
+ "content-type": "text/plain; charset=utf-8",
684
+ "x-content-type-options": "nosniff"
685
+ }).end("Not found.");
843
686
  }
844
687
  function normalizeDeviceName(value) {
845
- const candidate = value?.trim() || hostname().trim() || 'UAPKG CLI';
846
- return candidate.slice(0, 80);
688
+ return (value?.trim() || hostname().trim() || "UAPKG CLI").slice(0, 80);
847
689
  }
848
690
  function oidcDiscoveryUrl(issuer) {
849
- const discoveryUrl = new URL(issuer);
850
- discoveryUrl.pathname = `${discoveryUrl.pathname.replace(/\/+$/, '')}/.well-known/openid-configuration`;
851
- return discoveryUrl;
691
+ const discoveryUrl = new URL(issuer);
692
+ discoveryUrl.pathname = `${discoveryUrl.pathname.replace(/\/+$/, "")}/.well-known/openid-configuration`;
693
+ return discoveryUrl;
852
694
  }
853
695
  function timestampFromIso(value) {
854
- const parsed = Date.parse(value);
855
- if (!Number.isFinite(parsed)) {
856
- throw new Error('The authorization server returned an invalid registry-grant expiration.');
857
- }
858
- return Math.floor(parsed / 1000);
696
+ const parsed = Date.parse(value);
697
+ if (!Number.isFinite(parsed)) throw new Error("The authorization server returned an invalid registry-grant expiration.");
698
+ return Math.floor(parsed / 1e3);
859
699
  }
860
700
  function missingKeyError(trust) {
861
- return new Error([
862
- `The saved login for "${trust.alias}" cannot be used because its device-bound signing key is missing or has changed.`,
863
- '',
864
- 'This can happen after copying configuration to another computer, resetting secure storage,',
865
- 'restoring an incomplete backup, or reinstalling the operating system.',
866
- '',
867
- `Run \`uapkg login --registry ${trust.alias} --reauthorize\` to authorize this device again.`,
868
- ].join('\n'));
701
+ return new Error([
702
+ `The saved login for "${trust.alias}" cannot be used because its device-bound signing key is missing or has changed.`,
703
+ "",
704
+ "This can happen after copying configuration to another computer, resetting secure storage,",
705
+ "restoring an incomplete backup, or reinstalling the operating system.",
706
+ "",
707
+ `Run \`uapkg login --registry ${trust.alias} --reauthorize\` to authorize this device again.`
708
+ ].join("\n"));
869
709
  }
870
710
  function loginFinalizationTimeoutError(registryAlias) {
871
- return new LoginError('LOGIN_AUTHORIZATION_TIMEOUT', `Login timed out while verifying and saving browser authorization. No new login was saved. Run \`uapkg login --registry ${registryAlias}\` to try again.`);
711
+ return new LoginError("LOGIN_AUTHORIZATION_TIMEOUT", `Login timed out while verifying and saving browser authorization. No new login was saved. Run \`uapkg login --registry ${registryAlias}\` to try again.`);
872
712
  }
873
713
  function loginConfirmationAmbiguousError(registryAlias) {
874
- return new LoginError('LOGIN_FAILED', [
875
- 'UAPKG could not determine whether the service activated this login.',
876
- 'The locally saved credentials were kept to avoid orphaning a possibly active grant.',
877
- `Run \`uapkg whoami --registry ${registryAlias}\` to check the login before retrying.`,
878
- ].join(' '));
714
+ return new LoginError("LOGIN_FAILED", [
715
+ "UAPKG could not determine whether the service activated this login.",
716
+ "The locally saved credentials were kept to avoid orphaning a possibly active grant.",
717
+ `Run \`uapkg whoami --registry ${registryAlias}\` to check the login before retrying.`
718
+ ].join(" "));
879
719
  }
880
720
  function loginReauthorizationConflictError(registryAlias) {
881
- return new LoginError('LOGIN_REAUTHORIZATION_CONFLICT', `The saved login for "${registryAlias}" changed while reauthorization was in progress. The newer local login was preserved. Run \`uapkg login --registry ${registryAlias} --reauthorize\` again if you still want to replace it.`);
721
+ return new LoginError("LOGIN_REAUTHORIZATION_CONFLICT", `The saved login for "${registryAlias}" changed while reauthorization was in progress. The newer local login was preserved. Run \`uapkg login --registry ${registryAlias} --reauthorize\` again if you still want to replace it.`);
882
722
  }
883
723
  function loginReplacementBindingError(registryAlias) {
884
- return new LoginError('LOGIN_REAUTHORIZATION_CONFLICT', `The authorization service did not bind this login to the expected saved grant for "${registryAlias}". No new local login was saved. Run \`uapkg login --registry ${registryAlias} --reauthorize\` to try again.`);
724
+ return new LoginError("LOGIN_REAUTHORIZATION_CONFLICT", `The authorization service did not bind this login to the expected saved grant for "${registryAlias}". No new local login was saved. Run \`uapkg login --registry ${registryAlias} --reauthorize\` to try again.`);
885
725
  }
886
726
  function reauthorizationConflictLoginError(error) {
887
- return new LoginError('LOGIN_REAUTHORIZATION_CONFLICT', error.message);
727
+ return new LoginError("LOGIN_REAUTHORIZATION_CONFLICT", error.message);
888
728
  }
889
729
  function isCliLoginReauthorizationConflict(error) {
890
- return error instanceof ControlPlaneError && error.code === 'CLI_LOGIN_REAUTHORIZATION_CONFLICT';
730
+ return error instanceof ControlPlaneError && error.code === "CLI_LOGIN_REAUTHORIZATION_CONFLICT";
891
731
  }
892
732
  function isSameRegistryGrant(expected, current) {
893
- if (!expected || !current)
894
- return expected === current;
895
- return (expected.grantId === current.grantId &&
896
- expected.keyReference === current.keyReference &&
897
- expected.refreshTokenReference === current.refreshTokenReference);
733
+ if (!expected || !current) return expected === current;
734
+ return expected.grantId === current.grantId && expected.keyReference === current.keyReference && expected.refreshTokenReference === current.refreshTokenReference;
898
735
  }
899
736
  function isDefinitiveCliLoginConfirmationRejection(error) {
900
- if (!(error instanceof ControlPlaneError) || error.status === undefined)
901
- return false;
902
- if (error.status < 400 || error.status >= 500)
903
- return false;
904
- return ![408, 409, 425, 429].includes(error.status);
737
+ if (!(error instanceof ControlPlaneError) || error.status === void 0) return false;
738
+ if (error.status < 400 || error.status >= 500) return false;
739
+ return ![
740
+ 408,
741
+ 409,
742
+ 425,
743
+ 429
744
+ ].includes(error.status);
905
745
  }
906
746
  function emitLoginProgress(onProgress, event) {
907
- try {
908
- onProgress?.(event);
909
- }
910
- catch {
911
- // Reporting must never change the authorization outcome.
912
- }
747
+ try {
748
+ onProgress?.(event);
749
+ } catch {}
913
750
  }
914
751
  function authorizationResponseLoginError(error) {
915
- if (error instanceof oauth.AuthorizationResponseError) {
916
- const oauthError = sanitizeOAuthErrorIdentifier(error.error);
917
- const description = sanitizeOAuthErrorDescription(error.error_description);
918
- if (oauthError === 'access_denied') {
919
- return new LoginError('LOGIN_ACCESS_DENIED', `Login denied: ${description ?? 'The user denied the registry grant.'} (access_denied)`, oauthError);
920
- }
921
- return new LoginError('LOGIN_OAUTH_ERROR', `Login failed: ${description ?? 'The authorization server rejected the request.'}${oauthError ? ` (${oauthError})` : ''}`, oauthError);
922
- }
923
- return new LoginError('LOGIN_AUTHORIZATION_RESPONSE_INVALID', 'The browser authorization response was invalid. Run `uapkg login` again.');
752
+ if (error instanceof oauth.AuthorizationResponseError) {
753
+ const oauthError = sanitizeOAuthErrorIdentifier(error.error);
754
+ const description = sanitizeOAuthErrorDescription(error.error_description);
755
+ if (oauthError === "access_denied") return new LoginError("LOGIN_ACCESS_DENIED", `Login denied: ${description ?? "The user denied the registry grant."} (access_denied)`, oauthError);
756
+ return new LoginError("LOGIN_OAUTH_ERROR", `Login failed: ${description ?? "The authorization server rejected the request."}${oauthError ? ` (${oauthError})` : ""}`, oauthError);
757
+ }
758
+ return new LoginError("LOGIN_AUTHORIZATION_RESPONSE_INVALID", "The browser authorization response was invalid. Run `uapkg login` again.");
924
759
  }
925
760
  function normalizeLoginError(error) {
926
- if (error instanceof LoginError)
927
- return error;
928
- if (isCliLoginReauthorizationConflict(error))
929
- return reauthorizationConflictLoginError(error);
930
- if (error instanceof oauth.AuthorizationResponseError)
931
- return authorizationResponseLoginError(error);
932
- if (error instanceof oauth.ResponseBodyError) {
933
- const oauthError = sanitizeOAuthErrorIdentifier(error.error);
934
- const description = sanitizeOAuthErrorDescription(error.error_description);
935
- return new LoginError('LOGIN_OAUTH_ERROR', `Login failed: ${description ?? 'The authorization server rejected the request.'}${oauthError ? ` (${oauthError})` : ''}`, oauthError);
936
- }
937
- return new LoginError('LOGIN_FAILED', describeControlPlaneError(error));
761
+ if (error instanceof LoginError) return error;
762
+ if (isCliLoginReauthorizationConflict(error)) return reauthorizationConflictLoginError(error);
763
+ if (error instanceof oauth.AuthorizationResponseError) return authorizationResponseLoginError(error);
764
+ if (error instanceof oauth.ResponseBodyError) {
765
+ const oauthError = sanitizeOAuthErrorIdentifier(error.error);
766
+ const description = sanitizeOAuthErrorDescription(error.error_description);
767
+ return new LoginError("LOGIN_OAUTH_ERROR", `Login failed: ${description ?? "The authorization server rejected the request."}${oauthError ? ` (${oauthError})` : ""}`, oauthError);
768
+ }
769
+ return new LoginError("LOGIN_FAILED", describeControlPlaneError(error));
938
770
  }
939
771
  function sanitizeOAuthErrorIdentifier(value) {
940
- return value && /^[a-z][a-z0-9._~-]{0,63}$/i.test(value) ? value : undefined;
772
+ return value && /^[a-z][a-z0-9._~-]{0,63}$/i.test(value) ? value : void 0;
941
773
  }
942
774
  function sanitizeOAuthErrorDescription(value) {
943
- if (!value)
944
- return undefined;
945
- const sanitized = Array.from(value, (character) => {
946
- const codePoint = character.codePointAt(0) ?? 0;
947
- return isUnsafeOAuthDescriptionCodePoint(codePoint) ? ' ' : character;
948
- })
949
- .join('')
950
- .replace(/\s+/g, ' ')
951
- .trim();
952
- return sanitized ? Array.from(sanitized).slice(0, 300).join('') : undefined;
775
+ if (!value) return void 0;
776
+ const sanitized = Array.from(value, (character) => {
777
+ return isUnsafeOAuthDescriptionCodePoint(character.codePointAt(0) ?? 0) ? " " : character;
778
+ }).join("").replace(/\s+/g, " ").trim();
779
+ return sanitized ? Array.from(sanitized).slice(0, 300).join("") : void 0;
953
780
  }
954
781
  function isUnsafeOAuthDescriptionCodePoint(codePoint) {
955
- return (codePoint <= 0x1f ||
956
- (codePoint >= 0x7f && codePoint <= 0x9f) ||
957
- codePoint === 0x061c ||
958
- codePoint === 0x200e ||
959
- codePoint === 0x200f ||
960
- (codePoint >= 0x202a && codePoint <= 0x202e) ||
961
- codePoint === 0x2028 ||
962
- codePoint === 0x2029 ||
963
- (codePoint >= 0x2066 && codePoint <= 0x2069));
782
+ return codePoint <= 31 || codePoint >= 127 && codePoint <= 159 || codePoint === 1564 || codePoint === 8206 || codePoint === 8207 || codePoint >= 8234 && codePoint <= 8238 || codePoint === 8232 || codePoint === 8233 || codePoint >= 8294 && codePoint <= 8297;
964
783
  }
965
- export function loginDiagnosticForError(error) {
966
- const loginError = normalizeLoginError(error);
967
- return {
968
- level: 'error',
969
- code: loginError.code,
970
- message: loginError.message,
971
- data: loginError.oauthError ? { oauthError: loginError.oauthError } : {},
972
- };
784
+ function loginDiagnosticForError(error) {
785
+ const loginError = normalizeLoginError(error);
786
+ return {
787
+ level: "error",
788
+ code: loginError.code,
789
+ message: loginError.message,
790
+ data: loginError.oauthError ? { oauthError: loginError.oauthError } : {}
791
+ };
973
792
  }
974
- export function controlPlaneDiagnosticForError(error, operation) {
975
- const serverCode = error instanceof ControlPlaneError && CONTROL_PLANE_SERVER_CODE_PATTERN.test(error.code) ? error.code : undefined;
976
- const status = error instanceof ControlPlaneError &&
977
- error.status !== undefined &&
978
- Number.isInteger(error.status) &&
979
- error.status >= 100 &&
980
- error.status <= 599
981
- ? error.status
982
- : undefined;
983
- const data = {
984
- operation,
985
- ...(serverCode === undefined ? {} : { serverCode }),
986
- ...(status === undefined ? {} : { status }),
987
- };
988
- return createControlPlaneCommandFailedDiagnostic(describeControlPlaneError(error), data);
793
+ function controlPlaneDiagnosticForError(error, operation) {
794
+ const serverCode = error instanceof ControlPlaneError && CONTROL_PLANE_SERVER_CODE_PATTERN.test(error.code) ? error.code : void 0;
795
+ const status = error instanceof ControlPlaneError && error.status !== void 0 && Number.isInteger(error.status) && error.status >= 100 && error.status <= 599 ? error.status : void 0;
796
+ const data = {
797
+ operation,
798
+ ...serverCode === void 0 ? {} : { serverCode },
799
+ ...status === void 0 ? {} : { status }
800
+ };
801
+ return createControlPlaneCommandFailedDiagnostic(describeControlPlaneError(error), data);
989
802
  }
990
- export function describeControlPlaneError(error) {
991
- if (error instanceof LoginError)
992
- return error.message;
993
- if (error instanceof OAuthScopeInsufficientError && error.missingScopes.length > 0) {
994
- const scopes = error.missingScopes.map((scope) => `\`${scope}\``).join(', ');
995
- const noun = error.missingScopes.length === 1 ? 'scope' : 'scopes';
996
- return `Missing authorization ${noun} ${scopes} for this action.\nRun \`uapkg login --registry ${error.registryAlias} --reauthorize\` to authorize the capabilities required by this CLI version.`;
997
- }
998
- if (error instanceof ControlPlaneError) {
999
- if (error.status === 401 && requiresSavedLoginRenewal(error.code)) {
1000
- return `${error.message}\n\nRun \`uapkg login\` to authenticate again.`;
1001
- }
1002
- return `${error.message} (${error.code})`;
1003
- }
1004
- return error instanceof Error ? error.message : String(error);
803
+ function describeControlPlaneError(error) {
804
+ if (error instanceof LoginError) return error.message;
805
+ if (error instanceof OAuthScopeInsufficientError && error.missingScopes.length > 0) {
806
+ const scopes = error.missingScopes.map((scope) => `\`${scope}\``).join(", ");
807
+ return `Missing authorization ${error.missingScopes.length === 1 ? "scope" : "scopes"} ${scopes} for this action.\nRun \`uapkg login --registry ${error.registryAlias} --reauthorize\` to authorize the capabilities required by this CLI version.`;
808
+ }
809
+ if (error instanceof ControlPlaneError) {
810
+ if (error.status === 401 && requiresSavedLoginRenewal(error.code)) return `${error.message}\n\nRun \`uapkg login\` to authenticate again.`;
811
+ return `${error.message} (${error.code})`;
812
+ }
813
+ return error instanceof Error ? error.message : String(error);
1005
814
  }
1006
815
  function requiresSavedLoginRenewal(code) {
1007
- const normalized = code.toUpperCase();
1008
- return (normalized.startsWith('DPOP_') ||
1009
- normalized.startsWith('REGISTRY_GRANT_') ||
1010
- normalized === 'CONTROL_PLANE_AUTHENTICATION_REQUIRED' ||
1011
- normalized === 'CLI_ACCESS_TOKEN_INVALID' ||
1012
- normalized === 'CLI_ACCESS_TOKEN_EXPIRED');
816
+ const normalized = code.toUpperCase();
817
+ return normalized.startsWith("DPOP_") || normalized.startsWith("REGISTRY_GRANT_") || normalized === "CONTROL_PLANE_AUTHENTICATION_REQUIRED" || normalized === "CLI_ACCESS_TOKEN_INVALID" || normalized === "CLI_ACCESS_TOKEN_EXPIRED";
1013
818
  }
819
+
820
+ //#endregion
821
+ export { AccountManager, LoginError, LoopbackAuthorizationReceiver, controlPlaneDiagnosticForError, describeControlPlaneError, loginDiagnosticForError };
1014
822
  //# sourceMappingURL=AccountManager.js.map