renovate 44.210.2 → 44.212.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/dist/config/options/index.js +1 -1
  2. package/dist/config/options/index.js.map +1 -1
  3. package/dist/config/utils.js +2 -1
  4. package/dist/config/utils.js.map +1 -1
  5. package/dist/config/validation-helpers/regex-glob-matchers.js.map +1 -1
  6. package/dist/config/validation-helpers/utils.js +5 -1
  7. package/dist/config/validation-helpers/utils.js.map +1 -1
  8. package/dist/config/validation.js +8 -2
  9. package/dist/config/validation.js.map +1 -1
  10. package/dist/config-validator.js +1 -1
  11. package/dist/config-validator.js.map +1 -1
  12. package/dist/data/monorepo.js +8 -0
  13. package/dist/global-config-option-defaults.generated.js +1 -1
  14. package/dist/global-config-option-defaults.generated.js.map +1 -1
  15. package/dist/instrumentation/index.js +3 -2
  16. package/dist/instrumentation/index.js.map +1 -1
  17. package/dist/logger/bunyan.js +3 -2
  18. package/dist/logger/bunyan.js.map +1 -1
  19. package/dist/logger/pretty-stdout.js +2 -1
  20. package/dist/logger/pretty-stdout.js.map +1 -1
  21. package/dist/modules/datasource/apk/index.js +2 -2
  22. package/dist/modules/datasource/apk/index.js.map +1 -1
  23. package/dist/modules/datasource/artifactory/index.js +2 -3
  24. package/dist/modules/datasource/artifactory/index.js.map +1 -1
  25. package/dist/modules/datasource/bazel/index.js +2 -1
  26. package/dist/modules/datasource/bazel/index.js.map +1 -1
  27. package/dist/modules/datasource/cdnjs/index.js +2 -1
  28. package/dist/modules/datasource/cdnjs/index.js.map +1 -1
  29. package/dist/modules/datasource/common.d.ts +9 -0
  30. package/dist/modules/datasource/common.js +20 -2
  31. package/dist/modules/datasource/common.js.map +1 -1
  32. package/dist/modules/datasource/conda/index.js +2 -1
  33. package/dist/modules/datasource/conda/index.js.map +1 -1
  34. package/dist/modules/datasource/crate/index.js +2 -1
  35. package/dist/modules/datasource/crate/index.js.map +1 -1
  36. package/dist/modules/datasource/dart-version/index.js +2 -1
  37. package/dist/modules/datasource/dart-version/index.js.map +1 -1
  38. package/dist/modules/datasource/datasource.js +2 -2
  39. package/dist/modules/datasource/datasource.js.map +1 -1
  40. package/dist/modules/datasource/deb/url.js +3 -1
  41. package/dist/modules/datasource/deb/url.js.map +1 -1
  42. package/dist/modules/datasource/devbox/index.js +2 -1
  43. package/dist/modules/datasource/devbox/index.js.map +1 -1
  44. package/dist/modules/datasource/docker/common.js +10 -8
  45. package/dist/modules/datasource/docker/common.js.map +1 -1
  46. package/dist/modules/datasource/docker/ecr.js +2 -1
  47. package/dist/modules/datasource/docker/ecr.js.map +1 -1
  48. package/dist/modules/datasource/docker/index.js +20 -17
  49. package/dist/modules/datasource/docker/index.js.map +1 -1
  50. package/dist/modules/datasource/gitea-tags/base.js +2 -3
  51. package/dist/modules/datasource/gitea-tags/base.js.map +1 -1
  52. package/dist/modules/datasource/github-tags/index.js +2 -1
  53. package/dist/modules/datasource/github-tags/index.js.map +1 -1
  54. package/dist/modules/datasource/gitlab-tags/index.js +2 -3
  55. package/dist/modules/datasource/gitlab-tags/index.js.map +1 -1
  56. package/dist/modules/datasource/go/base.js +1 -1
  57. package/dist/modules/datasource/go/base.js.map +1 -1
  58. package/dist/modules/datasource/go/common.js +8 -2
  59. package/dist/modules/datasource/go/common.js.map +1 -1
  60. package/dist/modules/datasource/go/env.js +2 -1
  61. package/dist/modules/datasource/go/env.js.map +1 -1
  62. package/dist/modules/datasource/go/releases-goproxy.js +7 -5
  63. package/dist/modules/datasource/go/releases-goproxy.js.map +1 -1
  64. package/dist/modules/datasource/helm/index.js +2 -1
  65. package/dist/modules/datasource/helm/index.js.map +1 -1
  66. package/dist/modules/datasource/hexpm-bob/index.js +2 -1
  67. package/dist/modules/datasource/hexpm-bob/index.js.map +1 -1
  68. package/dist/modules/datasource/index.js +4 -3
  69. package/dist/modules/datasource/index.js.map +1 -1
  70. package/dist/modules/datasource/java-version/adoptium.js +3 -2
  71. package/dist/modules/datasource/java-version/adoptium.js.map +1 -1
  72. package/dist/modules/datasource/java-version/graalvm.js +2 -1
  73. package/dist/modules/datasource/java-version/graalvm.js.map +1 -1
  74. package/dist/modules/datasource/maven/index.js.map +1 -1
  75. package/dist/modules/datasource/maven/util.js +7 -10
  76. package/dist/modules/datasource/maven/util.js.map +1 -1
  77. package/dist/modules/datasource/npm/npmrc.js +2 -2
  78. package/dist/modules/datasource/npm/npmrc.js.map +1 -1
  79. package/dist/modules/datasource/nuget/v3.js +3 -5
  80. package/dist/modules/datasource/nuget/v3.js.map +1 -1
  81. package/dist/modules/datasource/packagist/index.js +4 -5
  82. package/dist/modules/datasource/packagist/index.js.map +1 -1
  83. package/dist/modules/datasource/pod/index.js +4 -4
  84. package/dist/modules/datasource/pod/index.js.map +1 -1
  85. package/dist/modules/datasource/pypi/index.js +19 -11
  86. package/dist/modules/datasource/pypi/index.js.map +1 -1
  87. package/dist/modules/datasource/python-version/index.js +2 -3
  88. package/dist/modules/datasource/python-version/index.js.map +1 -1
  89. package/dist/modules/datasource/repology/index.js +4 -3
  90. package/dist/modules/datasource/repology/index.js.map +1 -1
  91. package/dist/modules/datasource/rpm/providers/common.js +3 -1
  92. package/dist/modules/datasource/rpm/providers/common.js.map +1 -1
  93. package/dist/modules/datasource/rubygems/index.js +2 -5
  94. package/dist/modules/datasource/rubygems/index.js.map +1 -1
  95. package/dist/modules/datasource/rubygems/versions-endpoint-cache.js +13 -18
  96. package/dist/modules/datasource/rubygems/versions-endpoint-cache.js.map +1 -1
  97. package/dist/modules/datasource/terraform-module/base.js +2 -1
  98. package/dist/modules/datasource/terraform-module/base.js.map +1 -1
  99. package/dist/modules/datasource/terraform-provider/index.js +2 -3
  100. package/dist/modules/datasource/terraform-provider/index.js.map +1 -1
  101. package/dist/modules/manager/apm/extract.js +44 -17
  102. package/dist/modules/manager/apm/extract.js.map +1 -1
  103. package/dist/modules/manager/apm/index.js +5 -1
  104. package/dist/modules/manager/apm/index.js.map +1 -1
  105. package/dist/modules/manager/bazel-module/parser/context.js +0 -1
  106. package/dist/modules/manager/bazel-module/parser/context.js.map +1 -1
  107. package/dist/modules/manager/bundler/host-rules.js +4 -1
  108. package/dist/modules/manager/bundler/host-rules.js.map +1 -1
  109. package/dist/modules/manager/composer/range.js +1 -1
  110. package/dist/modules/manager/composer/range.js.map +1 -1
  111. package/dist/modules/manager/custom/utils.js +3 -1
  112. package/dist/modules/manager/custom/utils.js.map +1 -1
  113. package/dist/modules/manager/devbox/schema.js +2 -1
  114. package/dist/modules/manager/devbox/schema.js.map +1 -1
  115. package/dist/modules/manager/dockerfile/extract.js +10 -2
  116. package/dist/modules/manager/dockerfile/extract.js.map +1 -1
  117. package/dist/modules/manager/fingerprint.generated.js +3 -3
  118. package/dist/modules/manager/fingerprint.generated.js.map +1 -1
  119. package/dist/modules/manager/github-actions/parse.js +2 -1
  120. package/dist/modules/manager/github-actions/parse.js.map +1 -1
  121. package/dist/modules/manager/gomod/artifacts.js +5 -2
  122. package/dist/modules/manager/gomod/artifacts.js.map +1 -1
  123. package/dist/modules/manager/gradle/artifacts.js +5 -2
  124. package/dist/modules/manager/gradle/artifacts.js.map +1 -1
  125. package/dist/modules/manager/gradle/utils.js +2 -1
  126. package/dist/modules/manager/gradle/utils.js.map +1 -1
  127. package/dist/modules/manager/gradle-wrapper/utils.js +9 -5
  128. package/dist/modules/manager/gradle-wrapper/utils.js.map +1 -1
  129. package/dist/modules/manager/helm-values/util.js +1 -1
  130. package/dist/modules/manager/helm-values/util.js.map +1 -1
  131. package/dist/modules/manager/helmfile/artifacts.js +1 -1
  132. package/dist/modules/manager/helmfile/artifacts.js.map +1 -1
  133. package/dist/modules/manager/helmv3/artifacts.js +1 -1
  134. package/dist/modules/manager/helmv3/artifacts.js.map +1 -1
  135. package/dist/modules/manager/maven/extract.js +5 -2
  136. package/dist/modules/manager/maven/extract.js.map +1 -1
  137. package/dist/modules/manager/maven-wrapper/artifacts.js +3 -2
  138. package/dist/modules/manager/maven-wrapper/artifacts.js.map +1 -1
  139. package/dist/modules/manager/mise/artifacts.js +2 -1
  140. package/dist/modules/manager/mise/artifacts.js.map +1 -1
  141. package/dist/modules/manager/mise/extract.js.map +1 -1
  142. package/dist/modules/manager/nix/extract.js +1 -2
  143. package/dist/modules/manager/nix/extract.js.map +1 -1
  144. package/dist/modules/manager/npm/artifacts.js +3 -1
  145. package/dist/modules/manager/npm/artifacts.js.map +1 -1
  146. package/dist/modules/manager/npm/extract/common/dependency.js +4 -1
  147. package/dist/modules/manager/npm/extract/common/dependency.js.map +1 -1
  148. package/dist/modules/manager/npm/extract/common/package-file.js +2 -1
  149. package/dist/modules/manager/npm/extract/common/package-file.js.map +1 -1
  150. package/dist/modules/manager/npm/extract/index.js.map +1 -1
  151. package/dist/modules/manager/npm/extract/post/locked-versions.js.map +1 -1
  152. package/dist/modules/manager/npm/npmrc.js +2 -1
  153. package/dist/modules/manager/npm/npmrc.js.map +1 -1
  154. package/dist/modules/manager/npm/post-update/index.js +2 -1
  155. package/dist/modules/manager/npm/post-update/index.js.map +1 -1
  156. package/dist/modules/manager/npm/post-update/npm.js +2 -3
  157. package/dist/modules/manager/npm/post-update/npm.js.map +1 -1
  158. package/dist/modules/manager/npm/post-update/yarn.js.map +1 -1
  159. package/dist/modules/manager/npm/schema.js +6 -2
  160. package/dist/modules/manager/npm/schema.js.map +1 -1
  161. package/dist/modules/manager/npm/update/dependency/index.js +3 -2
  162. package/dist/modules/manager/npm/update/dependency/index.js.map +1 -1
  163. package/dist/modules/manager/npm/update/locked-dependency/common/parent-version.js +6 -2
  164. package/dist/modules/manager/npm/update/locked-dependency/common/parent-version.js.map +1 -1
  165. package/dist/modules/manager/npm/update/locked-dependency/package-lock/get-locked.js +2 -1
  166. package/dist/modules/manager/npm/update/locked-dependency/package-lock/get-locked.js.map +1 -1
  167. package/dist/modules/manager/nuget/package-tree.js +2 -1
  168. package/dist/modules/manager/nuget/package-tree.js.map +1 -1
  169. package/dist/modules/manager/paket/update-locked.js +4 -1
  170. package/dist/modules/manager/paket/update-locked.js.map +1 -1
  171. package/dist/modules/manager/pipenv/extract.js +4 -1
  172. package/dist/modules/manager/pipenv/extract.js.map +1 -1
  173. package/dist/modules/platform/azure/azure-helper.js +2 -1
  174. package/dist/modules/platform/azure/azure-helper.js.map +1 -1
  175. package/dist/modules/platform/azure/index.js +10 -6
  176. package/dist/modules/platform/azure/index.js.map +1 -1
  177. package/dist/modules/platform/bitbucket/index.js +13 -6
  178. package/dist/modules/platform/bitbucket/index.js.map +1 -1
  179. package/dist/modules/platform/bitbucket-server/index.js +13 -9
  180. package/dist/modules/platform/bitbucket-server/index.js.map +1 -1
  181. package/dist/modules/platform/codecommit/index.js +2 -2
  182. package/dist/modules/platform/codecommit/index.js.map +1 -1
  183. package/dist/modules/platform/gerrit/client.js +4 -1
  184. package/dist/modules/platform/gerrit/client.js.map +1 -1
  185. package/dist/modules/platform/gerrit/index.js +3 -2
  186. package/dist/modules/platform/gerrit/index.js.map +1 -1
  187. package/dist/modules/platform/gitea/gitea-helper.js +5 -4
  188. package/dist/modules/platform/gitea/gitea-helper.js.map +1 -1
  189. package/dist/modules/platform/gitea/index.js +11 -4
  190. package/dist/modules/platform/gitea/index.js.map +1 -1
  191. package/dist/modules/platform/github/index.js +37 -24
  192. package/dist/modules/platform/github/index.js.map +1 -1
  193. package/dist/modules/platform/gitlab/index.js +16 -9
  194. package/dist/modules/platform/gitlab/index.js.map +1 -1
  195. package/dist/modules/platform/scm-manager/index.js +4 -1
  196. package/dist/modules/platform/scm-manager/index.js.map +1 -1
  197. package/dist/modules/platform/scm-manager/utils.js +2 -1
  198. package/dist/modules/platform/scm-manager/utils.js.map +1 -1
  199. package/dist/modules/versioning/cargo/index.js.map +1 -1
  200. package/dist/modules/versioning/composer/index.js +2 -1
  201. package/dist/modules/versioning/composer/index.js.map +1 -1
  202. package/dist/modules/versioning/conan/common.js +4 -1
  203. package/dist/modules/versioning/conan/common.js.map +1 -1
  204. package/dist/modules/versioning/debian/index.js +2 -1
  205. package/dist/modules/versioning/debian/index.js.map +1 -1
  206. package/dist/modules/versioning/gradle/compare.js +2 -1
  207. package/dist/modules/versioning/gradle/compare.js.map +1 -1
  208. package/dist/modules/versioning/hex/index.js +2 -1
  209. package/dist/modules/versioning/hex/index.js.map +1 -1
  210. package/dist/modules/versioning/julia/index.js.map +1 -1
  211. package/dist/modules/versioning/maven/compare.js +17 -7
  212. package/dist/modules/versioning/maven/compare.js.map +1 -1
  213. package/dist/modules/versioning/npm/index.js +2 -1
  214. package/dist/modules/versioning/npm/index.js.map +1 -1
  215. package/dist/modules/versioning/npm/range.js.map +1 -1
  216. package/dist/modules/versioning/paket/index.js +2 -1
  217. package/dist/modules/versioning/paket/index.js.map +1 -1
  218. package/dist/modules/versioning/paket/range.js +7 -3
  219. package/dist/modules/versioning/paket/range.js.map +1 -1
  220. package/dist/modules/versioning/pep440/index.js +2 -1
  221. package/dist/modules/versioning/pep440/index.js.map +1 -1
  222. package/dist/modules/versioning/poetry/index.js +2 -1
  223. package/dist/modules/versioning/poetry/index.js.map +1 -1
  224. package/dist/modules/versioning/regex/index.js +1 -1
  225. package/dist/modules/versioning/regex/index.js.map +1 -1
  226. package/dist/modules/versioning/rez/index.js +2 -1
  227. package/dist/modules/versioning/rez/index.js.map +1 -1
  228. package/dist/modules/versioning/vcpkg/index.js +2 -1
  229. package/dist/modules/versioning/vcpkg/index.js.map +1 -1
  230. package/dist/util/cache/package/impl/base.js +2 -1
  231. package/dist/util/cache/package/impl/base.js.map +1 -1
  232. package/dist/util/cache/package/with-cache.js +2 -1
  233. package/dist/util/cache/package/with-cache.js.map +1 -1
  234. package/dist/util/check-token.js +7 -4
  235. package/dist/util/check-token.js.map +1 -1
  236. package/dist/util/exec/utils.js +4 -1
  237. package/dist/util/exec/utils.js.map +1 -1
  238. package/dist/util/git/auth.js +5 -1
  239. package/dist/util/git/auth.js.map +1 -1
  240. package/dist/util/git/error.js.map +1 -1
  241. package/dist/util/git/private-key.js +5 -0
  242. package/dist/util/git/private-key.js.map +1 -1
  243. package/dist/util/host-rules.js +5 -3
  244. package/dist/util/host-rules.js.map +1 -1
  245. package/dist/util/http/cache/abstract-http-cache-provider.js +3 -2
  246. package/dist/util/http/cache/abstract-http-cache-provider.js.map +1 -1
  247. package/dist/util/http/cache/package-http-cache-provider.js +2 -1
  248. package/dist/util/http/cache/package-http-cache-provider.js.map +1 -1
  249. package/dist/util/http/github.js +15 -11
  250. package/dist/util/http/github.js.map +1 -1
  251. package/dist/util/http/gitlab.js +5 -4
  252. package/dist/util/http/gitlab.js.map +1 -1
  253. package/dist/util/http/http.js +2 -1
  254. package/dist/util/http/http.js.map +1 -1
  255. package/dist/util/http/jwt.js +2 -1
  256. package/dist/util/http/jwt.js.map +1 -1
  257. package/dist/util/http/retry-after.js +2 -1
  258. package/dist/util/http/retry-after.js.map +1 -1
  259. package/dist/util/http/status.js +95 -0
  260. package/dist/util/http/status.js.map +1 -0
  261. package/dist/util/merge-confidence/index.js +3 -2
  262. package/dist/util/merge-confidence/index.js.map +1 -1
  263. package/dist/util/package-rules/current-version.js +4 -1
  264. package/dist/util/package-rules/current-version.js.map +1 -1
  265. package/dist/util/package-rules/index.js +7 -3
  266. package/dist/util/package-rules/index.js.map +1 -1
  267. package/dist/util/schema-utils/index.js +5 -0
  268. package/dist/util/schema-utils/index.js.map +1 -1
  269. package/dist/workers/global/config/parse/host-rules-from-env.js +2 -1
  270. package/dist/workers/global/config/parse/host-rules-from-env.js.map +1 -1
  271. package/dist/workers/repository/common.js +4 -1
  272. package/dist/workers/repository/common.js.map +1 -1
  273. package/dist/workers/repository/config-migration/branch/index.js +2 -1
  274. package/dist/workers/repository/config-migration/branch/index.js.map +1 -1
  275. package/dist/workers/repository/dependency-dashboard.js +6 -2
  276. package/dist/workers/repository/dependency-dashboard.js.map +1 -1
  277. package/dist/workers/repository/finalize/repository-statistics.js +4 -1
  278. package/dist/workers/repository/finalize/repository-statistics.js.map +1 -1
  279. package/dist/workers/repository/init/merge.js +13 -3
  280. package/dist/workers/repository/init/merge.js.map +1 -1
  281. package/dist/workers/repository/onboarding/branch/check.js +2 -1
  282. package/dist/workers/repository/onboarding/branch/check.js.map +1 -1
  283. package/dist/workers/repository/onboarding/pr/pr-list.js +4 -2
  284. package/dist/workers/repository/onboarding/pr/pr-list.js.map +1 -1
  285. package/dist/workers/repository/process/extract-update.js +4 -1
  286. package/dist/workers/repository/process/extract-update.js.map +1 -1
  287. package/dist/workers/repository/process/lookup/digest.js +2 -1
  288. package/dist/workers/repository/process/lookup/digest.js.map +1 -1
  289. package/dist/workers/repository/process/lookup/generate.js +1 -1
  290. package/dist/workers/repository/process/lookup/generate.js.map +1 -1
  291. package/dist/workers/repository/process/lookup/index.js +4 -1
  292. package/dist/workers/repository/process/lookup/index.js.map +1 -1
  293. package/dist/workers/repository/process/lookup/utils.js +7 -1
  294. package/dist/workers/repository/process/lookup/utils.js.map +1 -1
  295. package/dist/workers/repository/process/vulnerabilities.js +10 -3
  296. package/dist/workers/repository/process/vulnerabilities.js.map +1 -1
  297. package/dist/workers/repository/reconfigure/index.js +2 -1
  298. package/dist/workers/repository/reconfigure/index.js.map +1 -1
  299. package/dist/workers/repository/update/branch/auto-replace.js +6 -2
  300. package/dist/workers/repository/update/branch/auto-replace.js.map +1 -1
  301. package/dist/workers/repository/update/branch/errors.js +2 -1
  302. package/dist/workers/repository/update/branch/errors.js.map +1 -1
  303. package/dist/workers/repository/update/branch/execute-post-upgrade-commands.js +2 -2
  304. package/dist/workers/repository/update/branch/execute-post-upgrade-commands.js.map +1 -1
  305. package/dist/workers/repository/update/branch/get-updated.js +1 -2
  306. package/dist/workers/repository/update/branch/get-updated.js.map +1 -1
  307. package/dist/workers/repository/update/branch/index.js +2 -1
  308. package/dist/workers/repository/update/branch/index.js.map +1 -1
  309. package/dist/workers/repository/update/branch/status-checks.js +2 -1
  310. package/dist/workers/repository/update/branch/status-checks.js.map +1 -1
  311. package/dist/workers/repository/update/pr/body/index.js.map +1 -1
  312. package/dist/workers/repository/update/pr/changelog/release-notes.js +6 -3
  313. package/dist/workers/repository/update/pr/changelog/release-notes.js.map +1 -1
  314. package/dist/workers/repository/update/pr/index.js +7 -3
  315. package/dist/workers/repository/update/pr/index.js.map +1 -1
  316. package/dist/workers/repository/updates/generate.js +6 -3
  317. package/dist/workers/repository/updates/generate.js.map +1 -1
  318. package/package.json +2 -2
  319. package/renovate-schema.json +2 -2
@@ -70,11 +70,29 @@ function applyVersionCompatibility(releaseResult, versionCompatibility, currentC
70
70
  });
71
71
  return releaseResult;
72
72
  }
73
+ /**
74
+ * Extracts a version string from regex named capture groups.
75
+ *
76
+ * Supports two modes:
77
+ * 1. A `version` group: returned as-is.
78
+ * 2. SemVer-part groups (`major`, `minor`, `patch`, `prerelease`, `build`):
79
+ * assembled into `MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]`.
80
+ */
81
+ function extractVersionFromGroups(groups) {
82
+ if (!groups) return;
83
+ if (groups.version) return groups.version;
84
+ if (!groups.major) return;
85
+ let version = `${groups.major}.${groups.minor ?? "0"}.${groups.patch ?? "0"}`;
86
+ if (groups.prerelease) version += `-${groups.prerelease}`;
87
+ if (groups.build) version += `+${groups.build}`;
88
+ return version;
89
+ }
73
90
  function applyExtractVersion(releaseResult, extractVersion) {
74
91
  if (!extractVersion) return releaseResult;
75
92
  const extractVersionRegEx = regEx(extractVersion);
76
93
  releaseResult.releases = filterMap(releaseResult.releases, (release) => {
77
- const version = extractVersionRegEx.exec(release.version)?.groups?.version;
94
+ const groups = extractVersionRegEx.exec(release.version)?.groups;
95
+ const version = extractVersionFromGroups(groups);
78
96
  if (!version) return null;
79
97
  release.versionOrig = release.version;
80
98
  release.version = version;
@@ -256,6 +274,6 @@ function applyConstraintsFiltering(releaseResult, config) {
256
274
  }
257
275
  return releaseResult;
258
276
  }
259
- export { applyConstraintsFiltering, applyExtractVersion, applyVersionCompatibility, filterValidVersions, getDatasourceFor, getDatasourceHostType, getDefaultVersioning, isGetPkgReleasesConfig, sortAndRemoveDuplicates };
277
+ export { applyConstraintsFiltering, applyExtractVersion, applyVersionCompatibility, extractVersionFromGroups, filterValidVersions, getDatasourceFor, getDatasourceHostType, getDefaultVersioning, isGetPkgReleasesConfig, sortAndRemoveDuplicates };
260
278
 
261
279
  //# sourceMappingURL=common.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"common.js","names":["datasources","allVersioning.get"],"sources":["../../../lib/modules/datasource/common.ts"],"sourcesContent":["import {\n isNonEmptyArray,\n isNonEmptyStringAndNotWhitespace,\n} from '@sindresorhus/is';\nimport { logger } from '../../logger/index.ts';\nimport {\n type ConstraintName,\n isAdditionalConstraintName,\n} from '../../util/exec/types.ts';\nimport { filterMap } from '../../util/filter-map.ts';\nimport { regEx } from '../../util/regex.ts';\nimport * as allVersioning from '../versioning/index.ts';\nimport { defaultVersioning } from '../versioning/index.ts';\nimport datasources from './api.ts';\nimport { CustomDatasource } from './custom/index.ts';\nimport type {\n DatasourceApi,\n GetPkgReleasesConfig,\n ReleaseResult,\n} from './types.ts';\n\nexport function getDatasourceFor(datasource: string): DatasourceApi | null {\n if (datasource?.startsWith('custom.')) {\n return getDatasourceFor(CustomDatasource.id);\n }\n return datasources.get(datasource) ?? null;\n}\n\n/**\n * The host types of the datasources whose requests use another host type than their id.\n */\nconst datasourceHostTypes: Record<string, string> = {\n 'sbt-package': 'sbt',\n 'sbt-plugin': 'sbt',\n};\n\n/**\n * Returns the host type the requests of `datasource` use, such as `custom` for `custom.<name>`, or `null` when there is no such datasource.\n */\nexport function getDatasourceHostType(datasource: string): string | null {\n const id = getDatasourceFor(datasource)?.id;\n if (!id) {\n return null;\n }\n return datasourceHostTypes[id] ?? id;\n}\n\nexport function getDefaultVersioning(\n datasourceName: string | undefined,\n): string {\n if (!datasourceName) {\n return defaultVersioning.id;\n }\n\n const datasource = getDatasourceFor(datasourceName);\n\n if (!datasource) {\n logger.warn({ datasourceName }, 'Missing datasource!');\n return defaultVersioning.id;\n }\n\n if (!datasource.defaultVersioning) {\n return defaultVersioning.id;\n }\n\n return datasource.defaultVersioning;\n}\n\nexport function isGetPkgReleasesConfig(\n input: unknown,\n): input is GetPkgReleasesConfig {\n return (\n isNonEmptyStringAndNotWhitespace(\n (input as GetPkgReleasesConfig).datasource,\n ) &&\n isNonEmptyStringAndNotWhitespace(\n (input as GetPkgReleasesConfig).packageName,\n )\n );\n}\n\nexport function applyVersionCompatibility(\n releaseResult: ReleaseResult,\n versionCompatibility: string | undefined,\n currentCompatibility: string | undefined,\n): ReleaseResult {\n if (!versionCompatibility) {\n return releaseResult;\n }\n\n const versionCompatibilityRegEx = regEx(versionCompatibility);\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n const regexResult = versionCompatibilityRegEx.exec(release.version);\n if (!regexResult?.groups?.version) {\n logger.trace(\n { releaseVersion: release.version, versionCompatibility },\n 'versionCompatibility: Does not match regex',\n );\n return null;\n }\n if (regexResult?.groups?.compatibility !== currentCompatibility) {\n logger.trace(\n { releaseVersion: release.version, versionCompatibility },\n 'versionCompatibility: Does not match compatibility',\n );\n return null;\n }\n logger.trace(\n {\n releaseVersion: release.version,\n versionCompatibility,\n version: regexResult.groups.version,\n compatibility: regexResult.groups.compatibility,\n },\n 'versionCompatibility: matches',\n );\n release.versionOrig ??= release.version;\n release.version = regexResult.groups.version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function applyExtractVersion(\n releaseResult: ReleaseResult,\n extractVersion: string | undefined,\n): ReleaseResult {\n if (!extractVersion) {\n return releaseResult;\n }\n\n const extractVersionRegEx = regEx(extractVersion);\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n const version = extractVersionRegEx.exec(release.version)?.groups?.version;\n if (!version) {\n return null;\n }\n\n release.versionOrig = release.version;\n release.version = version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function filterValidVersions<\n Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n releaseResult.releases = filterMap(releaseResult.releases, (release) =>\n versioning.isVersion(release.version) ? release : null,\n );\n\n return releaseResult;\n}\n\nexport function sortAndRemoveDuplicates<\n Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n releaseResult.releases = releaseResult.releases.sort((a, b) =>\n versioning.sortVersions(a.version, b.version),\n );\n\n // Once releases are sorted, deduplication is straightforward and efficient\n let previousVersion: string | null = null;\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n if (previousVersion === release.version) {\n return null;\n }\n previousVersion = release.version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function applyConstraintsFiltering<\n Config extends Pick<\n GetPkgReleasesConfig,\n | 'constraintsFiltering'\n | 'constraintsVersioning'\n | 'versioning'\n | 'datasource'\n | 'constraints'\n | 'packageName'\n >,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n if (config?.constraintsFiltering !== 'strict') {\n for (const release of releaseResult.releases) {\n delete release.constraints;\n }\n\n return releaseResult;\n }\n\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n\n const configConstraints = config.constraints;\n const filteredReleases: string[] = [];\n const startingLength = releaseResult.releases.length;\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n logger.trace(\n {\n release,\n versioning: versioningName,\n },\n `applyConstraintsFiltering(${release.version})`,\n );\n const releaseConstraints = release.constraints;\n delete release.constraints;\n\n logger.trace(\n {\n release,\n versioning: versioningName,\n configConstraints: configConstraints ?? 'undefined',\n releaseConstraints: releaseConstraints ?? 'undefined',\n },\n `applyConstraintsFiltering(${release.version}): checking constraints`,\n );\n if (!configConstraints || !releaseConstraints) {\n return release;\n }\n\n for (const [name, configConstraint] of Object.entries(\n configConstraints,\n ) as [ConstraintName, string][]) {\n let constraintVersioningName = versioningName;\n if (\n isAdditionalConstraintName(name) &&\n config.constraintsVersioning?.[name]\n ) {\n const val = config.constraintsVersioning[name];\n logger.once.debug(\n { packageName: config.packageName, release },\n `applyConstraintsFiltering(${config.packageName}, ${name}): overriding constraintsVersioning from ${constraintVersioningName} to ${val}`,\n );\n logger.trace(\n { packageName: config.packageName, release },\n `applyConstraintsFiltering(${release.version}): overriding constraintsVersioning from ${constraintVersioningName} to ${val}`,\n );\n constraintVersioningName = val;\n }\n const constraintVersioning = allVersioning.get(constraintVersioningName);\n\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n constraintName: name,\n constraint: configConstraint,\n },\n `applyConstraintsFiltering(${release.version}) for constraint ${name}`,\n );\n\n const isValid = constraintVersioning.isValid(configConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): versioning.isValid(${configConstraint})=${isValid}`,\n );\n if (!isValid) {\n logger.once.warn(\n {\n packageName: config.packageName,\n constraint: configConstraint,\n versioning: constraintVersioningName,\n },\n 'Invalid constraint used with strict constraintsFiltering',\n );\n continue;\n }\n\n const constraint = releaseConstraints[name];\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): releaseConstraints[${name}]=${JSON.stringify(constraint)}`,\n );\n if (!isNonEmptyArray(constraint)) {\n // A release with no constraints is OK\n continue;\n }\n\n let satisfiesConstraints = false;\n for (const releaseConstraint of constraint) {\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): releaseConstraint=${releaseConstraint}`,\n );\n if (!releaseConstraint) {\n satisfiesConstraints = true;\n logger.once.debug(\n {\n packageName: config.packageName,\n versioning: constraintVersioningName,\n constraint: releaseConstraint,\n },\n 'Undefined release constraint',\n );\n break;\n }\n\n const isValidConstraintVersion =\n constraintVersioning.isValid(releaseConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): constraintVersioning.isValid(${releaseConstraint})=${isValidConstraintVersion}`,\n );\n if (!isValidConstraintVersion) {\n logger.once.debug(\n {\n packageName: config.packageName,\n versioning: constraintVersioningName,\n constraint: releaseConstraint,\n },\n 'Invalid release constraint',\n );\n break;\n }\n\n const isEqual = configConstraint === releaseConstraint;\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): ${configConstraint} === ${releaseConstraint}=${isEqual}`,\n );\n if (isEqual) {\n satisfiesConstraints = true;\n break;\n }\n\n const isSubset = constraintVersioning.subset?.(\n configConstraint,\n releaseConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.subset?.(${configConstraint}, ${releaseConstraint})=${isSubset}`,\n );\n if (isSubset) {\n satisfiesConstraints = true;\n break;\n }\n\n const doesMatchConfig = constraintVersioning.matches(\n configConstraint,\n releaseConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.matches(${configConstraint}, ${releaseConstraint})=${doesMatchConfig}`,\n );\n const doesMatchRelease = constraintVersioning.matches(\n releaseConstraint,\n configConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.matches(${releaseConstraint}, ${configConstraint})=${doesMatchRelease}`,\n );\n if (doesMatchConfig || doesMatchRelease) {\n satisfiesConstraints = true;\n break;\n }\n }\n\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): satisfiesConstraints=${satisfiesConstraints}`,\n );\n if (!satisfiesConstraints) {\n filteredReleases.push(release.version);\n return null;\n }\n }\n\n return release;\n });\n\n if (filteredReleases.length) {\n const count = filteredReleases.length;\n const packageName = config.packageName;\n const releases = filteredReleases.join(', ');\n logger.debug(\n {\n datasource: config.datasource,\n packageName: config.packageName,\n },\n `Filtered out ${count} non-matching releases out of ${startingLength} total for ${packageName} due to constraintsFiltering=strict: ${releases}`,\n );\n }\n\n return releaseResult;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"common.js","names":["datasources","allVersioning.get"],"sources":["../../../lib/modules/datasource/common.ts"],"sourcesContent":["import {\n isNonEmptyArray,\n isNonEmptyStringAndNotWhitespace,\n} from '@sindresorhus/is';\nimport { logger } from '../../logger/index.ts';\nimport {\n type ConstraintName,\n isAdditionalConstraintName,\n} from '../../util/exec/types.ts';\nimport { filterMap } from '../../util/filter-map.ts';\nimport { regEx } from '../../util/regex.ts';\nimport * as allVersioning from '../versioning/index.ts';\nimport { defaultVersioning } from '../versioning/index.ts';\nimport datasources from './api.ts';\nimport { CustomDatasource } from './custom/index.ts';\nimport type {\n DatasourceApi,\n GetPkgReleasesConfig,\n ReleaseResult,\n} from './types.ts';\n\nexport function getDatasourceFor(datasource: string): DatasourceApi | null {\n if (datasource?.startsWith('custom.')) {\n return getDatasourceFor(CustomDatasource.id);\n }\n return datasources.get(datasource) ?? null;\n}\n\n/**\n * The host types of the datasources whose requests use another host type than their id.\n */\nconst datasourceHostTypes: Record<string, string> = {\n 'sbt-package': 'sbt',\n 'sbt-plugin': 'sbt',\n};\n\n/**\n * Returns the host type the requests of `datasource` use, such as `custom` for `custom.<name>`, or `null` when there is no such datasource.\n */\nexport function getDatasourceHostType(datasource: string): string | null {\n const id = getDatasourceFor(datasource)?.id;\n if (!id) {\n return null;\n }\n return datasourceHostTypes[id] ?? id;\n}\n\nexport function getDefaultVersioning(\n datasourceName: string | undefined,\n): string {\n if (!datasourceName) {\n return defaultVersioning.id;\n }\n\n const datasource = getDatasourceFor(datasourceName);\n\n if (!datasource) {\n logger.warn({ datasourceName }, 'Missing datasource!');\n return defaultVersioning.id;\n }\n\n if (!datasource.defaultVersioning) {\n return defaultVersioning.id;\n }\n\n return datasource.defaultVersioning;\n}\n\nexport function isGetPkgReleasesConfig(\n input: unknown,\n): input is GetPkgReleasesConfig {\n return (\n isNonEmptyStringAndNotWhitespace(\n (input as GetPkgReleasesConfig).datasource,\n ) &&\n isNonEmptyStringAndNotWhitespace(\n (input as GetPkgReleasesConfig).packageName,\n )\n );\n}\n\nexport function applyVersionCompatibility(\n releaseResult: ReleaseResult,\n versionCompatibility: string | undefined,\n currentCompatibility: string | undefined,\n): ReleaseResult {\n if (!versionCompatibility) {\n return releaseResult;\n }\n\n const versionCompatibilityRegEx = regEx(versionCompatibility);\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n const regexResult = versionCompatibilityRegEx.exec(release.version);\n if (!regexResult?.groups?.version) {\n logger.trace(\n { releaseVersion: release.version, versionCompatibility },\n 'versionCompatibility: Does not match regex',\n );\n return null;\n }\n if (regexResult?.groups?.compatibility !== currentCompatibility) {\n logger.trace(\n { releaseVersion: release.version, versionCompatibility },\n 'versionCompatibility: Does not match compatibility',\n );\n return null;\n }\n logger.trace(\n {\n releaseVersion: release.version,\n versionCompatibility,\n version: regexResult.groups.version,\n compatibility: regexResult.groups.compatibility,\n },\n 'versionCompatibility: matches',\n );\n release.versionOrig ??= release.version;\n release.version = regexResult.groups.version;\n return release;\n });\n\n return releaseResult;\n}\n\n/**\n * Extracts a version string from regex named capture groups.\n *\n * Supports two modes:\n * 1. A `version` group: returned as-is.\n * 2. SemVer-part groups (`major`, `minor`, `patch`, `prerelease`, `build`):\n * assembled into `MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]`.\n */\nexport function extractVersionFromGroups(\n groups: Record<string, string> | undefined,\n): string | undefined {\n if (!groups) {\n return undefined;\n }\n\n if (groups.version) {\n return groups.version;\n }\n\n if (!groups.major) {\n return undefined;\n }\n\n let version = `${groups.major}.${groups.minor ?? '0'}.${groups.patch ?? '0'}`;\n if (groups.prerelease) {\n version += `-${groups.prerelease}`;\n }\n if (groups.build) {\n version += `+${groups.build}`;\n }\n return version;\n}\n\nexport function applyExtractVersion(\n releaseResult: ReleaseResult,\n extractVersion: string | undefined,\n): ReleaseResult {\n if (!extractVersion) {\n return releaseResult;\n }\n\n const extractVersionRegEx = regEx(extractVersion);\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n const groups = extractVersionRegEx.exec(release.version)?.groups;\n const version = extractVersionFromGroups(groups);\n if (!version) {\n return null;\n }\n\n release.versionOrig = release.version;\n release.version = version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function filterValidVersions<\n Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n releaseResult.releases = filterMap(releaseResult.releases, (release) =>\n versioning.isVersion(release.version) ? release : null,\n );\n\n return releaseResult;\n}\n\nexport function sortAndRemoveDuplicates<\n Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n releaseResult.releases = releaseResult.releases.sort((a, b) =>\n versioning.sortVersions(a.version, b.version),\n );\n\n // Once releases are sorted, deduplication is straightforward and efficient\n let previousVersion: string | null = null;\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n if (previousVersion === release.version) {\n return null;\n }\n previousVersion = release.version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function applyConstraintsFiltering<\n Config extends Pick<\n GetPkgReleasesConfig,\n | 'constraintsFiltering'\n | 'constraintsVersioning'\n | 'versioning'\n | 'datasource'\n | 'constraints'\n | 'packageName'\n >,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n if (config?.constraintsFiltering !== 'strict') {\n for (const release of releaseResult.releases) {\n delete release.constraints;\n }\n\n return releaseResult;\n }\n\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n\n const configConstraints = config.constraints;\n const filteredReleases: string[] = [];\n const startingLength = releaseResult.releases.length;\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n logger.trace(\n {\n release,\n versioning: versioningName,\n },\n `applyConstraintsFiltering(${release.version})`,\n );\n const releaseConstraints = release.constraints;\n delete release.constraints;\n\n logger.trace(\n {\n release,\n versioning: versioningName,\n configConstraints: configConstraints ?? 'undefined',\n releaseConstraints: releaseConstraints ?? 'undefined',\n },\n `applyConstraintsFiltering(${release.version}): checking constraints`,\n );\n if (!configConstraints || !releaseConstraints) {\n return release;\n }\n\n for (const [name, configConstraint] of Object.entries(\n configConstraints,\n ) as [ConstraintName, string][]) {\n let constraintVersioningName = versioningName;\n if (\n isAdditionalConstraintName(name) &&\n config.constraintsVersioning?.[name]\n ) {\n const val = config.constraintsVersioning[name];\n logger.once.debug(\n { packageName: config.packageName, release },\n `applyConstraintsFiltering(${config.packageName}, ${name}): overriding constraintsVersioning from ${constraintVersioningName} to ${val}`,\n );\n logger.trace(\n { packageName: config.packageName, release },\n `applyConstraintsFiltering(${release.version}): overriding constraintsVersioning from ${constraintVersioningName} to ${val}`,\n );\n constraintVersioningName = val;\n }\n const constraintVersioning = allVersioning.get(constraintVersioningName);\n\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n constraintName: name,\n constraint: configConstraint,\n },\n `applyConstraintsFiltering(${release.version}) for constraint ${name}`,\n );\n\n const isValid = constraintVersioning.isValid(configConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): versioning.isValid(${configConstraint})=${isValid}`,\n );\n if (!isValid) {\n logger.once.warn(\n {\n packageName: config.packageName,\n constraint: configConstraint,\n versioning: constraintVersioningName,\n },\n 'Invalid constraint used with strict constraintsFiltering',\n );\n continue;\n }\n\n const constraint = releaseConstraints[name];\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): releaseConstraints[${name}]=${JSON.stringify(constraint)}`,\n );\n if (!isNonEmptyArray(constraint)) {\n // A release with no constraints is OK\n continue;\n }\n\n let satisfiesConstraints = false;\n for (const releaseConstraint of constraint) {\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): releaseConstraint=${releaseConstraint}`,\n );\n if (!releaseConstraint) {\n satisfiesConstraints = true;\n logger.once.debug(\n {\n packageName: config.packageName,\n versioning: constraintVersioningName,\n constraint: releaseConstraint,\n },\n 'Undefined release constraint',\n );\n break;\n }\n\n const isValidConstraintVersion =\n constraintVersioning.isValid(releaseConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): constraintVersioning.isValid(${releaseConstraint})=${isValidConstraintVersion}`,\n );\n if (!isValidConstraintVersion) {\n logger.once.debug(\n {\n packageName: config.packageName,\n versioning: constraintVersioningName,\n constraint: releaseConstraint,\n },\n 'Invalid release constraint',\n );\n break;\n }\n\n const isEqual = configConstraint === releaseConstraint;\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): ${configConstraint} === ${releaseConstraint}=${isEqual}`,\n );\n if (isEqual) {\n satisfiesConstraints = true;\n break;\n }\n\n const isSubset = constraintVersioning.subset?.(\n configConstraint,\n releaseConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.subset?.(${configConstraint}, ${releaseConstraint})=${isSubset}`,\n );\n if (isSubset) {\n satisfiesConstraints = true;\n break;\n }\n\n const doesMatchConfig = constraintVersioning.matches(\n configConstraint,\n releaseConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.matches(${configConstraint}, ${releaseConstraint})=${doesMatchConfig}`,\n );\n const doesMatchRelease = constraintVersioning.matches(\n releaseConstraint,\n configConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.matches(${releaseConstraint}, ${configConstraint})=${doesMatchRelease}`,\n );\n if (doesMatchConfig || doesMatchRelease) {\n satisfiesConstraints = true;\n break;\n }\n }\n\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): satisfiesConstraints=${satisfiesConstraints}`,\n );\n if (!satisfiesConstraints) {\n filteredReleases.push(release.version);\n return null;\n }\n }\n\n return release;\n });\n\n if (filteredReleases.length) {\n const count = filteredReleases.length;\n const packageName = config.packageName;\n const releases = filteredReleases.join(', ');\n logger.debug(\n {\n datasource: config.datasource,\n packageName: config.packageName,\n },\n `Filtered out ${count} non-matching releases out of ${startingLength} total for ${packageName} due to constraintsFiltering=strict: ${releases}`,\n );\n }\n\n return releaseResult;\n}\n"],"mappings":"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"}
@@ -2,6 +2,7 @@ import { coerceArray } from "../../../util/array.js";
2
2
  import { logger } from "../../../logger/index.js";
3
3
  import { buildCacheKey } from "../../../util/cache/package/key.js";
4
4
  import { ensureTrailingSlash, joinUrlParts } from "../../../util/url.js";
5
+ import { isNotFound } from "../../../util/http/status.js";
5
6
  import { ExternalHostError } from "../../../types/errors/external-host-error.js";
6
7
  import { RequestError } from "../../../util/http/got.js";
7
8
  import "../../../util/http/index.js";
@@ -53,7 +54,7 @@ var CondaDatasource = class extends Datasource {
53
54
  result.releases.push(thisRelease);
54
55
  });
55
56
  } catch (err) {
56
- if (err instanceof RequestError && err.response?.statusCode !== 404) throw new ExternalHostError(err);
57
+ if (err instanceof RequestError && !isNotFound(err)) throw new ExternalHostError(err);
57
58
  this.handleGenericErrors(err);
58
59
  }
59
60
  return result.releases.length ? result : null;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["prefixDev.getReleases","HttpError"],"sources":["../../../../lib/modules/datasource/conda/index.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport { Timestamp } from '../../../util/timestamp.ts';\nimport { ensureTrailingSlash, joinUrlParts } from '../../../util/url.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport { datasource, defaultRegistryUrl, isPrefixDevUrl } from './common.ts';\nimport * as prefixDev from './prefix-dev.ts';\nimport { CondaPackage } from './schema.ts';\n\nexport class CondaDatasource extends Datasource {\n static readonly id = datasource;\n\n constructor() {\n super(datasource);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n\n override readonly registryStrategy = 'hunt';\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [defaultRegistryUrl];\n }\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from the `upload_time` field of the files of a version when using the Anaconda.org API, or from the `createdAt` field of the variants of a version when using prefix.dev. All files of a version are assumed to be published at roughly the same time.';\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `dev_url` field in the results.';\n\n private async fetchReleases({\n registryUrl,\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n logger.trace({ registryUrl, packageName }, 'fetching conda package');\n\n if (!registryUrl) {\n return null;\n }\n\n // We expect registryUrl to be `https://prefix.dev/${channel}` here.\n if (isPrefixDevUrl(registryUrl)) {\n // Since the registryUrl contains at least 3 `/` ,\n // the channel varitable won't be undefined in any case.\n const channel = ensureTrailingSlash(registryUrl).split('/').at(-2)!;\n\n return prefixDev.getReleases(this.http, channel, packageName);\n }\n\n const url = joinUrlParts(registryUrl, packageName);\n\n const result: ReleaseResult = {\n releases: [],\n };\n\n try {\n const response = await this.http.getJson(url, CondaPackage);\n\n result.homepage = response.body.html_url;\n result.sourceUrl = response.body.dev_url;\n\n const releaseDate: Record<string, Timestamp> = {};\n // we assume all packages are roughly released on the same time\n for (const file of coerceArray(response.body.files)) {\n releaseDate[file.version] ??= Timestamp.parse(file.upload_time);\n }\n\n coerceArray(response.body.versions).forEach((version: string) => {\n const thisRelease: Release = {\n version,\n releaseTimestamp: releaseDate[version],\n };\n result.releases.push(thisRelease);\n });\n } catch (err) {\n if (err instanceof HttpError && err.response?.statusCode !== 404) {\n throw new ExternalHostError(err);\n }\n this.handleGenericErrors(err);\n }\n\n return result.releases.length ? result : null;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n key: buildCacheKey(config.registryUrl, config.packageName),\n fallback: true,\n },\n () => this.fetchReleases(config),\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAa,kBAAb,cAAqC,WAAW;CAC9C,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,UAAU;CAClB;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,mBAAqC;CAErC,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,kBAAkB;CAC5B;CAEA,0BAA4C;CAC5C,uBACE;CACF,mBAAqC;CACrC,gBACE;CAEF,MAAc,cAAc,EAC1B,aACA,eACmD;EACnD,OAAO,MAAM;GAAE;GAAa;EAAY,GAAG,wBAAwB;EAEnE,IAAI,CAAC,aACH,OAAO;EAIT,IAAI,eAAe,WAAW,GAAG;GAG/B,MAAM,UAAU,oBAAoB,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE;GAEjE,OAAOA,YAAsB,KAAK,MAAM,SAAS,WAAW;EAC9D;EAEA,MAAM,MAAM,aAAa,aAAa,WAAW;EAEjD,MAAM,SAAwB,EAC5B,UAAU,CAAC,EACb;EAEA,IAAI;GACF,MAAM,WAAW,MAAM,KAAK,KAAK,QAAQ,KAAK,YAAY;GAE1D,OAAO,WAAW,SAAS,KAAK;GAChC,OAAO,YAAY,SAAS,KAAK;GAEjC,MAAM,cAAyC,CAAC;GAEhD,KAAK,MAAM,QAAQ,YAAY,SAAS,KAAK,KAAK,GAChD,YAAY,KAAK,aAAa,UAAU,MAAM,KAAK,WAAW;GAGhE,YAAY,SAAS,KAAK,QAAQ,CAAC,CAAC,SAAS,YAAoB;IAC/D,MAAM,cAAuB;KAC3B;KACA,kBAAkB,YAAY;IAChC;IACA,OAAO,SAAS,KAAK,WAAW;GAClC,CAAC;EACH,SAAS,KAAK;GACZ,IAAI,eAAeC,gBAAa,IAAI,UAAU,eAAe,KAC3D,MAAM,IAAI,kBAAkB,GAAG;GAEjC,KAAK,oBAAoB,GAAG;EAC9B;EAEA,OAAO,OAAO,SAAS,SAAS,SAAS;CAC3C;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GACE,KAAK,cAAc,OAAO,aAAa,OAAO,WAAW;GACzD,UAAU;EACZ,SACM,KAAK,cAAc,MAAM,CACjC;CACF;AACF"}
1
+ {"version":3,"file":"index.js","names":["prefixDev.getReleases","HttpError"],"sources":["../../../../lib/modules/datasource/conda/index.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport { isNotFound } from '../../../util/http/status.ts';\nimport { Timestamp } from '../../../util/timestamp.ts';\nimport { ensureTrailingSlash, joinUrlParts } from '../../../util/url.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport { datasource, defaultRegistryUrl, isPrefixDevUrl } from './common.ts';\nimport * as prefixDev from './prefix-dev.ts';\nimport { CondaPackage } from './schema.ts';\n\nexport class CondaDatasource extends Datasource {\n static readonly id = datasource;\n\n constructor() {\n super(datasource);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n\n override readonly registryStrategy = 'hunt';\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [defaultRegistryUrl];\n }\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from the `upload_time` field of the files of a version when using the Anaconda.org API, or from the `createdAt` field of the variants of a version when using prefix.dev. All files of a version are assumed to be published at roughly the same time.';\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `dev_url` field in the results.';\n\n private async fetchReleases({\n registryUrl,\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n logger.trace({ registryUrl, packageName }, 'fetching conda package');\n\n if (!registryUrl) {\n return null;\n }\n\n // We expect registryUrl to be `https://prefix.dev/${channel}` here.\n if (isPrefixDevUrl(registryUrl)) {\n // Since the registryUrl contains at least 3 `/` ,\n // the channel varitable won't be undefined in any case.\n const channel = ensureTrailingSlash(registryUrl).split('/').at(-2)!;\n\n return prefixDev.getReleases(this.http, channel, packageName);\n }\n\n const url = joinUrlParts(registryUrl, packageName);\n\n const result: ReleaseResult = {\n releases: [],\n };\n\n try {\n const response = await this.http.getJson(url, CondaPackage);\n\n result.homepage = response.body.html_url;\n result.sourceUrl = response.body.dev_url;\n\n const releaseDate: Record<string, Timestamp> = {};\n // we assume all packages are roughly released on the same time\n for (const file of coerceArray(response.body.files)) {\n releaseDate[file.version] ??= Timestamp.parse(file.upload_time);\n }\n\n coerceArray(response.body.versions).forEach((version: string) => {\n const thisRelease: Release = {\n version,\n releaseTimestamp: releaseDate[version],\n };\n result.releases.push(thisRelease);\n });\n } catch (err) {\n if (err instanceof HttpError && !isNotFound(err)) {\n throw new ExternalHostError(err);\n }\n this.handleGenericErrors(err);\n }\n\n return result.releases.length ? result : null;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return this.cached(\n {\n key: buildCacheKey(config.registryUrl, config.packageName),\n fallback: true,\n },\n () => this.fetchReleases(config),\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,IAAa,kBAAb,cAAqC,WAAW;CAC9C,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,UAAU;CAClB;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,mBAAqC;CAErC,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,kBAAkB;CAC5B;CAEA,0BAA4C;CAC5C,uBACE;CACF,mBAAqC;CACrC,gBACE;CAEF,MAAc,cAAc,EAC1B,aACA,eACmD;EACnD,OAAO,MAAM;GAAE;GAAa;EAAY,GAAG,wBAAwB;EAEnE,IAAI,CAAC,aACH,OAAO;EAIT,IAAI,eAAe,WAAW,GAAG;GAG/B,MAAM,UAAU,oBAAoB,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE;GAEjE,OAAOA,YAAsB,KAAK,MAAM,SAAS,WAAW;EAC9D;EAEA,MAAM,MAAM,aAAa,aAAa,WAAW;EAEjD,MAAM,SAAwB,EAC5B,UAAU,CAAC,EACb;EAEA,IAAI;GACF,MAAM,WAAW,MAAM,KAAK,KAAK,QAAQ,KAAK,YAAY;GAE1D,OAAO,WAAW,SAAS,KAAK;GAChC,OAAO,YAAY,SAAS,KAAK;GAEjC,MAAM,cAAyC,CAAC;GAEhD,KAAK,MAAM,QAAQ,YAAY,SAAS,KAAK,KAAK,GAChD,YAAY,KAAK,aAAa,UAAU,MAAM,KAAK,WAAW;GAGhE,YAAY,SAAS,KAAK,QAAQ,CAAC,CAAC,SAAS,YAAoB;IAC/D,MAAM,cAAuB;KAC3B;KACA,kBAAkB,YAAY;IAChC;IACA,OAAO,SAAS,KAAK,WAAW;GAClC,CAAC;EACH,SAAS,KAAK;GACZ,IAAI,eAAeC,gBAAa,CAAC,WAAW,GAAG,GAC7C,MAAM,IAAI,kBAAkB,GAAG;GAEjC,KAAK,oBAAoB,GAAG;EAC9B;EAEA,OAAO,OAAO,SAAS,SAAS,SAAS;CAC3C;CAEA,YAAY,QAA0D;EACpE,OAAO,KAAK,OACV;GACE,KAAK,cAAc,OAAO,aAAa,OAAO,WAAW;GACzD,UAAU;EACZ,SACM,KAAK,cAAc,MAAM,CACjC;CACF;AACF"}
@@ -4,6 +4,7 @@ import { GlobalConfig } from "../../../config/global.js";
4
4
  import { logger } from "../../../logger/index.js";
5
5
  import { buildCacheKey } from "../../../util/cache/package/key.js";
6
6
  import { isHttpUrl, joinUrlParts, parseUrl } from "../../../util/url.js";
7
+ import { isNotFound } from "../../../util/http/status.js";
7
8
  import { toSha256 } from "../../../util/hash.js";
8
9
  import { privateCacheDir, readCacheFile } from "../../../util/fs/index.js";
9
10
  import { Json } from "../../../util/schema-utils/index.js";
@@ -129,7 +130,7 @@ var CrateDatasource = class CrateDatasource extends Datasource {
129
130
  return parseUrl(api)?.hostname === "crates.io";
130
131
  }
131
132
  static isNotFound(err) {
132
- return err instanceof RequestError && err.response?.statusCode === 404;
133
+ return err instanceof RequestError && isNotFound(err);
133
134
  }
134
135
  /**
135
136
  * The marker is keyed by the `api` URL, since the missing endpoints are a
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["cargoVersioning.id","memCache.get","HttpError","packageCache.get","packageCache.set"],"sources":["../../../../lib/modules/datasource/crate/index.ts"],"sourcesContent":["import { isBoolean } from '@sindresorhus/is';\nimport upath from 'upath';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport * as packageCache from '../../../util/cache/package/index.ts';\nimport { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport { withCache } from '../../../util/cache/package/with-cache.ts';\nimport { privateCacheDir, readCacheFile } from '../../../util/fs/index.ts';\nimport { createSimpleGit } from '../../../util/git/index.ts';\nimport { toSha256 } from '../../../util/hash.ts';\nimport { memCacheProvider } from '../../../util/http/cache/memory-http-cache-provider.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport { acquireLock } from '../../../util/mutex.ts';\nimport { newlineRegex, regEx } from '../../../util/regex.ts';\nimport { Json } from '../../../util/schema-utils/index.ts';\nimport { asTimestamp } from '../../../util/timestamp.ts';\nimport { isHttpUrl, joinUrlParts, parseUrl } from '../../../util/url.ts';\nimport * as cargoVersioning from '../../versioning/cargo/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n GetReleasesConfig,\n PostprocessReleaseConfig,\n PostprocessReleaseResult,\n Release,\n ReleaseResult,\n} from '../types.ts';\nimport type { CrateMetadata } from './schema.ts';\nimport {\n CrateMetadataResponse,\n RegistryConfig,\n ReleaseTimestamp,\n} from './schema.ts';\nimport type { CrateRecord, RegistryFlavor, RegistryInfo } from './types.ts';\n\ntype CloneResult =\n | {\n err: Error;\n clonePath?: undefined;\n }\n | {\n clonePath: string;\n err?: undefined;\n };\n\nexport class CrateDatasource extends Datasource {\n static readonly id = 'crate';\n\n constructor() {\n super(CrateDatasource.id);\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['sparse+https://index.crates.io/'];\n }\n\n override defaultVersioning = cargoVersioning.id;\n\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `repository` field in the results.';\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from `pubtime` field from crates.io index if available, or `version.created_at` field from crates.io API otherwise.';\n\n private async _getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n /* v8 ignore if -- should never happen */\n if (!registryUrl) {\n logger.warn(\n 'crate datasource: No registryUrl specified, cannot perform getReleases',\n );\n return null;\n }\n\n const registryInfo = await CrateDatasource.fetchRegistryInfo({\n packageName,\n registryUrl,\n });\n if (!registryInfo) {\n logger.debug(`Could not fetch registry info from ${registryUrl}`);\n return null;\n }\n\n const dependencyUrl = CrateDatasource.getDependencyUrl(\n registryInfo,\n packageName,\n );\n\n const payload = await this.fetchCrateRecordsPayload(\n registryInfo,\n packageName,\n );\n const lines = payload\n .split(newlineRegex) // break into lines\n .map((line) => line.trim()) // remove whitespace\n .filter((line) => line.length !== 0) // remove empty lines\n .map((line) => JSON.parse(line) as CrateRecord); // parse\n\n const metadata = await this.getCrateMetadata(registryInfo, packageName);\n\n const result: ReleaseResult = {\n dependencyUrl,\n releases: [],\n };\n\n if (metadata?.homepage) {\n result.homepage = metadata.homepage;\n }\n\n if (metadata?.repository) {\n result.sourceUrl = metadata.repository;\n }\n\n result.releases = lines\n .map((line) => {\n const versionOrig = line.vers;\n const version = versionOrig.replace(regEx(/\\+.*$/), '');\n const release: Release = { version };\n\n if (versionOrig !== version) {\n release.versionOrig = versionOrig;\n }\n\n if (line.yanked) {\n release.isDeprecated = true;\n }\n\n if (line.rust_version) {\n release.constraints = { rust: [line.rust_version] };\n }\n\n if (line.pubtime) {\n release.releaseTimestamp = asTimestamp(line.pubtime);\n }\n\n return release;\n })\n .filter((release) => release.version);\n if (!result.releases.length) {\n return null;\n }\n\n return result;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return withCache(\n {\n namespace: `datasource-${CrateDatasource.id}`,\n key: buildCacheKey(config.registryUrl, config.packageName),\n public: CrateDatasource.isCratesIo(config.registryUrl),\n fallback: true,\n },\n () => this._getReleases(config),\n );\n }\n\n /** Returns the memory cache key of the registry's config.json. */\n private static registryConfigCacheKey(rawUrl: string): string {\n return buildCacheKey('crate-datasource', 'registry-config', rawUrl);\n }\n\n /** Returns the memory cache key of the unsupported read API marker. */\n private static apiUnsupportedCacheKey(api: string): string {\n return buildCacheKey('crate-datasource', 'registry-api-unsupported', api);\n }\n\n /**\n * Fetches the registry's config.json which provides the API base URL\n * and download URL template.\n * See: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-configuration\n */\n private async fetchRegistryConfig(\n info: RegistryInfo,\n ): Promise<RegistryConfig | null> {\n const cacheKey = CrateDatasource.registryConfigCacheKey(info.rawUrl);\n const cached = memCache.get<RegistryConfig>(cacheKey);\n if (cached) {\n return cached;\n }\n\n if (info.clonePath) {\n try {\n const configPath = upath.join(info.clonePath, 'config.json');\n const content = await readCacheFile(configPath, 'utf8');\n const parsed = Json.pipe(RegistryConfig).parse(content);\n memCache.set(cacheKey, parsed);\n return parsed;\n } catch {\n logger.debug(\n { registryUrl: info.rawUrl },\n 'Could not read config.json from cloned registry',\n );\n }\n } else {\n try {\n const configUrl = joinUrlParts(info.rawUrl, 'config.json');\n const { body } = await this.http.getJson(configUrl, RegistryConfig);\n memCache.set(cacheKey, body);\n return body;\n } catch {\n logger.debug(\n { registryUrl: info.rawUrl },\n 'Could not fetch registry config.json',\n );\n }\n }\n\n return null;\n }\n\n /**\n * The registry web API specification only defines publish, yank, unyank,\n * owners, search and login endpoints, see\n * https://doc.rust-lang.org/cargo/reference/registry-web-api.html.\n * `GET api/v1/crates/<name>` and `GET api/v1/crates/<name>/<version>` are\n * crates.io extensions. Registries which mirror the crates.io index keep\n * `api` pointing at crates.io and are used without probing. Any other\n * registry is probed once and remembered as unsupported when it answers\n * 404, since private registries (Artifactory, CodeArtifact, ...) advertise\n * an `api` URL for publishing only.\n */\n private static isCratesIoApi(api: string): boolean {\n return parseUrl(api)?.hostname === 'crates.io';\n }\n\n private static isNotFound(err: unknown): boolean {\n return err instanceof HttpError && err.response?.statusCode === 404;\n }\n\n /**\n * The marker is keyed by the `api` URL, since the missing endpoints are a\n * property of the API server, not of the index that points to it.\n */\n private async isReadApiUnsupported(api: string): Promise<boolean> {\n if (CrateDatasource.isCratesIoApi(api)) {\n return false;\n }\n\n const memKey = CrateDatasource.apiUnsupportedCacheKey(api);\n const cached = memCache.get<boolean>(memKey);\n if (isBoolean(cached)) {\n return cached;\n }\n\n const persisted = await packageCache.get<boolean>(\n 'datasource-crate-registry-api',\n api,\n );\n const unsupported = persisted === true;\n memCache.set(memKey, unsupported);\n return unsupported;\n }\n\n private async markReadApiUnsupported(\n registryUrl: string,\n api: string,\n ): Promise<void> {\n logger.debug(\n { registryUrl, api },\n 'Registry does not implement the crates.io read API, skipping crate metadata and release timestamp lookups',\n );\n memCache.set(CrateDatasource.apiUnsupportedCacheKey(api), true);\n await packageCache.set('datasource-crate-registry-api', api, true, 24 * 60);\n }\n\n private async _getCrateMetadata(\n info: RegistryInfo,\n packageName: string,\n ): Promise<CrateMetadata | null> {\n const registryConfig = await this.fetchRegistryConfig(info);\n if (!registryConfig?.api) {\n return null;\n }\n\n const { api } = registryConfig;\n if (await this.isReadApiUnsupported(api)) {\n return null;\n }\n\n const apiBaseUrl = joinUrlParts(api, 'api/v1/');\n\n // The `?include=` suffix is required to avoid unnecessary database queries\n // on the crates.io server. This lets us work around the regular request\n // throttling of one request per second.\n const crateUrl = `${apiBaseUrl}crates/${packageName}?include=`;\n\n logger.trace(\n { crateUrl, packageName, registryUrl: info.rawUrl },\n 'downloading crate metadata',\n );\n\n try {\n const { body } = await this.http.getJson(crateUrl, CrateMetadataResponse);\n return body.crate;\n } catch (err) {\n // The index lookup preceding this call found the crate, so a 404 means\n // the registry does not implement the endpoint at all\n if (\n !CrateDatasource.isCratesIoApi(api) &&\n CrateDatasource.isNotFound(err)\n ) {\n await this.markReadApiUnsupported(info.rawUrl, api);\n return null;\n }\n logger.debug(\n { err, packageName, registryUrl: info.rawUrl },\n 'failed to download crate metadata',\n );\n }\n\n return null;\n }\n\n public getCrateMetadata(\n info: RegistryInfo,\n packageName: string,\n ): Promise<CrateMetadata | null> {\n return withCache(\n {\n namespace: `datasource-${CrateDatasource.id}-metadata`,\n key: buildCacheKey(info.rawUrl, packageName),\n public: info.flavor === 'crates.io',\n ttlMinutes: 24 * 60, // 24 hours\n },\n () => this._getCrateMetadata(info, packageName),\n );\n }\n\n public async fetchCrateRecordsPayload(\n info: RegistryInfo,\n packageName: string,\n ): Promise<string> {\n if (info.clonePath) {\n const path = upath.join(\n info.clonePath,\n ...CrateDatasource.getIndexSuffix(packageName),\n );\n return readCacheFile(path, 'utf8');\n }\n\n // sparse index\n const packageSuffix = CrateDatasource.getIndexSuffix(\n packageName.toLowerCase(),\n );\n const crateUrl = joinUrlParts(info.rawUrl, ...packageSuffix);\n logger.trace(\n { crateUrl, packageName, registryUrl: info.rawUrl },\n 'fetching crate records from sparse index',\n );\n try {\n return (await this.http.getText(crateUrl)).body;\n } catch (err) {\n this.handleGenericErrors(err);\n }\n }\n\n /**\n * Computes the dependency URL for a crate, given\n * registry information\n */\n private static getDependencyUrl(\n info: RegistryInfo,\n packageName: string,\n ): string {\n switch (info.flavor) {\n case 'crates.io':\n return `https://crates.io/crates/${packageName}`;\n case 'cloudsmith': {\n // input: https://dl.cloudsmith.io/basic/$org/$repo/cargo/index.git\n const tokens = info.url.pathname.split('/');\n const org = tokens[2];\n const repo = tokens[3];\n return `https://cloudsmith.io/~${org}/repos/${repo}/packages/detail/cargo/${packageName}`;\n }\n default:\n return `${info.url}/${packageName}`;\n }\n }\n\n /**\n * Given a Git URL, computes a semi-human-readable name for a folder in which to\n * clone the repository.\n */\n private static cacheDirFromUrl(url: URL): string {\n const proto = url.protocol.replace(regEx(/:$/), '');\n const host = url.hostname;\n const hash = toSha256(url.pathname).substring(0, 7);\n\n return `crate-registry-${proto}-${host}-${hash}`;\n }\n\n private static isSparseRegistry(url: string): boolean {\n const parsed = parseUrl(url);\n if (!parsed) {\n return false;\n }\n return parsed.protocol.startsWith('sparse+');\n }\n\n /**\n * Fetches information about a registry, by url.\n * If no url is given, assumes crates.io.\n * If an url is given, assumes it's a valid Git repository\n * url and clones it to cache.\n */\n private static async fetchRegistryInfo({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<RegistryInfo | null> {\n /* v8 ignore next -- should never happen */\n if (!registryUrl) {\n return null;\n }\n\n const isSparseRegistry = CrateDatasource.isSparseRegistry(registryUrl);\n const registryFetchUrl = isSparseRegistry\n ? registryUrl.replace(regEx(/^sparse\\+/), '')\n : registryUrl;\n\n const url = parseUrl(registryFetchUrl);\n if (!url) {\n logger.debug(`Could not parse registry URL ${registryFetchUrl}`);\n return null;\n }\n\n let flavor: RegistryFlavor;\n if (url.hostname === 'index.crates.io') {\n flavor = 'crates.io';\n } else if (url.hostname === 'dl.cloudsmith.io') {\n flavor = 'cloudsmith';\n } else {\n flavor = 'other';\n }\n\n const registry: RegistryInfo = {\n flavor,\n rawUrl: registryFetchUrl,\n url,\n };\n\n if (!isSparseRegistry) {\n if (\n registry.flavor !== 'crates.io' &&\n !GlobalConfig.get('allowCustomCrateGitRegistries')\n ) {\n logger.warn(\n 'crate datasource: allowCustomCrateGitRegistries=true is required for git-cloning registries other than crates.io, bailing out',\n );\n return null;\n }\n const cacheKey = buildCacheKey(\n 'crate-datasource',\n 'registry-clone-path',\n registryFetchUrl,\n );\n const lockKey = registryFetchUrl;\n\n const executionTimeout = GlobalConfig.get('executionTimeout') * 60 * 1000;\n const gitTimeout = GlobalConfig.get('gitTimeout') || executionTimeout;\n const releaseLock = await acquireLock(\n lockKey,\n 'crate-registry',\n gitTimeout,\n );\n try {\n const cached = memCache.get<CloneResult>(cacheKey);\n\n if (cached?.err) {\n logger.warn(\n { err: cached.err, packageName, registryFetchUrl },\n 'Previous git clone failed, bailing out.',\n );\n return null;\n }\n\n if (cached?.clonePath) {\n registry.clonePath = cached.clonePath;\n return registry;\n }\n\n const clonePath = upath.join(\n privateCacheDir(),\n CrateDatasource.cacheDirFromUrl(url),\n );\n\n const result = await CrateDatasource.clone(\n registryFetchUrl,\n clonePath,\n packageName,\n );\n\n memCache.set(cacheKey, result);\n\n if (result.err) {\n logger.warn(\n { err: result.err, packageName, registryFetchUrl },\n 'Git clone failed, bailing out.',\n );\n return null;\n }\n\n registry.clonePath = result.clonePath;\n } finally {\n releaseLock();\n }\n }\n\n return registry;\n }\n\n private static async clone(\n registryFetchUrl: string,\n clonePath: string,\n packageName: string,\n ): Promise<CloneResult> {\n logger.info(\n { clonePath, registryFetchUrl },\n `Cloning private cargo registry`,\n );\n\n const git = createSimpleGit({\n config: { maxConcurrentProcesses: 1 },\n ...(isHttpUrl(registryFetchUrl) && {\n // the URL as well, for the credentials registered from it, which only apply to this registry\n authentication: {\n hostTypes: [CrateDatasource.id],\n url: registryFetchUrl,\n },\n }),\n });\n\n try {\n await git.clone(registryFetchUrl, clonePath, {\n '--depth': 1,\n });\n return { clonePath };\n } catch (err) {\n if (\n err.message.includes(\n 'fatal: dumb http transport does not support shallow capabilities',\n )\n ) {\n logger.info(\n { packageName, registryFetchUrl },\n 'failed to shallow clone git registry, doing full clone',\n );\n try {\n await git.clone(registryFetchUrl, clonePath);\n return { clonePath };\n } catch (err) {\n logger.warn(\n { err, packageName, registryFetchUrl },\n 'failed cloning git registry',\n );\n return { err };\n }\n } else {\n logger.warn(\n { err, packageName, registryFetchUrl },\n 'failed cloning git registry',\n );\n return { err };\n }\n }\n }\n\n private static isCratesIo(registryUrl: string | undefined): boolean {\n if (!registryUrl) {\n return false;\n }\n const normalized = registryUrl.replace(regEx(/^sparse\\+/), '');\n const parsed = parseUrl(normalized);\n return parsed?.hostname === 'index.crates.io';\n }\n\n public static getIndexSuffix(packageName: string): string[] {\n const len = packageName.length;\n\n if (len === 1) {\n return ['1', packageName];\n }\n if (len === 2) {\n return ['2', packageName];\n }\n if (len === 3) {\n return ['3', packageName[0], packageName];\n }\n\n return [packageName.slice(0, 2), packageName.slice(2, 4), packageName];\n }\n\n private async _postprocessRelease(\n { packageName, registryUrl }: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult> {\n if (release.releaseTimestamp) {\n return release;\n }\n\n // Look up the registry config from cache (populated during getReleases)\n const rawUrl = registryUrl?.replace(regEx(/^sparse\\+/), '');\n if (!rawUrl) {\n return release;\n }\n const config = memCache.get<RegistryConfig>(\n CrateDatasource.registryConfigCacheKey(rawUrl),\n );\n if (!config?.api) {\n return release;\n }\n\n const { api } = config;\n if (await this.isReadApiUnsupported(api)) {\n return release;\n }\n\n const apiBaseUrl = joinUrlParts(api, 'api/v1/');\n const url = `${apiBaseUrl}crates/${packageName}/${release.versionOrig ?? release.version}`;\n logger.trace(\n { url, packageName, version: release.version, registryUrl },\n 'fetching crate release timestamp',\n );\n // Getting release timestamp could become unnecessary if the manual backfill of `pubtime` mentioned in\n // https://github.com/rust-lang/cargo/issues/15491 is done for all packages.\n try {\n const { body: releaseTimestamp } = await this.http.getJson(\n url,\n { cacheProvider: memCacheProvider },\n ReleaseTimestamp,\n );\n release.releaseTimestamp = releaseTimestamp;\n } catch (err) {\n if (\n CrateDatasource.isCratesIoApi(api) ||\n !CrateDatasource.isNotFound(err)\n ) {\n throw err;\n }\n await this.markReadApiUnsupported(rawUrl, api);\n }\n return release;\n }\n\n override postprocessRelease(\n config: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult> {\n return withCache(\n {\n namespace: `datasource-crate`,\n key: buildCacheKey(\n 'postprocessRelease',\n config.registryUrl,\n config.packageName,\n release.version,\n ),\n ttlMinutes: 7 * 24 * 60,\n public: CrateDatasource.isCratesIo(config.registryUrl ?? undefined),\n },\n () => this._postprocessRelease(config, release),\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["cargoVersioning.id","memCache.get","HttpError","packageCache.get","packageCache.set"],"sources":["../../../../lib/modules/datasource/crate/index.ts"],"sourcesContent":["import { isBoolean } from '@sindresorhus/is';\nimport upath from 'upath';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport * as packageCache from '../../../util/cache/package/index.ts';\nimport { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport { withCache } from '../../../util/cache/package/with-cache.ts';\nimport { privateCacheDir, readCacheFile } from '../../../util/fs/index.ts';\nimport { createSimpleGit } from '../../../util/git/index.ts';\nimport { toSha256 } from '../../../util/hash.ts';\nimport { memCacheProvider } from '../../../util/http/cache/memory-http-cache-provider.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport { isNotFound } from '../../../util/http/status.ts';\nimport { acquireLock } from '../../../util/mutex.ts';\nimport { newlineRegex, regEx } from '../../../util/regex.ts';\nimport { Json } from '../../../util/schema-utils/index.ts';\nimport { asTimestamp } from '../../../util/timestamp.ts';\nimport { isHttpUrl, joinUrlParts, parseUrl } from '../../../util/url.ts';\nimport * as cargoVersioning from '../../versioning/cargo/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n GetReleasesConfig,\n PostprocessReleaseConfig,\n PostprocessReleaseResult,\n Release,\n ReleaseResult,\n} from '../types.ts';\nimport type { CrateMetadata } from './schema.ts';\nimport {\n CrateMetadataResponse,\n RegistryConfig,\n ReleaseTimestamp,\n} from './schema.ts';\nimport type { CrateRecord, RegistryFlavor, RegistryInfo } from './types.ts';\n\ntype CloneResult =\n | {\n err: Error;\n clonePath?: undefined;\n }\n | {\n clonePath: string;\n err?: undefined;\n };\n\nexport class CrateDatasource extends Datasource {\n static readonly id = 'crate';\n\n constructor() {\n super(CrateDatasource.id);\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['sparse+https://index.crates.io/'];\n }\n\n override defaultVersioning = cargoVersioning.id;\n\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `repository` field in the results.';\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from `pubtime` field from crates.io index if available, or `version.created_at` field from crates.io API otherwise.';\n\n private async _getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n /* v8 ignore if -- should never happen */\n if (!registryUrl) {\n logger.warn(\n 'crate datasource: No registryUrl specified, cannot perform getReleases',\n );\n return null;\n }\n\n const registryInfo = await CrateDatasource.fetchRegistryInfo({\n packageName,\n registryUrl,\n });\n if (!registryInfo) {\n logger.debug(`Could not fetch registry info from ${registryUrl}`);\n return null;\n }\n\n const dependencyUrl = CrateDatasource.getDependencyUrl(\n registryInfo,\n packageName,\n );\n\n const payload = await this.fetchCrateRecordsPayload(\n registryInfo,\n packageName,\n );\n const lines = payload\n .split(newlineRegex) // break into lines\n .map((line) => line.trim()) // remove whitespace\n .filter((line) => line.length !== 0) // remove empty lines\n .map((line) => JSON.parse(line) as CrateRecord); // parse\n\n const metadata = await this.getCrateMetadata(registryInfo, packageName);\n\n const result: ReleaseResult = {\n dependencyUrl,\n releases: [],\n };\n\n if (metadata?.homepage) {\n result.homepage = metadata.homepage;\n }\n\n if (metadata?.repository) {\n result.sourceUrl = metadata.repository;\n }\n\n result.releases = lines\n .map((line) => {\n const versionOrig = line.vers;\n const version = versionOrig.replace(regEx(/\\+.*$/), '');\n const release: Release = { version };\n\n if (versionOrig !== version) {\n release.versionOrig = versionOrig;\n }\n\n if (line.yanked) {\n release.isDeprecated = true;\n }\n\n if (line.rust_version) {\n release.constraints = { rust: [line.rust_version] };\n }\n\n if (line.pubtime) {\n release.releaseTimestamp = asTimestamp(line.pubtime);\n }\n\n return release;\n })\n .filter((release) => release.version);\n if (!result.releases.length) {\n return null;\n }\n\n return result;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return withCache(\n {\n namespace: `datasource-${CrateDatasource.id}`,\n key: buildCacheKey(config.registryUrl, config.packageName),\n public: CrateDatasource.isCratesIo(config.registryUrl),\n fallback: true,\n },\n () => this._getReleases(config),\n );\n }\n\n /** Returns the memory cache key of the registry's config.json. */\n private static registryConfigCacheKey(rawUrl: string): string {\n return buildCacheKey('crate-datasource', 'registry-config', rawUrl);\n }\n\n /** Returns the memory cache key of the unsupported read API marker. */\n private static apiUnsupportedCacheKey(api: string): string {\n return buildCacheKey('crate-datasource', 'registry-api-unsupported', api);\n }\n\n /**\n * Fetches the registry's config.json which provides the API base URL\n * and download URL template.\n * See: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-configuration\n */\n private async fetchRegistryConfig(\n info: RegistryInfo,\n ): Promise<RegistryConfig | null> {\n const cacheKey = CrateDatasource.registryConfigCacheKey(info.rawUrl);\n const cached = memCache.get<RegistryConfig>(cacheKey);\n if (cached) {\n return cached;\n }\n\n if (info.clonePath) {\n try {\n const configPath = upath.join(info.clonePath, 'config.json');\n const content = await readCacheFile(configPath, 'utf8');\n const parsed = Json.pipe(RegistryConfig).parse(content);\n memCache.set(cacheKey, parsed);\n return parsed;\n } catch {\n logger.debug(\n { registryUrl: info.rawUrl },\n 'Could not read config.json from cloned registry',\n );\n }\n } else {\n try {\n const configUrl = joinUrlParts(info.rawUrl, 'config.json');\n const { body } = await this.http.getJson(configUrl, RegistryConfig);\n memCache.set(cacheKey, body);\n return body;\n } catch {\n logger.debug(\n { registryUrl: info.rawUrl },\n 'Could not fetch registry config.json',\n );\n }\n }\n\n return null;\n }\n\n /**\n * The registry web API specification only defines publish, yank, unyank,\n * owners, search and login endpoints, see\n * https://doc.rust-lang.org/cargo/reference/registry-web-api.html.\n * `GET api/v1/crates/<name>` and `GET api/v1/crates/<name>/<version>` are\n * crates.io extensions. Registries which mirror the crates.io index keep\n * `api` pointing at crates.io and are used without probing. Any other\n * registry is probed once and remembered as unsupported when it answers\n * 404, since private registries (Artifactory, CodeArtifact, ...) advertise\n * an `api` URL for publishing only.\n */\n private static isCratesIoApi(api: string): boolean {\n return parseUrl(api)?.hostname === 'crates.io';\n }\n\n private static isNotFound(err: unknown): boolean {\n return err instanceof HttpError && isNotFound(err);\n }\n\n /**\n * The marker is keyed by the `api` URL, since the missing endpoints are a\n * property of the API server, not of the index that points to it.\n */\n private async isReadApiUnsupported(api: string): Promise<boolean> {\n if (CrateDatasource.isCratesIoApi(api)) {\n return false;\n }\n\n const memKey = CrateDatasource.apiUnsupportedCacheKey(api);\n const cached = memCache.get<boolean>(memKey);\n if (isBoolean(cached)) {\n return cached;\n }\n\n const persisted = await packageCache.get<boolean>(\n 'datasource-crate-registry-api',\n api,\n );\n const unsupported = persisted === true;\n memCache.set(memKey, unsupported);\n return unsupported;\n }\n\n private async markReadApiUnsupported(\n registryUrl: string,\n api: string,\n ): Promise<void> {\n logger.debug(\n { registryUrl, api },\n 'Registry does not implement the crates.io read API, skipping crate metadata and release timestamp lookups',\n );\n memCache.set(CrateDatasource.apiUnsupportedCacheKey(api), true);\n await packageCache.set('datasource-crate-registry-api', api, true, 24 * 60);\n }\n\n private async _getCrateMetadata(\n info: RegistryInfo,\n packageName: string,\n ): Promise<CrateMetadata | null> {\n const registryConfig = await this.fetchRegistryConfig(info);\n if (!registryConfig?.api) {\n return null;\n }\n\n const { api } = registryConfig;\n if (await this.isReadApiUnsupported(api)) {\n return null;\n }\n\n const apiBaseUrl = joinUrlParts(api, 'api/v1/');\n\n // The `?include=` suffix is required to avoid unnecessary database queries\n // on the crates.io server. This lets us work around the regular request\n // throttling of one request per second.\n const crateUrl = `${apiBaseUrl}crates/${packageName}?include=`;\n\n logger.trace(\n { crateUrl, packageName, registryUrl: info.rawUrl },\n 'downloading crate metadata',\n );\n\n try {\n const { body } = await this.http.getJson(crateUrl, CrateMetadataResponse);\n return body.crate;\n } catch (err) {\n // The index lookup preceding this call found the crate, so a 404 means\n // the registry does not implement the endpoint at all\n if (\n !CrateDatasource.isCratesIoApi(api) &&\n CrateDatasource.isNotFound(err)\n ) {\n await this.markReadApiUnsupported(info.rawUrl, api);\n return null;\n }\n logger.debug(\n { err, packageName, registryUrl: info.rawUrl },\n 'failed to download crate metadata',\n );\n }\n\n return null;\n }\n\n public getCrateMetadata(\n info: RegistryInfo,\n packageName: string,\n ): Promise<CrateMetadata | null> {\n return withCache(\n {\n namespace: `datasource-${CrateDatasource.id}-metadata`,\n key: buildCacheKey(info.rawUrl, packageName),\n public: info.flavor === 'crates.io',\n ttlMinutes: 24 * 60, // 24 hours\n },\n () => this._getCrateMetadata(info, packageName),\n );\n }\n\n public async fetchCrateRecordsPayload(\n info: RegistryInfo,\n packageName: string,\n ): Promise<string> {\n if (info.clonePath) {\n const path = upath.join(\n info.clonePath,\n ...CrateDatasource.getIndexSuffix(packageName),\n );\n return readCacheFile(path, 'utf8');\n }\n\n // sparse index\n const packageSuffix = CrateDatasource.getIndexSuffix(\n packageName.toLowerCase(),\n );\n const crateUrl = joinUrlParts(info.rawUrl, ...packageSuffix);\n logger.trace(\n { crateUrl, packageName, registryUrl: info.rawUrl },\n 'fetching crate records from sparse index',\n );\n try {\n return (await this.http.getText(crateUrl)).body;\n } catch (err) {\n this.handleGenericErrors(err);\n }\n }\n\n /**\n * Computes the dependency URL for a crate, given\n * registry information\n */\n private static getDependencyUrl(\n info: RegistryInfo,\n packageName: string,\n ): string {\n switch (info.flavor) {\n case 'crates.io':\n return `https://crates.io/crates/${packageName}`;\n case 'cloudsmith': {\n // input: https://dl.cloudsmith.io/basic/$org/$repo/cargo/index.git\n const tokens = info.url.pathname.split('/');\n const org = tokens[2];\n const repo = tokens[3];\n return `https://cloudsmith.io/~${org}/repos/${repo}/packages/detail/cargo/${packageName}`;\n }\n default:\n return `${info.url}/${packageName}`;\n }\n }\n\n /**\n * Given a Git URL, computes a semi-human-readable name for a folder in which to\n * clone the repository.\n */\n private static cacheDirFromUrl(url: URL): string {\n const proto = url.protocol.replace(regEx(/:$/), '');\n const host = url.hostname;\n const hash = toSha256(url.pathname).substring(0, 7);\n\n return `crate-registry-${proto}-${host}-${hash}`;\n }\n\n private static isSparseRegistry(url: string): boolean {\n const parsed = parseUrl(url);\n if (!parsed) {\n return false;\n }\n return parsed.protocol.startsWith('sparse+');\n }\n\n /**\n * Fetches information about a registry, by url.\n * If no url is given, assumes crates.io.\n * If an url is given, assumes it's a valid Git repository\n * url and clones it to cache.\n */\n private static async fetchRegistryInfo({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<RegistryInfo | null> {\n /* v8 ignore next -- should never happen */\n if (!registryUrl) {\n return null;\n }\n\n const isSparseRegistry = CrateDatasource.isSparseRegistry(registryUrl);\n const registryFetchUrl = isSparseRegistry\n ? registryUrl.replace(regEx(/^sparse\\+/), '')\n : registryUrl;\n\n const url = parseUrl(registryFetchUrl);\n if (!url) {\n logger.debug(`Could not parse registry URL ${registryFetchUrl}`);\n return null;\n }\n\n let flavor: RegistryFlavor;\n if (url.hostname === 'index.crates.io') {\n flavor = 'crates.io';\n } else if (url.hostname === 'dl.cloudsmith.io') {\n flavor = 'cloudsmith';\n } else {\n flavor = 'other';\n }\n\n const registry: RegistryInfo = {\n flavor,\n rawUrl: registryFetchUrl,\n url,\n };\n\n if (!isSparseRegistry) {\n if (\n registry.flavor !== 'crates.io' &&\n !GlobalConfig.get('allowCustomCrateGitRegistries')\n ) {\n logger.warn(\n 'crate datasource: allowCustomCrateGitRegistries=true is required for git-cloning registries other than crates.io, bailing out',\n );\n return null;\n }\n const cacheKey = buildCacheKey(\n 'crate-datasource',\n 'registry-clone-path',\n registryFetchUrl,\n );\n const lockKey = registryFetchUrl;\n\n const executionTimeout = GlobalConfig.get('executionTimeout') * 60 * 1000;\n const gitTimeout = GlobalConfig.get('gitTimeout') || executionTimeout;\n const releaseLock = await acquireLock(\n lockKey,\n 'crate-registry',\n gitTimeout,\n );\n try {\n const cached = memCache.get<CloneResult>(cacheKey);\n\n if (cached?.err) {\n logger.warn(\n { err: cached.err, packageName, registryFetchUrl },\n 'Previous git clone failed, bailing out.',\n );\n return null;\n }\n\n if (cached?.clonePath) {\n registry.clonePath = cached.clonePath;\n return registry;\n }\n\n const clonePath = upath.join(\n privateCacheDir(),\n CrateDatasource.cacheDirFromUrl(url),\n );\n\n const result = await CrateDatasource.clone(\n registryFetchUrl,\n clonePath,\n packageName,\n );\n\n memCache.set(cacheKey, result);\n\n if (result.err) {\n logger.warn(\n { err: result.err, packageName, registryFetchUrl },\n 'Git clone failed, bailing out.',\n );\n return null;\n }\n\n registry.clonePath = result.clonePath;\n } finally {\n releaseLock();\n }\n }\n\n return registry;\n }\n\n private static async clone(\n registryFetchUrl: string,\n clonePath: string,\n packageName: string,\n ): Promise<CloneResult> {\n logger.info(\n { clonePath, registryFetchUrl },\n `Cloning private cargo registry`,\n );\n\n const git = createSimpleGit({\n config: { maxConcurrentProcesses: 1 },\n ...(isHttpUrl(registryFetchUrl) && {\n // the URL as well, for the credentials registered from it, which only apply to this registry\n authentication: {\n hostTypes: [CrateDatasource.id],\n url: registryFetchUrl,\n },\n }),\n });\n\n try {\n await git.clone(registryFetchUrl, clonePath, {\n '--depth': 1,\n });\n return { clonePath };\n } catch (err) {\n if (\n err.message.includes(\n 'fatal: dumb http transport does not support shallow capabilities',\n )\n ) {\n logger.info(\n { packageName, registryFetchUrl },\n 'failed to shallow clone git registry, doing full clone',\n );\n try {\n await git.clone(registryFetchUrl, clonePath);\n return { clonePath };\n } catch (err) {\n logger.warn(\n { err, packageName, registryFetchUrl },\n 'failed cloning git registry',\n );\n return { err };\n }\n } else {\n logger.warn(\n { err, packageName, registryFetchUrl },\n 'failed cloning git registry',\n );\n return { err };\n }\n }\n }\n\n private static isCratesIo(registryUrl: string | undefined): boolean {\n if (!registryUrl) {\n return false;\n }\n const normalized = registryUrl.replace(regEx(/^sparse\\+/), '');\n const parsed = parseUrl(normalized);\n return parsed?.hostname === 'index.crates.io';\n }\n\n public static getIndexSuffix(packageName: string): string[] {\n const len = packageName.length;\n\n if (len === 1) {\n return ['1', packageName];\n }\n if (len === 2) {\n return ['2', packageName];\n }\n if (len === 3) {\n return ['3', packageName[0], packageName];\n }\n\n return [packageName.slice(0, 2), packageName.slice(2, 4), packageName];\n }\n\n private async _postprocessRelease(\n { packageName, registryUrl }: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult> {\n if (release.releaseTimestamp) {\n return release;\n }\n\n // Look up the registry config from cache (populated during getReleases)\n const rawUrl = registryUrl?.replace(regEx(/^sparse\\+/), '');\n if (!rawUrl) {\n return release;\n }\n const config = memCache.get<RegistryConfig>(\n CrateDatasource.registryConfigCacheKey(rawUrl),\n );\n if (!config?.api) {\n return release;\n }\n\n const { api } = config;\n if (await this.isReadApiUnsupported(api)) {\n return release;\n }\n\n const apiBaseUrl = joinUrlParts(api, 'api/v1/');\n const url = `${apiBaseUrl}crates/${packageName}/${release.versionOrig ?? release.version}`;\n logger.trace(\n { url, packageName, version: release.version, registryUrl },\n 'fetching crate release timestamp',\n );\n // Getting release timestamp could become unnecessary if the manual backfill of `pubtime` mentioned in\n // https://github.com/rust-lang/cargo/issues/15491 is done for all packages.\n try {\n const { body: releaseTimestamp } = await this.http.getJson(\n url,\n { cacheProvider: memCacheProvider },\n ReleaseTimestamp,\n );\n release.releaseTimestamp = releaseTimestamp;\n } catch (err) {\n if (\n CrateDatasource.isCratesIoApi(api) ||\n !CrateDatasource.isNotFound(err)\n ) {\n throw err;\n }\n await this.markReadApiUnsupported(rawUrl, api);\n }\n return release;\n }\n\n override postprocessRelease(\n config: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult> {\n return withCache(\n {\n namespace: `datasource-crate`,\n key: buildCacheKey(\n 'postprocessRelease',\n config.registryUrl,\n config.packageName,\n release.version,\n ),\n ttlMinutes: 7 * 24 * 60,\n public: CrateDatasource.isCratesIo(config.registryUrl ?? undefined),\n },\n () => this._postprocessRelease(config, release),\n );\n }\n}\n"],"mappings":"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"}
@@ -51,7 +51,8 @@ var DartVersionDatasource = class DartVersionDatasource extends Datasource {
51
51
  }
52
52
  getReleasesFromResponse(channel, prefixes) {
53
53
  return prefixes.map((prefix) => this.getVersionFromPrefix(prefix)).filter(isString).filter((version) => {
54
- if (version === "latest" || svnVersionRegex.test(version) || channel !== "stable" && stableVersionRegex.test(version)) return false;
54
+ const isStableAsNonStable = channel !== "stable" && stableVersionRegex.test(version);
55
+ if (version === "latest" || svnVersionRegex.test(version) || isStableAsNonStable) return false;
55
56
  return true;
56
57
  }).map((version) => ({
57
58
  version,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../lib/modules/datasource/dart-version/index.ts"],"sourcesContent":["import { isString } from '@sindresorhus/is';\nimport { regEx } from '../../../util/regex.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport { DartResponse } from './schema.ts';\n\nexport const stableVersionRegex = regEx(/^\\d+\\.\\d+\\.\\d+$/);\n/**\n * The server returns old svn versions which would need mapping to a version.\n * They are very old, so we skip them instead.\n * https://github.com/dart-lang/site-www/blob/7d4409c87bb6570b2d8870b20283f81f2b7e08fc/tool/get-dart/dart_sdk_archive/lib/src/svn_versions.dart#L2\n */\nexport const svnVersionRegex = regEx(/^\\d+$/);\n\nexport class DartVersionDatasource extends Datasource {\n static readonly id = 'dart-version';\n\n constructor() {\n super(DartVersionDatasource.id);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return false;\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['https://storage.googleapis.com'];\n }\n\n override readonly caching = true;\n\n private readonly channels = ['stable', 'beta', 'dev'];\n\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'We use the URL: https://github.com/dart-lang/sdk.';\n\n async getReleases({\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n /* v8 ignore next -- should never happen */\n if (!registryUrl) {\n return null;\n }\n const result: ReleaseResult = {\n homepage: 'https://dart.dev/',\n sourceUrl: 'https://github.com/dart-lang/sdk',\n registryUrl,\n releases: [],\n };\n try {\n for (const channel of this.channels) {\n const resp = (\n await this.http.getJson(\n `${registryUrl}/storage/v1/b/dart-archive/o?delimiter=%2F&prefix=channels%2F${channel}%2Frelease%2F&alt=json`,\n DartResponse,\n )\n ).body;\n const releases = this.getReleasesFromResponse(channel, resp.prefixes);\n result.releases.push(...releases);\n }\n } catch (err) {\n this.handleGenericErrors(err);\n }\n\n return result.releases.length ? result : null;\n }\n\n private getReleasesFromResponse(\n channel: string,\n prefixes: string[],\n ): Release[] {\n return prefixes\n .map((prefix) => this.getVersionFromPrefix(prefix))\n .filter(isString)\n .filter((version) => {\n if (\n version === 'latest' ||\n // skip old svn versions\n svnVersionRegex.test(version) ||\n // The API response contains a stable version being released as a non-stable\n // release. So we filter out these releases here.\n (channel !== 'stable' && stableVersionRegex.test(version))\n ) {\n return false;\n }\n return true;\n })\n .map((version) => ({ version, isStable: channel === 'stable' }));\n }\n\n // Prefix should have a format of \"channels/stable/release/2.9.3/\"\n private getVersionFromPrefix(prefix: string): string | undefined {\n const parts = prefix.split('/');\n return parts.at(-2);\n }\n}\n"],"mappings":";;;;;AAMA,MAAa,qBAAqB,MAAM,iBAAiB;;;;;;AAMzD,MAAa,kBAAkB,MAAM,OAAO;AAE5C,IAAa,wBAAb,MAAa,8BAA8B,WAAW;CACpD,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,sBAAsB,EAAE;CAChC;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,gCAAgC;CAC1C;CAEA,UAA4B;CAE5B,WAA4B;EAAC;EAAU;EAAQ;CAAK;CAEpD,mBAAqC;CACrC,gBACE;CAEF,MAAM,YAAY,EAChB,eACmD;;EAEnD,IAAI,CAAC,aACH,OAAO;EAET,MAAM,SAAwB;GAC5B,UAAU;GACV,WAAW;GACX;GACA,UAAU,CAAC;EACb;EACA,IAAI;GACF,KAAK,MAAM,WAAW,KAAK,UAAU;IACnC,MAAM,QACJ,MAAM,KAAK,KAAK,QACd,GAAG,YAAY,+DAA+D,QAAQ,yBACtF,YACF,EAAA,CACA;IACF,MAAM,WAAW,KAAK,wBAAwB,SAAS,KAAK,QAAQ;IACpE,OAAO,SAAS,KAAK,GAAG,QAAQ;GAClC;EACF,SAAS,KAAK;GACZ,KAAK,oBAAoB,GAAG;EAC9B;EAEA,OAAO,OAAO,SAAS,SAAS,SAAS;CAC3C;CAEA,wBACE,SACA,UACW;EACX,OAAO,SACJ,KAAK,WAAW,KAAK,qBAAqB,MAAM,CAAC,CAAC,CAClD,OAAO,QAAQ,CAAC,CAChB,QAAQ,YAAY;GACnB,IACE,YAAY,YAEZ,gBAAgB,KAAK,OAAO,KAG3B,YAAY,YAAY,mBAAmB,KAAK,OAAO,GAExD,OAAO;GAET,OAAO;EACT,CAAC,CAAC,CACD,KAAK,aAAa;GAAE;GAAS,UAAU,YAAY;EAAS,EAAE;CACnE;CAGA,qBAA6B,QAAoC;EAE/D,OADc,OAAO,MAAM,GAChB,CAAC,CAAC,GAAG,EAAE;CACpB;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../lib/modules/datasource/dart-version/index.ts"],"sourcesContent":["import { isString } from '@sindresorhus/is';\nimport { regEx } from '../../../util/regex.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport { DartResponse } from './schema.ts';\n\nexport const stableVersionRegex = regEx(/^\\d+\\.\\d+\\.\\d+$/);\n/**\n * The server returns old svn versions which would need mapping to a version.\n * They are very old, so we skip them instead.\n * https://github.com/dart-lang/site-www/blob/7d4409c87bb6570b2d8870b20283f81f2b7e08fc/tool/get-dart/dart_sdk_archive/lib/src/svn_versions.dart#L2\n */\nexport const svnVersionRegex = regEx(/^\\d+$/);\n\nexport class DartVersionDatasource extends Datasource {\n static readonly id = 'dart-version';\n\n constructor() {\n super(DartVersionDatasource.id);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return false;\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['https://storage.googleapis.com'];\n }\n\n override readonly caching = true;\n\n private readonly channels = ['stable', 'beta', 'dev'];\n\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'We use the URL: https://github.com/dart-lang/sdk.';\n\n async getReleases({\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n /* v8 ignore next -- should never happen */\n if (!registryUrl) {\n return null;\n }\n const result: ReleaseResult = {\n homepage: 'https://dart.dev/',\n sourceUrl: 'https://github.com/dart-lang/sdk',\n registryUrl,\n releases: [],\n };\n try {\n for (const channel of this.channels) {\n const resp = (\n await this.http.getJson(\n `${registryUrl}/storage/v1/b/dart-archive/o?delimiter=%2F&prefix=channels%2F${channel}%2Frelease%2F&alt=json`,\n DartResponse,\n )\n ).body;\n const releases = this.getReleasesFromResponse(channel, resp.prefixes);\n result.releases.push(...releases);\n }\n } catch (err) {\n this.handleGenericErrors(err);\n }\n\n return result.releases.length ? result : null;\n }\n\n private getReleasesFromResponse(\n channel: string,\n prefixes: string[],\n ): Release[] {\n return prefixes\n .map((prefix) => this.getVersionFromPrefix(prefix))\n .filter(isString)\n .filter((version) => {\n // The API response contains a stable version being released as a non-stable\n // release. So we filter out these releases here.\n const isStableAsNonStable =\n channel !== 'stable' && stableVersionRegex.test(version);\n if (\n version === 'latest' ||\n // skip old svn versions\n svnVersionRegex.test(version) ||\n isStableAsNonStable\n ) {\n return false;\n }\n return true;\n })\n .map((version) => ({ version, isStable: channel === 'stable' }));\n }\n\n // Prefix should have a format of \"channels/stable/release/2.9.3/\"\n private getVersionFromPrefix(prefix: string): string | undefined {\n const parts = prefix.split('/');\n return parts.at(-2);\n }\n}\n"],"mappings":";;;;;AAMA,MAAa,qBAAqB,MAAM,iBAAiB;;;;;;AAMzD,MAAa,kBAAkB,MAAM,OAAO;AAE5C,IAAa,wBAAb,MAAa,8BAA8B,WAAW;CACpD,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,sBAAsB,EAAE;CAChC;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,gCAAgC;CAC1C;CAEA,UAA4B;CAE5B,WAA4B;EAAC;EAAU;EAAQ;CAAK;CAEpD,mBAAqC;CACrC,gBACE;CAEF,MAAM,YAAY,EAChB,eACmD;;EAEnD,IAAI,CAAC,aACH,OAAO;EAET,MAAM,SAAwB;GAC5B,UAAU;GACV,WAAW;GACX;GACA,UAAU,CAAC;EACb;EACA,IAAI;GACF,KAAK,MAAM,WAAW,KAAK,UAAU;IACnC,MAAM,QACJ,MAAM,KAAK,KAAK,QACd,GAAG,YAAY,+DAA+D,QAAQ,yBACtF,YACF,EAAA,CACA;IACF,MAAM,WAAW,KAAK,wBAAwB,SAAS,KAAK,QAAQ;IACpE,OAAO,SAAS,KAAK,GAAG,QAAQ;GAClC;EACF,SAAS,KAAK;GACZ,KAAK,oBAAoB,GAAG;EAC9B;EAEA,OAAO,OAAO,SAAS,SAAS,SAAS;CAC3C;CAEA,wBACE,SACA,UACW;EACX,OAAO,SACJ,KAAK,WAAW,KAAK,qBAAqB,MAAM,CAAC,CAAC,CAClD,OAAO,QAAQ,CAAC,CAChB,QAAQ,YAAY;GAGnB,MAAM,sBACJ,YAAY,YAAY,mBAAmB,KAAK,OAAO;GACzD,IACE,YAAY,YAEZ,gBAAgB,KAAK,OAAO,KAC5B,qBAEA,OAAO;GAET,OAAO;EACT,CAAC,CAAC,CACD,KAAK,aAAa;GAAE;GAAS,UAAU,YAAY;EAAS,EAAE;CACnE;CAGA,qBAA6B,QAAoC;EAE/D,OADc,OAAO,MAAM,GAChB,CAAC,CAAC,GAAG,EAAE;CACpB;AACF"}
@@ -1,5 +1,6 @@
1
1
  import { coerceObject } from "../../util/object.js";
2
2
  import { logger } from "../../logger/index.js";
3
+ import { isRateLimitedOrServerError } from "../../util/http/status.js";
3
4
  import { ExternalHostError } from "../../types/errors/external-host-error.js";
4
5
  import { withCache } from "../../util/cache/package/with-cache.js";
5
6
  import { RequestError } from "../../util/http/got.js";
@@ -95,8 +96,7 @@ var Datasource = class {
95
96
  if (err instanceof ExternalHostError) throw err;
96
97
  if (err instanceof RequestError) {
97
98
  this.handleHttpErrors(err);
98
- const statusCode = err.response?.statusCode;
99
- if (statusCode && (statusCode === 429 || statusCode >= 500 && statusCode < 600)) throw new ExternalHostError(err);
99
+ if (isRateLimitedOrServerError(err)) throw new ExternalHostError(err);
100
100
  }
101
101
  throw err;
102
102
  }
@@ -1 +1 @@
1
- {"version":3,"file":"datasource.js","names":["HttpError"],"sources":["../../../lib/modules/datasource/datasource.ts"],"sourcesContent":["import type { ZodType, z } from 'zod/v4';\nimport { ZodError } from 'zod/v4';\nimport { logger } from '../../logger/index.ts';\nimport { ExternalHostError } from '../../types/errors/external-host-error.ts';\nimport type { PackageCacheNamespace } from '../../util/cache/package/types.ts';\nimport type {\n CacheContext,\n CachedOptions,\n} from '../../util/cache/package/with-cache.ts';\nimport { withCache } from '../../util/cache/package/with-cache.ts';\nimport type { HttpBase } from '../../util/http/http.ts';\nimport { Http, HttpError } from '../../util/http/index.ts';\nimport type { HttpOptions } from '../../util/http/types.ts';\nimport { coerceObject } from '../../util/object.ts';\nimport type {\n DatasourceApi,\n DigestConfig,\n GetReleasesConfig,\n PostprocessReleaseConfig,\n PostprocessReleaseResult,\n RegistryStrategy,\n Release,\n ReleaseResult,\n SourceUrlSupport,\n} from './types.ts';\n\n/**\n * The options accepted by the JSON methods of the http client `H`:\n * `HttpOptions` for the plain client, and the client's own options type for a\n * specialised one such as `GithubHttp`.\n */\ntype JsonOptions<H extends Http> =\n H extends HttpBase<infer Opts, any> ? Opts : HttpOptions;\n\nexport abstract class Datasource<\n H extends Http = Http,\n> implements DatasourceApi {\n public readonly id: string;\n\n /**\n * The package cache namespace used by {@link Datasource.cached}.\n * Defaults to `datasource-<id>`, which must be registered in\n * `packageCacheNamespaces`.\n */\n protected readonly cacheNamespace: PackageCacheNamespace;\n\n /**\n * A subclass that narrows `H` to a specialised client (`GithubHttp`,\n * `GitlabHttp`, ...) must construct that client itself and pass it as\n * `http`, since this constructor can only build the plain `Http` default.\n */\n protected constructor(id: string, http?: H) {\n this.id = id;\n this.http = http ?? (new Http(id) as H);\n this.cacheNamespace = `datasource-${id}` as PackageCacheNamespace;\n }\n\n caching: boolean | undefined;\n\n defaultConfig: Record<string, unknown> | undefined;\n\n getDefaultRegistryUrls(_packageName: string): string[] | undefined {\n return undefined;\n }\n\n supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n\n defaultVersioning?: string | undefined;\n\n registryStrategy: RegistryStrategy = 'first';\n\n releaseTimestampSupport = false;\n releaseTimestampNote?: string | undefined;\n\n sourceUrlSupport: SourceUrlSupport = 'none';\n sourceUrlNote?: string | undefined;\n\n protected readonly http: H;\n\n abstract getReleases(\n getReleasesConfig: GetReleasesConfig,\n ): Promise<ReleaseResult | null>;\n\n /**\n * `newValue` may be `undefined`, for example when only the digest of the\n * current value is being resolved. Implementations must handle that case\n * explicitly, for example by resolving the digest of a default branch or\n * by returning `null`.\n */\n getDigest?(config: DigestConfig, newValue?: string): Promise<string | null>;\n\n postprocessRelease?(\n config: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult>;\n\n handleHttpErrors(_err: HttpError): void {\n // intentionally empty\n }\n\n /**\n * Caches the result of `fn` in the datasource cache namespace.\n *\n * Same as {@link withCache}, except that `namespace` defaults to\n * {@link Datasource.cacheNamespace}.\n */\n protected cached<T>(\n options: Omit<CachedOptions, 'namespace'> & {\n namespace?: PackageCacheNamespace;\n },\n fn: (ctx: CacheContext) => T | PromiseLike<T>,\n ): Promise<Awaited<T>> {\n return withCache(\n { ...options, namespace: options.namespace ?? this.cacheNamespace },\n fn,\n );\n }\n\n /**\n * Requests `url` and returns the response body validated by `schema`.\n *\n * Every error, a response that fails validation included, goes through\n * {@link Datasource.handleGenericErrors} and therefore fails the lookup. Use\n * it when a malformed response must be treated as an error; use\n * {@link Datasource.fetchJsonOrNull} when it should count as \"no data from\n * this registry\" instead.\n */\n protected async fetchJson<Schema extends ZodType<any, any, any>>(\n url: string,\n schema: Schema,\n options?: JsonOptions<H>,\n ): Promise<z.infer<Schema>> {\n const httpOptions = coerceObject(options) as HttpOptions;\n try {\n const { body } = await this.http.getJson(url, httpOptions, schema);\n return body;\n } catch (err) {\n this.handleGenericErrors(err);\n }\n }\n\n /**\n * Same as {@link Datasource.fetchJson}, except that a response which fails\n * schema validation is logged and reported as `null`.\n *\n * Use it when a malformed response means \"no data from this registry\" rather\n * than a failed lookup. Every other error still goes through\n * {@link Datasource.handleGenericErrors}.\n */\n protected async fetchJsonOrNull<Schema extends ZodType<any, any, any>>(\n url: string,\n schema: Schema,\n options?: JsonOptions<H>,\n ): Promise<z.infer<Schema> | null> {\n try {\n return await this.fetchJson(url, schema, options);\n } catch (err) {\n if (err instanceof ZodError) {\n logger.debug(\n { err, datasource: this.id, url },\n 'Ignoring response that failed schema validation',\n );\n return null;\n }\n\n throw err;\n }\n }\n\n protected handleGenericErrors(err: Error): never {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n\n if (err instanceof HttpError) {\n this.handleHttpErrors(err);\n\n const statusCode = err.response?.statusCode;\n if (\n statusCode &&\n (statusCode === 429 || (statusCode >= 500 && statusCode < 600))\n ) {\n throw new ExternalHostError(err);\n }\n }\n\n throw err;\n }\n}\n"],"mappings":";;;;;;;;AAkCA,IAAsB,aAAtB,MAE2B;CACzB;;;;;;CAOA;;;;;;CAOA,YAAsB,IAAY,MAAU;EAC1C,KAAK,KAAK;EACV,KAAK,OAAO,QAAS,IAAI,KAAK,EAAE;EAChC,KAAK,iBAAiB,cAAc;CACtC;CAEA;CAEA;CAEA,uBAAuB,cAA4C,CAEnE;CAEA,uBAAuB,cAA+B;EACpD,OAAO;CACT;CAEA;CAEA,mBAAqC;CAErC,0BAA0B;CAC1B;CAEA,mBAAqC;CACrC;CAEA;CAmBA,iBAAiB,MAAuB,CAExC;;;;;;;CAQA,OACE,SAGA,IACqB;EACrB,OAAO,UACL;GAAE,GAAG;GAAS,WAAW,QAAQ,aAAa,KAAK;EAAe,GAClE,EACF;CACF;;;;;;;;;;CAWA,MAAgB,UACd,KACA,QACA,SAC0B;EAC1B,MAAM,cAAc,aAAa,OAAO;EACxC,IAAI;GACF,MAAM,EAAE,SAAS,MAAM,KAAK,KAAK,QAAQ,KAAK,aAAa,MAAM;GACjE,OAAO;EACT,SAAS,KAAK;GACZ,KAAK,oBAAoB,GAAG;EAC9B;CACF;;;;;;;;;CAUA,MAAgB,gBACd,KACA,QACA,SACiC;EACjC,IAAI;GACF,OAAO,MAAM,KAAK,UAAU,KAAK,QAAQ,OAAO;EAClD,SAAS,KAAK;GACZ,IAAI,eAAe,UAAU;IAC3B,OAAO,MACL;KAAE;KAAK,YAAY,KAAK;KAAI;IAAI,GAChC,iDACF;IACA,OAAO;GACT;GAEA,MAAM;EACR;CACF;CAEA,oBAA8B,KAAmB;EAC/C,IAAI,eAAe,mBACjB,MAAM;EAGR,IAAI,eAAeA,cAAW;GAC5B,KAAK,iBAAiB,GAAG;GAEzB,MAAM,aAAa,IAAI,UAAU;GACjC,IACE,eACC,eAAe,OAAQ,cAAc,OAAO,aAAa,MAE1D,MAAM,IAAI,kBAAkB,GAAG;EAEnC;EAEA,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"datasource.js","names":["HttpError"],"sources":["../../../lib/modules/datasource/datasource.ts"],"sourcesContent":["import type { ZodType, z } from 'zod/v4';\nimport { ZodError } from 'zod/v4';\nimport { logger } from '../../logger/index.ts';\nimport { ExternalHostError } from '../../types/errors/external-host-error.ts';\nimport type { PackageCacheNamespace } from '../../util/cache/package/types.ts';\nimport type {\n CacheContext,\n CachedOptions,\n} from '../../util/cache/package/with-cache.ts';\nimport { withCache } from '../../util/cache/package/with-cache.ts';\nimport type { HttpBase } from '../../util/http/http.ts';\nimport { Http, HttpError } from '../../util/http/index.ts';\nimport { isRateLimitedOrServerError } from '../../util/http/status.ts';\nimport type { HttpOptions } from '../../util/http/types.ts';\nimport { coerceObject } from '../../util/object.ts';\nimport type {\n DatasourceApi,\n DigestConfig,\n GetReleasesConfig,\n PostprocessReleaseConfig,\n PostprocessReleaseResult,\n RegistryStrategy,\n Release,\n ReleaseResult,\n SourceUrlSupport,\n} from './types.ts';\n\n/**\n * The options accepted by the JSON methods of the http client `H`:\n * `HttpOptions` for the plain client, and the client's own options type for a\n * specialised one such as `GithubHttp`.\n */\ntype JsonOptions<H extends Http> =\n H extends HttpBase<infer Opts, any> ? Opts : HttpOptions;\n\nexport abstract class Datasource<\n H extends Http = Http,\n> implements DatasourceApi {\n public readonly id: string;\n\n /**\n * The package cache namespace used by {@link Datasource.cached}.\n * Defaults to `datasource-<id>`, which must be registered in\n * `packageCacheNamespaces`.\n */\n protected readonly cacheNamespace: PackageCacheNamespace;\n\n /**\n * A subclass that narrows `H` to a specialised client (`GithubHttp`,\n * `GitlabHttp`, ...) must construct that client itself and pass it as\n * `http`, since this constructor can only build the plain `Http` default.\n */\n protected constructor(id: string, http?: H) {\n this.id = id;\n this.http = http ?? (new Http(id) as H);\n this.cacheNamespace = `datasource-${id}` as PackageCacheNamespace;\n }\n\n caching: boolean | undefined;\n\n defaultConfig: Record<string, unknown> | undefined;\n\n getDefaultRegistryUrls(_packageName: string): string[] | undefined {\n return undefined;\n }\n\n supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n\n defaultVersioning?: string | undefined;\n\n registryStrategy: RegistryStrategy = 'first';\n\n releaseTimestampSupport = false;\n releaseTimestampNote?: string | undefined;\n\n sourceUrlSupport: SourceUrlSupport = 'none';\n sourceUrlNote?: string | undefined;\n\n protected readonly http: H;\n\n abstract getReleases(\n getReleasesConfig: GetReleasesConfig,\n ): Promise<ReleaseResult | null>;\n\n /**\n * `newValue` may be `undefined`, for example when only the digest of the\n * current value is being resolved. Implementations must handle that case\n * explicitly, for example by resolving the digest of a default branch or\n * by returning `null`.\n */\n getDigest?(config: DigestConfig, newValue?: string): Promise<string | null>;\n\n postprocessRelease?(\n config: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult>;\n\n handleHttpErrors(_err: HttpError): void {\n // intentionally empty\n }\n\n /**\n * Caches the result of `fn` in the datasource cache namespace.\n *\n * Same as {@link withCache}, except that `namespace` defaults to\n * {@link Datasource.cacheNamespace}.\n */\n protected cached<T>(\n options: Omit<CachedOptions, 'namespace'> & {\n namespace?: PackageCacheNamespace;\n },\n fn: (ctx: CacheContext) => T | PromiseLike<T>,\n ): Promise<Awaited<T>> {\n return withCache(\n { ...options, namespace: options.namespace ?? this.cacheNamespace },\n fn,\n );\n }\n\n /**\n * Requests `url` and returns the response body validated by `schema`.\n *\n * Every error, a response that fails validation included, goes through\n * {@link Datasource.handleGenericErrors} and therefore fails the lookup. Use\n * it when a malformed response must be treated as an error; use\n * {@link Datasource.fetchJsonOrNull} when it should count as \"no data from\n * this registry\" instead.\n */\n protected async fetchJson<Schema extends ZodType<any, any, any>>(\n url: string,\n schema: Schema,\n options?: JsonOptions<H>,\n ): Promise<z.infer<Schema>> {\n const httpOptions = coerceObject(options) as HttpOptions;\n try {\n const { body } = await this.http.getJson(url, httpOptions, schema);\n return body;\n } catch (err) {\n this.handleGenericErrors(err);\n }\n }\n\n /**\n * Same as {@link Datasource.fetchJson}, except that a response which fails\n * schema validation is logged and reported as `null`.\n *\n * Use it when a malformed response means \"no data from this registry\" rather\n * than a failed lookup. Every other error still goes through\n * {@link Datasource.handleGenericErrors}.\n */\n protected async fetchJsonOrNull<Schema extends ZodType<any, any, any>>(\n url: string,\n schema: Schema,\n options?: JsonOptions<H>,\n ): Promise<z.infer<Schema> | null> {\n try {\n return await this.fetchJson(url, schema, options);\n } catch (err) {\n if (err instanceof ZodError) {\n logger.debug(\n { err, datasource: this.id, url },\n 'Ignoring response that failed schema validation',\n );\n return null;\n }\n\n throw err;\n }\n }\n\n protected handleGenericErrors(err: Error): never {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n\n if (err instanceof HttpError) {\n this.handleHttpErrors(err);\n\n if (isRateLimitedOrServerError(err)) {\n throw new ExternalHostError(err);\n }\n }\n\n throw err;\n }\n}\n"],"mappings":";;;;;;;;;AAmCA,IAAsB,aAAtB,MAE2B;CACzB;;;;;;CAOA;;;;;;CAOA,YAAsB,IAAY,MAAU;EAC1C,KAAK,KAAK;EACV,KAAK,OAAO,QAAS,IAAI,KAAK,EAAE;EAChC,KAAK,iBAAiB,cAAc;CACtC;CAEA;CAEA;CAEA,uBAAuB,cAA4C,CAEnE;CAEA,uBAAuB,cAA+B;EACpD,OAAO;CACT;CAEA;CAEA,mBAAqC;CAErC,0BAA0B;CAC1B;CAEA,mBAAqC;CACrC;CAEA;CAmBA,iBAAiB,MAAuB,CAExC;;;;;;;CAQA,OACE,SAGA,IACqB;EACrB,OAAO,UACL;GAAE,GAAG;GAAS,WAAW,QAAQ,aAAa,KAAK;EAAe,GAClE,EACF;CACF;;;;;;;;;;CAWA,MAAgB,UACd,KACA,QACA,SAC0B;EAC1B,MAAM,cAAc,aAAa,OAAO;EACxC,IAAI;GACF,MAAM,EAAE,SAAS,MAAM,KAAK,KAAK,QAAQ,KAAK,aAAa,MAAM;GACjE,OAAO;EACT,SAAS,KAAK;GACZ,KAAK,oBAAoB,GAAG;EAC9B;CACF;;;;;;;;;CAUA,MAAgB,gBACd,KACA,QACA,SACiC;EACjC,IAAI;GACF,OAAO,MAAM,KAAK,UAAU,KAAK,QAAQ,OAAO;EAClD,SAAS,KAAK;GACZ,IAAI,eAAe,UAAU;IAC3B,OAAO,MACL;KAAE;KAAK,YAAY,KAAK;KAAI;IAAI,GAChC,iDACF;IACA,OAAO;GACT;GAEA,MAAM;EACR;CACF;CAEA,oBAA8B,KAAmB;EAC/C,IAAI,eAAe,mBACjB,MAAM;EAGR,IAAI,eAAeA,cAAW;GAC5B,KAAK,iBAAiB,GAAG;GAEzB,IAAI,2BAA2B,GAAG,GAChC,MAAM,IAAI,kBAAkB,GAAG;EAEnC;EAEA,MAAM;CACR;AACF"}
@@ -1,5 +1,6 @@
1
1
  import { logger } from "../../../logger/index.js";
2
2
  import { joinUrlParts, parseUrl } from "../../../util/url.js";
3
+ import { isNotModified } from "../../../util/http/status.js";
3
4
  // lib/modules/datasource/deb/url.ts
4
5
  /**
5
6
  * Extracts the base suite URL from a package URL by removing the last two path segments.
@@ -77,7 +78,8 @@ function getReleaseParam(url, optionalParams) {
77
78
  async function checkIfModified(packageUrl, lastDownloadTimestamp, http) {
78
79
  const options = { headers: { "If-Modified-Since": lastDownloadTimestamp.toUTCString() } };
79
80
  try {
80
- return (await http.head(packageUrl, options)).statusCode !== 304;
81
+ const response = await http.head(packageUrl, options);
82
+ return !isNotModified(response);
81
83
  } catch (error) {
82
84
  logger.warn({
83
85
  packageUrl,
@@ -1 +1 @@
1
- {"version":3,"file":"url.js","names":[],"sources":["../../../../lib/modules/datasource/deb/url.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport type { Http, HttpOptions } from '../../../util/http/index.ts';\nimport { joinUrlParts, parseUrl } from '../../../util/url.ts';\n\n/**\n * Extracts the base suite URL from a package URL by removing the last two path segments.\n *\n * @param basePackageUrl - The base URL of the package.\n * @returns The base suite URL.\n *\n * @example\n * // Returns 'https://deb.debian.org/debian/dists/bullseye'\n * getBaseReleaseUrl('https://deb.debian.org/debian/dists/bullseye/main/binary-amd64');\n */\nexport function getBaseSuiteUrl(basePackageUrl: string): string {\n const urlParts = basePackageUrl.split('/');\n return urlParts.slice(0, urlParts.length - 2).join('/');\n}\n\n/**\n * Constructs the component URLs from the given registry URL.\n *\n * @param registryUrl - The base URL of the registry.\n * @returns An array of component URLs.\n * @throws Will throw an error if required parameters are missing from the URL.\n */\nexport function constructComponentUrls(registryUrl: string): string[] {\n const REQUIRED_PARAMS = ['components', 'binaryArch'];\n const OPTIONAL_PARAMS = ['suite', 'release'];\n\n try {\n const url = parseUrl(registryUrl);\n if (!url) {\n return [];\n }\n validateUrlAndParams(url, REQUIRED_PARAMS);\n\n const suite = getReleaseParam(url, OPTIONAL_PARAMS);\n const binaryArch = url.searchParams.get('binaryArch');\n const components = url.searchParams.get('components')!.split(',');\n\n // Clean up URL search parameters for constructing new URLs\n [...REQUIRED_PARAMS, ...OPTIONAL_PARAMS].forEach((param) =>\n url.searchParams.delete(param),\n );\n\n return components.map((component) =>\n joinUrlParts(\n url.toString(),\n `dists`,\n suite,\n component,\n `binary-${binaryArch}`,\n ),\n );\n } catch (error) {\n throw new Error(\n `Invalid deb repo URL: ${registryUrl} - see documentation: ${error.message}`,\n );\n }\n}\n\n/**\n * Validates that the required parameters are present in the URL.\n *\n * @param url - The URL to validate.\n * @param requiredParams - The list of required query parameters.\n * @throws Will throw an error if a required parameter is missing.\n */\nfunction validateUrlAndParams(url: URL, requiredParams: string[]): void {\n for (const param of requiredParams) {\n if (!url.searchParams.has(param)) {\n throw new Error(`Missing required query parameter '${param}'`);\n }\n }\n}\n\n/**\n * Retrieves the suite parameter from the URL.\n *\n * @param url - The URL to retrieve the suite parameter from.\n * @param optionalParams - The list of optional query parameters.\n * @returns The value of the suite parameter.\n * @throws Will throw an error if none of the optional parameters are found.\n */\nfunction getReleaseParam(url: URL, optionalParams: string[]): string {\n for (const param of optionalParams) {\n const paramValue = url.searchParams.get(param);\n if (paramValue !== null) {\n if (param === 'release') {\n logger.debug(\n 'Deprecation notice. Use `suite` instead of `release` for deb repo URLs',\n );\n }\n return paramValue;\n }\n }\n throw new Error(`Missing one of suite query parameter`);\n}\n\n/**\n * Checks if a packageUrl content has been modified since the specified timestamp.\n *\n * @param packageUrl - The URL to check.\n * @param lastDownloadTimestamp - The timestamp of the last download.\n * @returns True if the content has been modified, otherwise false.\n * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since\n */\nexport async function checkIfModified(\n packageUrl: string,\n lastDownloadTimestamp: Date,\n http: Http,\n): Promise<boolean> {\n const options: HttpOptions = {\n headers: {\n 'If-Modified-Since': lastDownloadTimestamp.toUTCString(),\n },\n };\n\n try {\n const response = await http.head(packageUrl, options);\n return response.statusCode !== 304;\n } catch (error) {\n logger.warn(\n { packageUrl, lastDownloadTimestamp, errorMessage: error.message },\n 'Could not determine if package file is modified since last download',\n );\n return true; // Assume it needs to be downloaded if check fails\n }\n}\n\n/**\n * Constructs a URL for accessing the component directory for a specific release and architecture.\n *\n * @param baseUrl - The base URL of the repository.\n * @param release - The release name or codename (e.g., 'buster', 'bullseye').\n * @param component - The component name (e.g., 'main', 'contrib', 'non-free').\n * @param arch - The architecture name (e.g., 'amd64', 'i386').\n * @returns The complete URL to the component directory.\n */\nexport function getComponentUrl(\n baseUrl: string,\n release: string,\n component: string,\n arch: string,\n): string {\n return `${baseUrl}/debian/dists/${release}/${component}/binary-${arch}`;\n}\n\n/**\n * Constructs a URL for accessing the Packages.gz file for a specific component, release, and architecture.\n *\n * @param baseUrl - The base URL of the repository.\n * @param release - The release name or codename (e.g., 'buster', 'bullseye').\n * @param component - The component name (e.g., 'main', 'contrib', 'non-free').\n * @param arch - The architecture name (e.g., 'amd64', 'i386').\n * @returns The complete URL to the Packages.gz file.\n */\nexport function getPackageUrl(\n baseUrl: string,\n release: string,\n component: string,\n arch: string,\n): string {\n return `${getComponentUrl(baseUrl, release, component, arch)}/Packages.gz`;\n}\n\n/**\n * Constructs a URL used generating the component url with specific release, components, and architecture.\n *\n * @param baseUrl - The base URL of the repository.\n * @param release - The release name or codename (e.g., 'buster', 'bullseye').\n * @param components - An array of component names (e.g., ['main', 'contrib', 'non-free']).\n * @param arch - The architecture name (e.g., 'amd64', 'i386').\n * @returns The complete URL to the package registry.\n */\nexport function getRegistryUrl(\n baseUrl: string,\n release: string,\n components: string[],\n arch: string,\n): string {\n return `${baseUrl}/debian?suite=${release}&components=${components.join(',')}&binaryArch=${arch}`;\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,SAAgB,gBAAgB,gBAAgC;CAC9D,MAAM,WAAW,eAAe,MAAM,GAAG;CACzC,OAAO,SAAS,MAAM,GAAG,SAAS,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG;AACxD;;;;;;;;AASA,SAAgB,uBAAuB,aAA+B;CACpE,MAAM,kBAAkB,CAAC,cAAc,YAAY;CACnD,MAAM,kBAAkB,CAAC,SAAS,SAAS;CAE3C,IAAI;EACF,MAAM,MAAM,SAAS,WAAW;EAChC,IAAI,CAAC,KACH,OAAO,CAAC;EAEV,qBAAqB,KAAK,eAAe;EAEzC,MAAM,QAAQ,gBAAgB,KAAK,eAAe;EAClD,MAAM,aAAa,IAAI,aAAa,IAAI,YAAY;EACpD,MAAM,aAAa,IAAI,aAAa,IAAI,YAAY,CAAC,CAAE,MAAM,GAAG;EAGhE,CAAC,GAAG,iBAAiB,GAAG,eAAe,CAAC,CAAC,SAAS,UAChD,IAAI,aAAa,OAAO,KAAK,CAC/B;EAEA,OAAO,WAAW,KAAK,cACrB,aACE,IAAI,SAAS,GACb,SACA,OACA,WACA,UAAU,YACZ,CACF;CACF,SAAS,OAAO;EACd,MAAM,IAAI,MACR,yBAAyB,YAAY,wBAAwB,MAAM,SACrE;CACF;AACF;;;;;;;;AASA,SAAS,qBAAqB,KAAU,gBAAgC;CACtE,KAAK,MAAM,SAAS,gBAClB,IAAI,CAAC,IAAI,aAAa,IAAI,KAAK,GAC7B,MAAM,IAAI,MAAM,qCAAqC,MAAM,EAAE;AAGnE;;;;;;;;;AAUA,SAAS,gBAAgB,KAAU,gBAAkC;CACnE,KAAK,MAAM,SAAS,gBAAgB;EAClC,MAAM,aAAa,IAAI,aAAa,IAAI,KAAK;EAC7C,IAAI,eAAe,MAAM;GACvB,IAAI,UAAU,WACZ,OAAO,MACL,wEACF;GAEF,OAAO;EACT;CACF;CACA,MAAM,IAAI,MAAM,sCAAsC;AACxD;;;;;;;;;AAUA,eAAsB,gBACpB,YACA,uBACA,MACkB;CAClB,MAAM,UAAuB,EAC3B,SAAS,EACP,qBAAqB,sBAAsB,YAAY,EACzD,EACF;CAEA,IAAI;EAEF,QAAO,MADgB,KAAK,KAAK,YAAY,OAAO,EAAA,CACpC,eAAe;CACjC,SAAS,OAAO;EACd,OAAO,KACL;GAAE;GAAY;GAAuB,cAAc,MAAM;EAAQ,GACjE,qEACF;EACA,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"url.js","names":[],"sources":["../../../../lib/modules/datasource/deb/url.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport type { Http, HttpOptions } from '../../../util/http/index.ts';\nimport { isNotModified } from '../../../util/http/status.ts';\nimport { joinUrlParts, parseUrl } from '../../../util/url.ts';\n\n/**\n * Extracts the base suite URL from a package URL by removing the last two path segments.\n *\n * @param basePackageUrl - The base URL of the package.\n * @returns The base suite URL.\n *\n * @example\n * // Returns 'https://deb.debian.org/debian/dists/bullseye'\n * getBaseReleaseUrl('https://deb.debian.org/debian/dists/bullseye/main/binary-amd64');\n */\nexport function getBaseSuiteUrl(basePackageUrl: string): string {\n const urlParts = basePackageUrl.split('/');\n return urlParts.slice(0, urlParts.length - 2).join('/');\n}\n\n/**\n * Constructs the component URLs from the given registry URL.\n *\n * @param registryUrl - The base URL of the registry.\n * @returns An array of component URLs.\n * @throws Will throw an error if required parameters are missing from the URL.\n */\nexport function constructComponentUrls(registryUrl: string): string[] {\n const REQUIRED_PARAMS = ['components', 'binaryArch'];\n const OPTIONAL_PARAMS = ['suite', 'release'];\n\n try {\n const url = parseUrl(registryUrl);\n if (!url) {\n return [];\n }\n validateUrlAndParams(url, REQUIRED_PARAMS);\n\n const suite = getReleaseParam(url, OPTIONAL_PARAMS);\n const binaryArch = url.searchParams.get('binaryArch');\n const components = url.searchParams.get('components')!.split(',');\n\n // Clean up URL search parameters for constructing new URLs\n [...REQUIRED_PARAMS, ...OPTIONAL_PARAMS].forEach((param) =>\n url.searchParams.delete(param),\n );\n\n return components.map((component) =>\n joinUrlParts(\n url.toString(),\n `dists`,\n suite,\n component,\n `binary-${binaryArch}`,\n ),\n );\n } catch (error) {\n throw new Error(\n `Invalid deb repo URL: ${registryUrl} - see documentation: ${error.message}`,\n );\n }\n}\n\n/**\n * Validates that the required parameters are present in the URL.\n *\n * @param url - The URL to validate.\n * @param requiredParams - The list of required query parameters.\n * @throws Will throw an error if a required parameter is missing.\n */\nfunction validateUrlAndParams(url: URL, requiredParams: string[]): void {\n for (const param of requiredParams) {\n if (!url.searchParams.has(param)) {\n throw new Error(`Missing required query parameter '${param}'`);\n }\n }\n}\n\n/**\n * Retrieves the suite parameter from the URL.\n *\n * @param url - The URL to retrieve the suite parameter from.\n * @param optionalParams - The list of optional query parameters.\n * @returns The value of the suite parameter.\n * @throws Will throw an error if none of the optional parameters are found.\n */\nfunction getReleaseParam(url: URL, optionalParams: string[]): string {\n for (const param of optionalParams) {\n const paramValue = url.searchParams.get(param);\n if (paramValue !== null) {\n if (param === 'release') {\n logger.debug(\n 'Deprecation notice. Use `suite` instead of `release` for deb repo URLs',\n );\n }\n return paramValue;\n }\n }\n throw new Error(`Missing one of suite query parameter`);\n}\n\n/**\n * Checks if a packageUrl content has been modified since the specified timestamp.\n *\n * @param packageUrl - The URL to check.\n * @param lastDownloadTimestamp - The timestamp of the last download.\n * @returns True if the content has been modified, otherwise false.\n * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since\n */\nexport async function checkIfModified(\n packageUrl: string,\n lastDownloadTimestamp: Date,\n http: Http,\n): Promise<boolean> {\n const options: HttpOptions = {\n headers: {\n 'If-Modified-Since': lastDownloadTimestamp.toUTCString(),\n },\n };\n\n try {\n const response = await http.head(packageUrl, options);\n return !isNotModified(response);\n } catch (error) {\n logger.warn(\n { packageUrl, lastDownloadTimestamp, errorMessage: error.message },\n 'Could not determine if package file is modified since last download',\n );\n return true; // Assume it needs to be downloaded if check fails\n }\n}\n\n/**\n * Constructs a URL for accessing the component directory for a specific release and architecture.\n *\n * @param baseUrl - The base URL of the repository.\n * @param release - The release name or codename (e.g., 'buster', 'bullseye').\n * @param component - The component name (e.g., 'main', 'contrib', 'non-free').\n * @param arch - The architecture name (e.g., 'amd64', 'i386').\n * @returns The complete URL to the component directory.\n */\nexport function getComponentUrl(\n baseUrl: string,\n release: string,\n component: string,\n arch: string,\n): string {\n return `${baseUrl}/debian/dists/${release}/${component}/binary-${arch}`;\n}\n\n/**\n * Constructs a URL for accessing the Packages.gz file for a specific component, release, and architecture.\n *\n * @param baseUrl - The base URL of the repository.\n * @param release - The release name or codename (e.g., 'buster', 'bullseye').\n * @param component - The component name (e.g., 'main', 'contrib', 'non-free').\n * @param arch - The architecture name (e.g., 'amd64', 'i386').\n * @returns The complete URL to the Packages.gz file.\n */\nexport function getPackageUrl(\n baseUrl: string,\n release: string,\n component: string,\n arch: string,\n): string {\n return `${getComponentUrl(baseUrl, release, component, arch)}/Packages.gz`;\n}\n\n/**\n * Constructs a URL used generating the component url with specific release, components, and architecture.\n *\n * @param baseUrl - The base URL of the repository.\n * @param release - The release name or codename (e.g., 'buster', 'bullseye').\n * @param components - An array of component names (e.g., ['main', 'contrib', 'non-free']).\n * @param arch - The architecture name (e.g., 'amd64', 'i386').\n * @returns The complete URL to the package registry.\n */\nexport function getRegistryUrl(\n baseUrl: string,\n release: string,\n components: string[],\n arch: string,\n): string {\n return `${baseUrl}/debian?suite=${release}&components=${components.join(',')}&binaryArch=${arch}`;\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,SAAgB,gBAAgB,gBAAgC;CAC9D,MAAM,WAAW,eAAe,MAAM,GAAG;CACzC,OAAO,SAAS,MAAM,GAAG,SAAS,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG;AACxD;;;;;;;;AASA,SAAgB,uBAAuB,aAA+B;CACpE,MAAM,kBAAkB,CAAC,cAAc,YAAY;CACnD,MAAM,kBAAkB,CAAC,SAAS,SAAS;CAE3C,IAAI;EACF,MAAM,MAAM,SAAS,WAAW;EAChC,IAAI,CAAC,KACH,OAAO,CAAC;EAEV,qBAAqB,KAAK,eAAe;EAEzC,MAAM,QAAQ,gBAAgB,KAAK,eAAe;EAClD,MAAM,aAAa,IAAI,aAAa,IAAI,YAAY;EACpD,MAAM,aAAa,IAAI,aAAa,IAAI,YAAY,CAAC,CAAE,MAAM,GAAG;EAGhE,CAAC,GAAG,iBAAiB,GAAG,eAAe,CAAC,CAAC,SAAS,UAChD,IAAI,aAAa,OAAO,KAAK,CAC/B;EAEA,OAAO,WAAW,KAAK,cACrB,aACE,IAAI,SAAS,GACb,SACA,OACA,WACA,UAAU,YACZ,CACF;CACF,SAAS,OAAO;EACd,MAAM,IAAI,MACR,yBAAyB,YAAY,wBAAwB,MAAM,SACrE;CACF;AACF;;;;;;;;AASA,SAAS,qBAAqB,KAAU,gBAAgC;CACtE,KAAK,MAAM,SAAS,gBAClB,IAAI,CAAC,IAAI,aAAa,IAAI,KAAK,GAC7B,MAAM,IAAI,MAAM,qCAAqC,MAAM,EAAE;AAGnE;;;;;;;;;AAUA,SAAS,gBAAgB,KAAU,gBAAkC;CACnE,KAAK,MAAM,SAAS,gBAAgB;EAClC,MAAM,aAAa,IAAI,aAAa,IAAI,KAAK;EAC7C,IAAI,eAAe,MAAM;GACvB,IAAI,UAAU,WACZ,OAAO,MACL,wEACF;GAEF,OAAO;EACT;CACF;CACA,MAAM,IAAI,MAAM,sCAAsC;AACxD;;;;;;;;;AAUA,eAAsB,gBACpB,YACA,uBACA,MACkB;CAClB,MAAM,UAAuB,EAC3B,SAAS,EACP,qBAAqB,sBAAsB,YAAY,EACzD,EACF;CAEA,IAAI;EACF,MAAM,WAAW,MAAM,KAAK,KAAK,YAAY,OAAO;EACpD,OAAO,CAAC,cAAc,QAAQ;CAChC,SAAS,OAAO;EACd,OAAO,KACL;GAAE;GAAY;GAAuB,cAAc,MAAM;EAAQ,GACjE,qEACF;EACA,OAAO;CACT;AACF"}
@@ -1,5 +1,6 @@
1
1
  import { logger } from "../../../logger/index.js";
2
2
  import { joinUrlParts } from "../../../util/url.js";
3
+ import { isNotFound } from "../../../util/http/status.js";
3
4
  import { ExternalHostError } from "../../../types/errors/external-host-error.js";
4
5
  import { id } from "../../versioning/devbox/index.js";
5
6
  import { RequestError } from "../../../util/http/got.js";
@@ -33,7 +34,7 @@ var DevboxDatasource = class extends Datasource {
33
34
  res.releases = response.body.releases;
34
35
  res.homepage = response.body.homepage;
35
36
  } catch (err) {
36
- if (err instanceof RequestError && err.response?.statusCode !== 404) throw new ExternalHostError(err);
37
+ if (err instanceof RequestError && !isNotFound(err)) throw new ExternalHostError(err);
37
38
  this.handleGenericErrors(err);
38
39
  }
39
40
  return res.releases.length ? res : null;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["devboxVersioning.id","HttpError"],"sources":["../../../../lib/modules/datasource/devbox/index.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport { joinUrlParts } from '../../../util/url.ts';\nimport * as devboxVersioning from '../../versioning/devbox/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, ReleaseResult } from '../types.ts';\nimport { datasource, defaultRegistryUrl } from './common.ts';\nimport { DevboxResponse } from './schema.ts';\n\nexport class DevboxDatasource extends Datasource {\n static readonly id = datasource;\n\n constructor() {\n super(datasource);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n override readonly releaseTimestampSupport = true;\n\n override readonly defaultVersioning = devboxVersioning.id;\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [defaultRegistryUrl];\n }\n\n async getReleases({\n registryUrl,\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n const res: ReleaseResult = {\n releases: [],\n };\n\n logger.trace({ registryUrl, packageName }, 'fetching devbox release');\n\n const devboxPkgUrl = joinUrlParts(\n registryUrl!,\n `/pkg?name=${encodeURIComponent(packageName)}`,\n );\n\n try {\n const response = await this.http.getJson(devboxPkgUrl, DevboxResponse);\n res.releases = response.body.releases;\n res.homepage = response.body.homepage;\n } catch (err) {\n if (err instanceof HttpError && err.response?.statusCode !== 404) {\n throw new ExternalHostError(err);\n }\n this.handleGenericErrors(err);\n }\n return res.releases.length ? res : null;\n }\n}\n"],"mappings":";;;;;;;;;;AAUA,IAAa,mBAAb,cAAsC,WAAW;CAC/C,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,UAAU;CAClB;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CACA,0BAA4C;CAE5C,oBAAsCA;CAEtC,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,kBAAkB;CAC5B;CAEA,MAAM,YAAY,EAChB,aACA,eACmD;EACnD,MAAM,MAAqB,EACzB,UAAU,CAAC,EACb;EAEA,OAAO,MAAM;GAAE;GAAa;EAAY,GAAG,yBAAyB;EAEpE,MAAM,eAAe,aACnB,aACA,aAAa,mBAAmB,WAAW,GAC7C;EAEA,IAAI;GACF,MAAM,WAAW,MAAM,KAAK,KAAK,QAAQ,cAAc,cAAc;GACrE,IAAI,WAAW,SAAS,KAAK;GAC7B,IAAI,WAAW,SAAS,KAAK;EAC/B,SAAS,KAAK;GACZ,IAAI,eAAeC,gBAAa,IAAI,UAAU,eAAe,KAC3D,MAAM,IAAI,kBAAkB,GAAG;GAEjC,KAAK,oBAAoB,GAAG;EAC9B;EACA,OAAO,IAAI,SAAS,SAAS,MAAM;CACrC;AACF"}
1
+ {"version":3,"file":"index.js","names":["devboxVersioning.id","HttpError"],"sources":["../../../../lib/modules/datasource/devbox/index.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport { isNotFound } from '../../../util/http/status.ts';\nimport { joinUrlParts } from '../../../util/url.ts';\nimport * as devboxVersioning from '../../versioning/devbox/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, ReleaseResult } from '../types.ts';\nimport { datasource, defaultRegistryUrl } from './common.ts';\nimport { DevboxResponse } from './schema.ts';\n\nexport class DevboxDatasource extends Datasource {\n static readonly id = datasource;\n\n constructor() {\n super(datasource);\n }\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n override readonly releaseTimestampSupport = true;\n\n override readonly defaultVersioning = devboxVersioning.id;\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return [defaultRegistryUrl];\n }\n\n async getReleases({\n registryUrl,\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n const res: ReleaseResult = {\n releases: [],\n };\n\n logger.trace({ registryUrl, packageName }, 'fetching devbox release');\n\n const devboxPkgUrl = joinUrlParts(\n registryUrl!,\n `/pkg?name=${encodeURIComponent(packageName)}`,\n );\n\n try {\n const response = await this.http.getJson(devboxPkgUrl, DevboxResponse);\n res.releases = response.body.releases;\n res.homepage = response.body.homepage;\n } catch (err) {\n if (err instanceof HttpError && !isNotFound(err)) {\n throw new ExternalHostError(err);\n }\n this.handleGenericErrors(err);\n }\n return res.releases.length ? res : null;\n }\n}\n"],"mappings":";;;;;;;;;;;AAWA,IAAa,mBAAb,cAAsC,WAAW;CAC/C,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,UAAU;CAClB;CAEA,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CACA,0BAA4C;CAE5C,oBAAsCA;CAEtC,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,kBAAkB;CAC5B;CAEA,MAAM,YAAY,EAChB,aACA,eACmD;EACnD,MAAM,MAAqB,EACzB,UAAU,CAAC,EACb;EAEA,OAAO,MAAM;GAAE;GAAa;EAAY,GAAG,yBAAyB;EAEpE,MAAM,eAAe,aACnB,aACA,aAAa,mBAAmB,WAAW,GAC7C;EAEA,IAAI;GACF,MAAM,WAAW,MAAM,KAAK,KAAK,QAAQ,cAAc,cAAc;GACrE,IAAI,WAAW,SAAS,KAAK;GAC7B,IAAI,WAAW,SAAS,KAAK;EAC/B,SAAS,KAAK;GACZ,IAAI,eAAeC,gBAAa,CAAC,WAAW,GAAG,GAC7C,MAAM,IAAI,kBAAkB,GAAG;GAEjC,KAAK,oBAAoB,GAAG;EAC9B;EACA,OAAO,IAAI,SAAS,SAAS,MAAM;CACrC;AACF"}
@@ -5,6 +5,7 @@ import { coerceArray } from "../../../util/array.js";
5
5
  import { addSecretForSanitizing } from "../../../util/sanitize.js";
6
6
  import { logger } from "../../../logger/index.js";
7
7
  import { ensureTrailingSlash, parseUrl, trimTrailingSlash } from "../../../util/url.js";
8
+ import { isForbidden, isNotFound, isOk, isRateLimited, isServerError, isUnauthorized } from "../../../util/http/status.js";
8
9
  import { toSha256 } from "../../../util/hash.js";
9
10
  import { find } from "../../../util/host-rules.js";
10
11
  import { detectPlatform } from "../../../util/common.js";
@@ -39,11 +40,11 @@ async function getAuthHeaders(http, registryHost, dockerRepository, apiCheckUrl
39
40
  let apiCheckResponse;
40
41
  if (apiCheckUrl.endsWith("/v2/")) apiCheckResponse = await http.get(apiCheckUrl, options);
41
42
  else apiCheckResponse = await http.getJsonUnchecked(apiCheckUrl, options);
42
- if (apiCheckResponse.statusCode === 200) {
43
+ if (isOk(apiCheckResponse)) {
43
44
  logger.debug(`No registry auth required for ${apiCheckUrl}`);
44
45
  return {};
45
46
  }
46
- if (apiCheckResponse.statusCode === 404) {
47
+ if (isNotFound(apiCheckResponse)) {
47
48
  logger.debug(`Page Not Found ${apiCheckUrl}`);
48
49
  throw new Error(PAGE_NOT_FOUND_ERROR);
49
50
  }
@@ -51,7 +52,7 @@ async function getAuthHeaders(http, registryHost, dockerRepository, apiCheckUrl
51
52
  logger.debug({ apiCheckUrl }, "Registry rejected n>1000 on auth probe; retrying auth check via base /v2/ endpoint");
52
53
  return getAuthHeaders(http, registryHost, dockerRepository);
53
54
  }
54
- if (apiCheckResponse.statusCode !== 401 || !isNonEmptyString(apiCheckResponse.headers["www-authenticate"])) {
55
+ if (!isUnauthorized(apiCheckResponse) || !isNonEmptyString(apiCheckResponse.headers["www-authenticate"])) {
55
56
  logger.warn({
56
57
  apiCheckUrl,
57
58
  res: apiCheckResponse
@@ -134,7 +135,7 @@ async function getAuthHeaders(http, registryHost, dockerRepository, apiCheckUrl
134
135
  /* v8 ignore if -- quay.io errors are swallowed pending #9604, not reproduced in specs */
135
136
  if (err.host === "quay.io") return;
136
137
  /* v8 ignore if -- registry auth rejection is logged and swallowed, not mocked in specs */
137
- if (err.statusCode === 401) {
138
+ if (isUnauthorized(err)) {
138
139
  logger.debug({
139
140
  registryHost,
140
141
  dockerRepository
@@ -143,7 +144,7 @@ async function getAuthHeaders(http, registryHost, dockerRepository, apiCheckUrl
143
144
  return;
144
145
  }
145
146
  /* v8 ignore if -- registry permission rejection is logged and swallowed, not mocked in specs */
146
- if (err.statusCode === 403) {
147
+ if (isForbidden(err)) {
147
148
  logger.debug({
148
149
  registryHost,
149
150
  dockerRepository
@@ -153,9 +154,9 @@ async function getAuthHeaders(http, registryHost, dockerRepository, apiCheckUrl
153
154
  }
154
155
  if (err.name === "RequestError" && isDockerHost(registryHost)) throw new ExternalHostError(err);
155
156
  /* v8 ignore if -- Docker Hub rate limiting maps to ExternalHostError, not mocked in specs */
156
- if (err.statusCode === 429 && isDockerHost(registryHost)) throw new ExternalHostError(err);
157
+ if (isRateLimited(err) && isDockerHost(registryHost)) throw new ExternalHostError(err);
157
158
  /* v8 ignore if -- registry server errors map to ExternalHostError, not mocked in specs */
158
- if (err.statusCode >= 500 && err.statusCode < 600) throw new ExternalHostError(err);
159
+ if (isServerError(err)) throw new ExternalHostError(err);
159
160
  if (err.message === "page-not-found") throw err;
160
161
  /* v8 ignore if -- hostRules-disabled host is swallowed silently, not mocked in specs */
161
162
  if (["host-blocked", "host-disabled"].includes(err.message)) {
@@ -197,7 +198,8 @@ function getRegistryRepository(packageName, registryUrl) {
197
198
  }
198
199
  let registryHost = registryUrl;
199
200
  const split = packageName.split("/");
200
- if (split.length > 1 && (split[0].includes(".") || split[0].includes(":"))) {
201
+ const hasRegistryHost = split[0].includes(".") || split[0].includes(":");
202
+ if (split.length > 1 && hasRegistryHost) {
201
203
  [registryHost] = split;
202
204
  split.shift();
203
205
  }