@vltpkg/cli-js 1.0.1 → 1.0.3

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 (83) hide show
  1. package/{access-SXQICNAN.js → access-5WETTBDZ.js} +9 -7
  2. package/{bugs-OOPMFRCI.js → bugs-KONFLIQQ.js} +19 -18
  3. package/{build-HDXI5OA7.js → build-S7G2DU7I.js} +12 -10
  4. package/{cache-RW4Y4XNQ.js → cache-Z4OIMLXQ.js} +23 -21
  5. package/{chunk-RXNA2XCX.js → chunk-4KCU2KZL.js} +8 -1
  6. package/{chunk-F2FKLPZD.js → chunk-5B23EKN4.js} +4 -4
  7. package/{chunk-4ZXA6RLP.js → chunk-5QJEOGEM.js} +3 -1
  8. package/{chunk-CCQYIYTA.js → chunk-5UPPEUG2.js} +11 -11
  9. package/chunk-BJBFEQRR.js +667 -0
  10. package/{chunk-MU7Y4R5E.js → chunk-DYCF76WI.js} +4 -4
  11. package/{chunk-EHEVBLDB.js → chunk-E737X73P.js} +38 -24
  12. package/{chunk-ICJRCXSG.js → chunk-FFOXTPQA.js} +12 -9
  13. package/chunk-G7UPIJAP.js +903 -0
  14. package/{chunk-CNSTFT7U.js → chunk-HAYXR3MW.js} +1 -1
  15. package/{chunk-U6DM3ROE.js → chunk-HNCE3YE5.js} +1649 -1569
  16. package/{chunk-2PLIV3N3.js → chunk-IITIX4ID.js} +740 -6
  17. package/chunk-LPIBYUMT.js +854 -0
  18. package/{chunk-E5YE7UTZ.js → chunk-LZGKX7JI.js} +114 -50
  19. package/{chunk-3SQ5Y324.js → chunk-NXEH3NQZ.js} +11 -13
  20. package/{chunk-MT76WHSM.js → chunk-OCJDISSI.js} +12 -6
  21. package/chunk-RNJSI3NZ.js +75 -0
  22. package/{chunk-FAG776ZD.js → chunk-T4GYDWUJ.js} +1 -1
  23. package/{chunk-VM2RMMY4.js → chunk-TMBNGWXK.js} +3 -3
  24. package/{chunk-EQ633HIM.js → chunk-UAAZW4N6.js} +4 -4
  25. package/{chunk-D5CP6O6G.js → chunk-UXIRAU5T.js} +4 -4
  26. package/{chunk-EFWPI6IY.js → chunk-VB3IWNHX.js} +1 -1
  27. package/chunk-VE6CCH33.js +3000 -0
  28. package/{chunk-UCD3RJYG.js → chunk-W2Q5EIMH.js} +8 -8
  29. package/{chunk-VZ7UNZHR.js → chunk-XQSBCMSC.js} +5 -5
  30. package/{reporter-2XBYWAVU.js → chunk-XU5SMHXP.js} +35 -10
  31. package/{ci-MTYU2K2A.js → ci-RZZE375O.js} +17 -16
  32. package/cli-package.json +1 -1
  33. package/{config-TVAXCTQO.js → config-LL3RLMZG.js} +9 -12
  34. package/{config-6NXV2BXW.js → config-MDFY3ORD.js} +15 -18
  35. package/{create-LXI5DCDW.js → create-GVSDTOGQ.js} +23 -23
  36. package/{deprecate-2AQBL5XT.js → deprecate-T4TQLGXQ.js} +16 -14
  37. package/{dist-tag-BFSYLRIH.js → dist-tag-GO46UQUN.js} +11 -9
  38. package/{docs-ADPJ4B4C.js → docs-FJME563T.js} +19 -18
  39. package/{exec-GMS54RAC.js → exec-M22KBPCK.js} +23 -23
  40. package/{exec-cache-R5LVZL5Z.js → exec-cache-3UNLDUAP.js} +22 -22
  41. package/{exec-local-TVCLZGIM.js → exec-local-YHVO5RLU.js} +20 -18
  42. package/{help-6CECUD6C.js → help-ZEWMLOJX.js} +3 -3
  43. package/{init-XXFLGYVP.js → init-4HPZY2KN.js} +12 -10
  44. package/{install-6KMXYSF5.js → install-2TZIP4PJ.js} +18 -17
  45. package/{list-RUO3SUKY.js → list-NFFXER43.js} +20 -18
  46. package/{login-6I2CGO7I.js → login-KV5YC5Z2.js} +9 -7
  47. package/{logout-JTU4BJKH.js → logout-I2VT3NAR.js} +9 -7
  48. package/{pack-NCWH2TUA.js → pack-47ZKFSHI.js} +16 -14
  49. package/package.json +6 -6
  50. package/{ping-4MEAC2WD.js → ping-Q7Y7QV63.js} +9 -7
  51. package/{pkg-ENSKG6G7.js → pkg-VTJS2ISJ.js} +13 -11
  52. package/{profile-62YHNFSO.js → profile-YXZYVEUX.js} +9 -7
  53. package/{publish-PPY724N2.js → publish-CBN67KN2.js} +21 -19
  54. package/{query-NLWXKOOT.js → query-U3QHF3ZE.js} +20 -18
  55. package/{registry-QGI44LG4.js → registry-CZPFR3OF.js} +3 -3
  56. package/registry-client-package.json +1 -1
  57. package/registry-client-src-revalidate.js +2080 -349
  58. package/{repo-BFRAXIVU.js → repo-4UIQRBI7.js} +19 -18
  59. package/{chunk-4RZDJQ5U.js → reporter-DKZTTACW.js} +5 -5
  60. package/{run-7O65747G.js → run-5DUYI6GL.js} +20 -18
  61. package/{run-exec-2OYWHL6K.js → run-exec-HPNBVAXH.js} +20 -18
  62. package/security-archive-src-update-expired.js +39 -4
  63. package/{setup-MMIDAIJI.js → setup-23W5FQVW.js} +24 -15
  64. package/{src-OK3KHDYR.js → src-2NB67FPG.js} +22 -23
  65. package/src-6OKPBJJT.js +59 -0
  66. package/src-M5RRGKUM.js +913 -0
  67. package/{token-VLVXUW54.js → token-SRCS5CRU.js} +9 -7
  68. package/{uninstall-TAG6QIAG.js → uninstall-JXHAFXZ2.js} +18 -17
  69. package/{unpublish-Y4L5J2IA.js → unpublish-GRYB5KQH.js} +12 -10
  70. package/{update-RYH4RKBS.js → update-GDLL4ER6.js} +17 -16
  71. package/{version-COHB32ON.js → version-JVG4CI4L.js} +13 -11
  72. package/{view-P7U4MF43.js → view-ABQLVL4L.js} +13 -15
  73. package/vlr.js +1 -1
  74. package/vlrx.js +1 -1
  75. package/vlt.js +1 -1
  76. package/vlx.js +1 -1
  77. package/vlxl.js +1 -1
  78. package/{whoami-47MVFMZC.js → whoami-RCCZ7BXI.js} +9 -7
  79. package/chunk-7NHXV6AH.js +0 -4488
  80. package/chunk-HB7CKTYO.js +0 -75
  81. package/chunk-PW6S6AIO.js +0 -716
  82. package/chunk-WXMYKCQW.js +0 -1640
  83. package/{chunk-Y7CQIZ7Y.js → chunk-FEIPJIEN.js} +3 -3
@@ -920,7 +920,685 @@ var comparatorNone = {
920
920
  test: (_) => false
921
921
  };
922
922
 
923
+ // ../../src/spec/src/valid-name.ts
924
+ var pathSafeName = /^(?!(?:node_modules|\.vlt)$)(?![A-Za-z]:)(?:@(?!\.\.?\/)[^/\\\x00-\x1f\x7f]+\/)?(?!\.\.?$)[^/\\\x00-\x1f\x7f]+$/i;
925
+ var isPathSafeName = (name) => typeof name === "string" && pathSafeName.test(name);
926
+ var assertPathSafeName = (name, from) => {
927
+ if (isPathSafeName(name)) return;
928
+ throw error(
929
+ "Invalid package name: not usable as a path segment",
930
+ {
931
+ code: "EINVALIDNAME",
932
+ found: name,
933
+ from,
934
+ wanted: "a single path segment, or a well-formed @scope/name"
935
+ },
936
+ assertPathSafeName
937
+ );
938
+ };
939
+
940
+ // ../../src/spec/src/browser.ts
941
+ var kCustomInspect = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
942
+ var defaultRegistryName = "npm";
943
+ var defaultRegistries = {
944
+ gh: "https://npm.pkg.github.com/"
945
+ };
946
+ var defaultJsrRegistries = { jsr: "https://npm.jsr.io/" };
947
+ var defaultGitHosts = {
948
+ github: "git+ssh://git@github.com:$1/$2.git",
949
+ bitbucket: "git+ssh://git@bitbucket.org:$1/$2.git",
950
+ gitlab: "git+ssh://git@gitlab.com:$1/$2.git",
951
+ gist: "git+ssh://git@gist.github.com/$1.git"
952
+ };
953
+ var defaultGitHostArchives = {
954
+ github: "https://api.github.com/repos/$1/$2/tarball/$committish",
955
+ bitbucket: "https://bitbucket.org/$1/$2/get/$committish.tar.gz",
956
+ gist: "https://codeload.github.com/gist/$1/tar.gz/$committish",
957
+ gitlab: "https://gitlab.com/$1/$2/repository/archive.tar.gz?ref=$committish"
958
+ };
959
+ var gitHostWebsites = {
960
+ github: "https://github.com/",
961
+ bitbucket: "https://bitbucket.org/",
962
+ gist: "https://gist.github.com/",
963
+ gitlab: "https://gitlab.com/"
964
+ };
965
+ var defaultScopeRegistries = {
966
+ "@jsr": "https://npm.jsr.io/"
967
+ };
968
+ var getOptions = (options) => ({
969
+ catalog: {},
970
+ catalogs: {},
971
+ ...options,
972
+ // built-in aliases are user/service-overridable: user config wins
973
+ "jsr-registries": {
974
+ ...defaultJsrRegistries,
975
+ ...options?.["jsr-registries"] ?? {}
976
+ },
977
+ registry: options?.registry,
978
+ "default-registry-alias": options?.["default-registry-alias"] ?? defaultRegistryName,
979
+ "scoped-registries": options?.["scoped-registries"] ?? {},
980
+ "git-hosts": options?.["git-hosts"] ? {
981
+ ...defaultGitHosts,
982
+ ...options["git-hosts"]
983
+ } : defaultGitHosts,
984
+ registries: {
985
+ ...defaultRegistries,
986
+ ...options?.registries ?? {}
987
+ },
988
+ "git-host-archives": options?.["git-host-archives"] ? {
989
+ ...defaultGitHostArchives,
990
+ ...options["git-host-archives"]
991
+ } : defaultGitHostArchives
992
+ });
993
+ var startsWithSpecIdentifier = (spec, options) => spec.startsWith("/") || spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("file:") || spec.startsWith("http:") || spec.startsWith("https:") || spec.startsWith("workspace:") || spec.startsWith("catalog:") || spec.startsWith("git@") || spec.startsWith("git://") || spec.startsWith("git+ssh://") || spec.startsWith("git+http://") || spec.startsWith("git+https://") || spec.startsWith("git+file://") || spec.startsWith("git@github.com") || spec.startsWith("registry:") || spec.startsWith("npm:") || spec.startsWith("jsr:") || spec.startsWith("gh:") || // anything that starts with a known git host key, or a
994
+ // custom registered registry protocol e.g: `github:`, `custom:`
995
+ [
996
+ ...Object.keys(options["git-hosts"]),
997
+ ...Object.keys(options.registries),
998
+ ...Object.keys(options["jsr-registries"])
999
+ ].some((key) => spec.startsWith(`${key}:`));
1000
+ var findFirstAt = (spec, hasScope) => spec.indexOf("@", hasScope ? 1 : 0);
1001
+ var findGitIdentifier = (spec) => spec.indexOf("#") > 2;
1002
+ var findFileIdentifier = (spec) => spec.includes("/");
1003
+ var isSpec = (spec) => typeof spec === "object" && spec !== null && "spec" in spec && "bareSpec" in spec && "name" in spec && "type" in spec && "options" in spec && typeof spec.spec === "string" && typeof spec.bareSpec === "string" && typeof spec.name === "string";
1004
+ var currentDefaultRegistryName = (registry, options) => {
1005
+ for (const [name, url] of Object.entries(
1006
+ options.registries ?? {}
1007
+ )) {
1008
+ const specRegURL = registry.endsWith("/") ? registry : registry + "/";
1009
+ const knownRegURL = url.endsWith("/") ? url : url + "/";
1010
+ if (specRegURL === knownRegURL) {
1011
+ return name;
1012
+ }
1013
+ }
1014
+ };
1015
+ var Spec = class _Spec {
1016
+ static parse(spec, bareOrOptions, options) {
1017
+ return typeof spec === "object" ? spec : new this(spec, bareOrOptions, options);
1018
+ }
1019
+ static parseArgs(specOrBareSpec, opts) {
1020
+ const options = getOptions(opts ?? {});
1021
+ if (startsWithSpecIdentifier(specOrBareSpec, options)) {
1022
+ const parsed = this.parse("(unknown)", specOrBareSpec, options);
1023
+ if (parsed.subspec) {
1024
+ const { namedJsrRegistry: jsrHost } = parsed;
1025
+ if (!jsrHost) {
1026
+ parsed.name = parsed.subspec.name;
1027
+ }
1028
+ parsed.spec = `${parsed.name}@${parsed.bareSpec}`;
1029
+ assertPathSafeName(parsed.name, parsed.spec);
1030
+ }
1031
+ return parsed;
1032
+ } else {
1033
+ const hasScope = specOrBareSpec.startsWith("@");
1034
+ const at = findFirstAt(specOrBareSpec, hasScope);
1035
+ if (at > -1) {
1036
+ return this.parse(
1037
+ specOrBareSpec.substring(0, at),
1038
+ specOrBareSpec.substring(at + 1),
1039
+ options
1040
+ );
1041
+ } else if (findGitIdentifier(specOrBareSpec) || !hasScope && findFileIdentifier(specOrBareSpec)) {
1042
+ return this.parse("(unknown)", specOrBareSpec, options);
1043
+ } else {
1044
+ return this.parse(`${specOrBareSpec}@`, options);
1045
+ }
1046
+ }
1047
+ }
1048
+ static nodejsDependencies;
1049
+ type;
1050
+ spec;
1051
+ options;
1052
+ name;
1053
+ scope;
1054
+ scopeRegistry;
1055
+ bareSpec;
1056
+ gitRemote;
1057
+ gitSelector;
1058
+ gitSelectorParsed;
1059
+ gitCommittish;
1060
+ namedGitHost;
1061
+ namedGitHostPath;
1062
+ workspaceSpec;
1063
+ workspace;
1064
+ namedRegistry;
1065
+ namedJsrRegistry;
1066
+ registry;
1067
+ registrySpec;
1068
+ conventionalRegistryTarball;
1069
+ semver;
1070
+ range;
1071
+ distTag;
1072
+ remoteURL;
1073
+ file;
1074
+ catalog;
1075
+ subspec;
1076
+ overridden = false;
1077
+ #final;
1078
+ #toString;
1079
+ /**
1080
+ * Return the final entry in the chain of subspecs
1081
+ * When deciding which thing to actually fetch, spec.final is the thing
1082
+ * to look at.
1083
+ */
1084
+ get final() {
1085
+ if (this.#final) return this.#final;
1086
+ const final = this.subspec ? this.subspec.final : this;
1087
+ if (final.type === "catalog") {
1088
+ throw error('invalid Spec.final value, type is "catalog"');
1089
+ }
1090
+ return this.#final = final;
1091
+ }
1092
+ /**
1093
+ * Normally, the string value of a Spec is just the string passed in to
1094
+ * be parsed. However, in the case of a chain of subspecs, like
1095
+ * `foo@npm:bar@npm:baz@npm:quux@latest`, this simplifies out the middle
1096
+ * parts of the chain, returning just `foo@npm:quux@latest`
1097
+ */
1098
+ toString() {
1099
+ if (this.#toString !== void 0) return this.#toString;
1100
+ let sub = this;
1101
+ while (sub.subspec?.subspec) sub = sub.subspec;
1102
+ if (sub.subspec && sub.subspec.type !== "registry")
1103
+ sub = sub.subspec;
1104
+ return this.#toString = this.name + "@" + sub.bareSpec;
1105
+ }
1106
+ constructor(spec, bareOrOptions, options = {}) {
1107
+ if (bareOrOptions && typeof bareOrOptions === "object") {
1108
+ options = bareOrOptions;
1109
+ bareOrOptions = void 0;
1110
+ }
1111
+ this.options = getOptions(options);
1112
+ if (typeof bareOrOptions === "string") {
1113
+ this.name = spec;
1114
+ this.#parseScope(spec);
1115
+ this.bareSpec = bareOrOptions;
1116
+ this.spec = `${this.name}@${bareOrOptions}`;
1117
+ assertPathSafeName(this.name, this.spec);
1118
+ } else {
1119
+ this.spec = spec;
1120
+ if (!spec.startsWith("git@") && startsWithSpecIdentifier(spec, this.options) && spec.includes(":") && [
1121
+ ...Object.keys(this.options.registries),
1122
+ ...Object.keys(defaultRegistries)
1123
+ ].some((key) => spec.startsWith(`${key}:`))) {
1124
+ this.name = spec;
1125
+ this.bareSpec = spec;
1126
+ } else {
1127
+ const hasScope = spec.startsWith("@");
1128
+ let at = findFirstAt(spec, hasScope);
1129
+ if (at === -1) {
1130
+ at = spec.length;
1131
+ spec += "@";
1132
+ }
1133
+ this.name = spec.substring(0, at);
1134
+ assertPathSafeName(this.name, spec);
1135
+ if (hasScope) this.#parseScope(this.name);
1136
+ this.bareSpec = spec.substring(at + 1);
1137
+ }
1138
+ }
1139
+ if (this.bareSpec.startsWith("catalog:")) {
1140
+ this.catalog = this.bareSpec.substring("catalog:".length);
1141
+ const catalog = this.catalog ? this.options.catalogs?.[this.catalog] : this.options.catalog;
1142
+ if (!catalog) {
1143
+ throw this.#error("Named catalog not found", {
1144
+ name: this.catalog,
1145
+ validOptions: this.options.catalogs && Object.keys(this.options.catalogs)
1146
+ });
1147
+ }
1148
+ const sub = catalog[this.name];
1149
+ if (!sub) {
1150
+ throw this.#error("Name not found in catalog", {
1151
+ name: this.name,
1152
+ validOptions: Object.keys(catalog)
1153
+ });
1154
+ }
1155
+ this.subspec = _Spec.parse(this.name, sub, this.options);
1156
+ this.type = "catalog";
1157
+ this.registry = this.subspec.final.registry;
1158
+ return;
1159
+ }
1160
+ if (this.bareSpec.startsWith("https://")) {
1161
+ for (const [name, origin] of Object.entries(gitHostWebsites)) {
1162
+ if (this.bareSpec.startsWith(origin)) {
1163
+ const parsed = new URL(this.bareSpec);
1164
+ const [user, project] = parsed.pathname.replace(/\.git$/, "").replace(/\/+/g, " ").trim().split(" ");
1165
+ if (user && project) {
1166
+ this.bareSpec = `${name}:${user}/${project}${parsed.hash}`;
1167
+ this.spec = `${this.name}@${this.bareSpec}`;
1168
+ break;
1169
+ }
1170
+ }
1171
+ }
1172
+ }
1173
+ if (this.bareSpec.startsWith("workspace:")) {
1174
+ this.type = "workspace";
1175
+ const ws = this.bareSpec.substring("workspace:".length).trim();
1176
+ const w = ws.lastIndexOf("@");
1177
+ if (w === -1) {
1178
+ this.workspace = this.name;
1179
+ } else {
1180
+ const wsName = ws.substring(0, w);
1181
+ if (!wsName || wsName === "*" || wsName === "~" || wsName === "^" || (wsName.startsWith("@") ? wsName.split("/").length !== 2 || wsName.substring(1).includes("@") : wsName.includes("@"))) {
1182
+ throw this.#error(
1183
+ "workspace: name must be a path or valid package name",
1184
+ { found: wsName }
1185
+ );
1186
+ }
1187
+ this.workspace = wsName;
1188
+ }
1189
+ const wss = w === -1 ? ws : ws.substring(w + 1) || "*";
1190
+ const range2 = wss === "*" ? void 0 : parseRange(wss);
1191
+ if (wss !== "*" && wss !== "~" && wss !== "^" && !range2) {
1192
+ throw this.#error(
1193
+ "workspace: spec must be one of *, ~, or ^, or a valid semver range",
1194
+ {
1195
+ found: wss,
1196
+ wanted: `'*'|'~'|'^'|SemverRange`
1197
+ }
1198
+ );
1199
+ }
1200
+ this.workspaceSpec = wss;
1201
+ if (range2) {
1202
+ this.semver = wss;
1203
+ this.range = range2;
1204
+ }
1205
+ return;
1206
+ }
1207
+ if (this.bareSpec.startsWith("git://") || this.bareSpec.startsWith("git+ssh://") || this.bareSpec.startsWith("git+http://") || this.bareSpec.startsWith("git+https://") || this.bareSpec.startsWith("git+file://") || // legacy affordance
1208
+ this.bareSpec.startsWith("git@github.com")) {
1209
+ if (this.bareSpec.startsWith("git@")) {
1210
+ this.bareSpec = `git+ssh://${this.bareSpec}`;
1211
+ this.spec = `${this.name}@${this.bareSpec}`;
1212
+ }
1213
+ this.type = "git";
1214
+ for (const [name, host] of Object.entries(
1215
+ this.options["git-hosts"]
1216
+ )) {
1217
+ const s = host.indexOf("$");
1218
+ if (s > 0 && this.bareSpec.startsWith(host.substring(0, s))) {
1219
+ const p = this.bareSpec.substring(s).replace(/\.git(#.*)?$/, "$1");
1220
+ this.bareSpec = `${name}:${p}`;
1221
+ this.spec = `${this.name}@${this.bareSpec}`;
1222
+ this.#parseHostedGit(name, host);
1223
+ this.type = "git";
1224
+ return;
1225
+ }
1226
+ }
1227
+ this.#parseGitSelector(this.bareSpec);
1228
+ return;
1229
+ }
1230
+ const regs = Object.entries(this.options.registries);
1231
+ if (this.bareSpec.startsWith("registry:")) {
1232
+ const reg = this.bareSpec.substring("registry:".length);
1233
+ const h = reg.indexOf("#");
1234
+ if (h === -1) {
1235
+ throw this.#error("registry: must include name/version");
1236
+ }
1237
+ this.type = "registry";
1238
+ let url = reg.substring(0, h);
1239
+ if (!url.endsWith("/")) url += "/";
1240
+ const regSpec = reg.substring(h + 1);
1241
+ for (let [name, u] of regs) {
1242
+ if (!u.endsWith("/")) {
1243
+ u += "/";
1244
+ this.options.registries[name] = u;
1245
+ }
1246
+ if (u === url) this.namedRegistry = name;
1247
+ }
1248
+ this.#parseRegistrySpec(regSpec, url);
1249
+ this.#guessRegistryTarball();
1250
+ return;
1251
+ }
1252
+ for (const [host, url] of regs) {
1253
+ const h = `${host}:`;
1254
+ if (this.bareSpec.startsWith(h)) {
1255
+ this.type = "registry";
1256
+ this.namedRegistry = host;
1257
+ this.#parseRegistrySpec(
1258
+ this.bareSpec.substring(h.length),
1259
+ url
1260
+ ).namedRegistry ??= host;
1261
+ if (this.subspec && this.name === this.bareSpec) {
1262
+ this.name = this.subspec.name;
1263
+ this.spec = `${this.name}@${this.bareSpec}`;
1264
+ assertPathSafeName(this.name, this.spec);
1265
+ }
1266
+ this.#guessRegistryTarball();
1267
+ return;
1268
+ }
1269
+ }
1270
+ const ghosts = Object.entries(this.options["git-hosts"]);
1271
+ for (const [name, template] of ghosts) {
1272
+ if (this.#parseHostedGit(name, template)) {
1273
+ this.type = "git";
1274
+ return;
1275
+ }
1276
+ }
1277
+ const jsrs = Object.entries(this.options["jsr-registries"]);
1278
+ for (const [host, url] of jsrs) {
1279
+ const h = `${host}:`;
1280
+ if (this.bareSpec.startsWith(h)) {
1281
+ this.type = "registry";
1282
+ this.namedJsrRegistry = host;
1283
+ this.#parseJsrRegistrySpec(
1284
+ this.bareSpec.substring(h.length),
1285
+ url
1286
+ ).namedJsrRegistry ??= host;
1287
+ return;
1288
+ }
1289
+ }
1290
+ if (this.bareSpec.startsWith("https://") || this.bareSpec.startsWith("http://")) {
1291
+ this.remoteURL = this.bareSpec;
1292
+ this.type = "remote";
1293
+ return;
1294
+ }
1295
+ if (this.bareSpec.startsWith("file:")) {
1296
+ this.type = "file";
1297
+ const [path, uri] = getNormalizeFile(
1298
+ this.constructor.nodejsDependencies
1299
+ )(this.bareSpec, this);
1300
+ this.file = path;
1301
+ this.bareSpec = uri.replace(/\/+$/, "");
1302
+ this.spec = `${this.name}@${this.bareSpec}`;
1303
+ return;
1304
+ }
1305
+ if (!this.bareSpec.startsWith("./") && !this.bareSpec.startsWith("../") && this.options["git-hosts"].github) {
1306
+ const hash = this.bareSpec.indexOf("#");
1307
+ const up = hash === -1 ? this.bareSpec : this.bareSpec.substring(0, hash);
1308
+ if (up.split("/").length === 2) {
1309
+ this.bareSpec = `github:${this.bareSpec}`;
1310
+ this.spec = `${this.name}@${this.bareSpec}`;
1311
+ this.#parseHostedGit(
1312
+ "github",
1313
+ this.options["git-hosts"].github
1314
+ );
1315
+ this.type = "git";
1316
+ return;
1317
+ }
1318
+ }
1319
+ if (this.bareSpec.includes("/") || this.bareSpec === "." || this.bareSpec === "..") {
1320
+ this.type = "file";
1321
+ const [file, uri] = getNormalizeFile(
1322
+ this.constructor.nodejsDependencies
1323
+ )(`file:${this.bareSpec}`, this);
1324
+ this.bareSpec = uri;
1325
+ this.spec = `${this.name}@${this.bareSpec}`;
1326
+ this.file = file;
1327
+ return;
1328
+ }
1329
+ this.type = "registry";
1330
+ const range = parseRange(this.bareSpec);
1331
+ if (range) {
1332
+ this.semver = this.bareSpec.trim();
1333
+ this.range = range;
1334
+ } else {
1335
+ this.distTag = this.bareSpec;
1336
+ }
1337
+ this.registrySpec = this.bareSpec;
1338
+ const {
1339
+ "scoped-registries": scopeRegs,
1340
+ registry,
1341
+ registries,
1342
+ "default-registry-alias": defaultAlias
1343
+ } = this.options;
1344
+ const scopeReg = this.scope && scopeRegs[this.scope];
1345
+ this.registry = scopeReg ?? registry ?? registries[defaultAlias];
1346
+ for (const r of Object.values(this.options["jsr-registries"])) {
1347
+ if (this.registry === r) return;
1348
+ }
1349
+ this.#guessRegistryTarball();
1350
+ }
1351
+ #parseScope(name) {
1352
+ if (!name.startsWith("@")) return;
1353
+ const s = name.indexOf("/");
1354
+ if (s > 1 && s < name.length - 1) {
1355
+ const scope = name.substring(0, s);
1356
+ this.registry = this.scopeRegistry = this.options["scoped-registries"][scope];
1357
+ this.scope = scope;
1358
+ }
1359
+ }
1360
+ #parseHostedGit(name, template) {
1361
+ if (this.bareSpec.startsWith(`${name}:`)) {
1362
+ const h = this.bareSpec.indexOf("#");
1363
+ const bare = h === -1 ? this.bareSpec : this.bareSpec.substring(0, h);
1364
+ const hash = h === -1 ? "" : this.bareSpec.substring(h);
1365
+ const hostPath = bare.substring(name.length + 1);
1366
+ if (!hostPath) {
1367
+ throw this.#error("invalid named git host specifier");
1368
+ }
1369
+ const split = hostPath.split("/");
1370
+ let t = template;
1371
+ for (let i = 0; i < split.length; i++) {
1372
+ t = t.split(`$${i + 1}`).join(split[i]);
1373
+ }
1374
+ t += hash;
1375
+ this.namedGitHost = name;
1376
+ this.namedGitHostPath = hostPath;
1377
+ this.#parseGitSelector(t);
1378
+ if (this.gitCommittish && !this.gitSelectorParsed?.path) {
1379
+ const archiveHost = this.options["git-host-archives"][name];
1380
+ if (name === "github" && this.gitCommittish.startsWith("pull/") && this.gitCommittish.match(/\//g)?.length === 1) {
1381
+ this.gitCommittish += "/head";
1382
+ }
1383
+ if (archiveHost) {
1384
+ this.type = "remote";
1385
+ let t2 = archiveHost;
1386
+ t2 = t2.split("$committish").join(this.gitCommittish);
1387
+ for (let i = 0; i < split.length; i++) {
1388
+ t2 = t2.split(`$${i + 1}`).join(split[i]);
1389
+ }
1390
+ this.remoteURL = t2;
1391
+ }
1392
+ }
1393
+ return true;
1394
+ }
1395
+ return false;
1396
+ }
1397
+ /* c8 ignore start */
1398
+ [kCustomInspect]() {
1399
+ return `@vltpkg/spec.Spec ${String(this)}`;
1400
+ }
1401
+ /* c8 ignore stop */
1402
+ #guessRegistryTarball() {
1403
+ const { name, registry, range } = this.final;
1404
+ if (!registry || !range?.isSingle) return;
1405
+ const stripScope = /^@[^/]+\//;
1406
+ const base = registry.endsWith("/") ? registry : registry + "/";
1407
+ this.conventionalRegistryTarball = String(
1408
+ new URL(
1409
+ `${name}/-/${name.replace(stripScope, "")}-${range}.tgz`,
1410
+ base
1411
+ )
1412
+ );
1413
+ }
1414
+ #parseRegistrySpec(s, url) {
1415
+ this.registry = url;
1416
+ this.subspec = this.constructor.parse(s, {
1417
+ ...this.options,
1418
+ registry: url
1419
+ });
1420
+ return this.subspec;
1421
+ }
1422
+ #parseJsrRegistrySpec(s, url) {
1423
+ this.registry = url;
1424
+ if (!s.startsWith("@")) s = `${this.name}@${s}`;
1425
+ const name = s.startsWith("@jsr/") ? s : `@jsr/${s.replace(/^@/, "").replace(/\//, "__")}`;
1426
+ this.subspec = this.constructor.parse(name, {
1427
+ ...this.options,
1428
+ "scoped-registries": {
1429
+ ...this.options["scoped-registries"],
1430
+ "@jsr": url
1431
+ }
1432
+ });
1433
+ if (this.name === "(unknown)") {
1434
+ const nextAt = s.indexOf("@", 1);
1435
+ if (nextAt === -1) {
1436
+ this.name = s;
1437
+ } else {
1438
+ this.name = s.substring(0, s.indexOf("@", 1));
1439
+ }
1440
+ assertPathSafeName(this.name, s);
1441
+ }
1442
+ const reg = `${this.namedJsrRegistry}:`;
1443
+ const n = `${reg}${this.name}`;
1444
+ if (this.bareSpec.startsWith(n + "@")) {
1445
+ this.bareSpec = reg + this.bareSpec.substring(n.length + 1);
1446
+ } else if (this.bareSpec === n) {
1447
+ this.bareSpec = reg;
1448
+ }
1449
+ this.spec = this.name + "@" + this.bareSpec;
1450
+ return this.subspec;
1451
+ }
1452
+ #error(message, extra = {}) {
1453
+ return error(message, { spec: this.spec, ...extra }, this.#error);
1454
+ }
1455
+ #parseGitSelector(s) {
1456
+ const h = s.indexOf("#");
1457
+ if (h === -1) {
1458
+ this.gitRemote = s;
1459
+ return;
1460
+ }
1461
+ this.gitRemote = s.substring(0, h);
1462
+ this.gitSelector = s.substring(h + 1);
1463
+ const [selectorParsed, committish, range] = this.constructor.parseGitSelector(this.gitSelector, this);
1464
+ this.range = range;
1465
+ this.gitCommittish = committish;
1466
+ this.gitSelectorParsed = selectorParsed;
1467
+ }
1468
+ /**
1469
+ * Should only ever be called with the bit that comes AFTER the #
1470
+ * in the git remote url.
1471
+ */
1472
+ static parseGitSelector(selector, spec) {
1473
+ if (!selector) return [{}];
1474
+ const split = selector.split("::");
1475
+ const first = split[0];
1476
+ let committish = void 0;
1477
+ let range = void 0;
1478
+ const parsed = {};
1479
+ if (typeof first !== "string") {
1480
+ throw typeError("impossible", {
1481
+ found: first,
1482
+ wanted: String
1483
+ });
1484
+ }
1485
+ if (!first.includes(":")) {
1486
+ committish = first;
1487
+ split.shift();
1488
+ }
1489
+ for (const kv of split) {
1490
+ const c = kv.indexOf(":");
1491
+ if (c === -1) continue;
1492
+ const k = kv.substring(0, c);
1493
+ const v = kv.substring(c + 1);
1494
+ if (k === "semver") {
1495
+ if (committish) {
1496
+ throw error(
1497
+ "Cannot specify a semver range and committish value",
1498
+ { spec }
1499
+ );
1500
+ }
1501
+ range = parseRange(v);
1502
+ if (!range) {
1503
+ throw error(`Invalid git tag semver range: ${v}`, { spec });
1504
+ }
1505
+ }
1506
+ if (k === "semver" || k === "path") {
1507
+ if (k === "path") {
1508
+ if (
1509
+ /* c8 ignore next */
1510
+ this.nodejsDependencies?.isAbsolute(
1511
+ v
1512
+ ) || /(^|\/|\\)\.\.($|\\|\/)/.test(v)
1513
+ ) {
1514
+ throw error("Invalid path in git selector", { spec });
1515
+ }
1516
+ parsed.path = (this.nodejsDependencies ? this.nodejsDependencies.join("/", v).substring(1) : v).replace(/\\/g, "/");
1517
+ } else {
1518
+ parsed[k] = v;
1519
+ }
1520
+ }
1521
+ }
1522
+ return [parsed, committish, range];
1523
+ }
1524
+ };
1525
+ var getNormalizeFile = (opts) => (bareSpec, spec) => {
1526
+ const slashes = bareSpec.substring(
1527
+ "file:".length,
1528
+ "file://".length
1529
+ );
1530
+ const pref = `file:${slashes === "//" ? slashes : ""}`;
1531
+ const rest = bareSpec.substring(pref.length);
1532
+ const [a = "", b = "/", c = "/", d = "/"] = rest.split("", 4);
1533
+ if (!a) {
1534
+ return [".", "file:."];
1535
+ }
1536
+ if (a === "/" && b === "~" && c !== "/" || a === "~" && b !== "/") {
1537
+ throw error(
1538
+ `invalid file: specifier. '~username' not supported`,
1539
+ { spec }
1540
+ );
1541
+ }
1542
+ if (a === "~") {
1543
+ return (
1544
+ /* c8 ignore start */
1545
+ opts ? [
1546
+ opts.resolve(opts.homedir(), rest.substring(2)),
1547
+ `file:${rest}`
1548
+ ] : [rest, `file:${rest}`]
1549
+ );
1550
+ }
1551
+ if (a === "/" && b === "~") {
1552
+ return opts ? [
1553
+ opts.resolve(opts.homedir(), rest.substring(3)),
1554
+ `file:${rest.substring(1)}`
1555
+ ] : (
1556
+ /* c8 ignore stop */
1557
+ [rest.substring(1), `file:${rest.substring(1)}`]
1558
+ );
1559
+ }
1560
+ if (a === "/" && b === "." && (c === "/" || c === "." && d === "/")) {
1561
+ return [rest.substring(1), `file:${rest.substring(1)}`];
1562
+ }
1563
+ if (a === "." && (b === "/" || b === "." && c === "/")) {
1564
+ return [rest, `file:${rest}`];
1565
+ }
1566
+ if (slashes === "//") {
1567
+ try {
1568
+ const parsed = new URL(bareSpec);
1569
+ if (parsed.host) {
1570
+ if (parsed.host !== "localhost") {
1571
+ throw error(
1572
+ `invalid file:// specifier. host must be empty or 'localhost'`,
1573
+ {
1574
+ spec,
1575
+ found: parsed.host,
1576
+ validOptions: ["", "localhost"]
1577
+ }
1578
+ );
1579
+ }
1580
+ }
1581
+ return [
1582
+ parsed.pathname.replace(/^\/([a-zA-Z]:\/)/, "$1"),
1583
+ `file://${parsed.pathname}`
1584
+ ];
1585
+ } catch (er) {
1586
+ throw error("invalid file:// specifier", {
1587
+ spec,
1588
+ cause: er
1589
+ });
1590
+ }
1591
+ }
1592
+ if (opts?.winPath.isAbsolute(rest)) {
1593
+ return [rest, `file://${rest}`];
1594
+ }
1595
+ return [`./${rest}`, `file:./${rest}`];
1596
+ };
1597
+
923
1598
  // ../../src/types/src/index.ts
1599
+ import { posix } from "node:path";
1600
+ import { debuglog } from "node:util";
1601
+ var debug = debuglog("vlt");
924
1602
  var normalizeFundingEntry = (item) => {
925
1603
  const getTypeFromUrl = (url) => {
926
1604
  try {
@@ -1199,14 +1877,35 @@ var isNormalizedLibc = (o) => {
1199
1877
  (item) => typeof item === "string" && !!item && !item.startsWith(" ") && !item.endsWith(" ")
1200
1878
  );
1201
1879
  };
1880
+ var unixify = (ref) => ref.replace(/[\\:]/g, "/");
1881
+ var secure = (ref) => {
1882
+ const s = unixify(posix.join(".", posix.join("/", unixify(ref))));
1883
+ return s === "./" ? "" : s;
1884
+ };
1885
+ var secureBinPaths = (bin) => {
1886
+ const res = {};
1887
+ for (const [key, val] of Object.entries(bin)) {
1888
+ const v = typeof val === "string" ? secure(val) : "";
1889
+ const k = posix.basename(secure(key));
1890
+ if (!k || !v) {
1891
+ debug("dropped unusable bin entry", key, val);
1892
+ continue;
1893
+ }
1894
+ if (k !== key || v !== val) {
1895
+ debug("rewrote unsafe bin entry", key, val, "->", k, v);
1896
+ }
1897
+ res[k] = v;
1898
+ }
1899
+ return res;
1900
+ };
1202
1901
  var normalizeBinPaths = (manifest) => {
1203
1902
  const { name, bin } = manifest;
1204
1903
  if (bin) {
1205
1904
  if (name && typeof bin === "string") {
1206
1905
  const [_scope, pkg] = parseScope(name);
1207
- return { [pkg]: bin };
1906
+ return secureBinPaths({ [pkg]: bin });
1208
1907
  } else if (typeof bin === "object") {
1209
- return bin;
1908
+ return secureBinPaths(bin);
1210
1909
  }
1211
1910
  }
1212
1911
  };
@@ -1250,11 +1949,14 @@ var asManifest = (m, from) => {
1250
1949
  return m;
1251
1950
  };
1252
1951
  var normalizeManifestCache = /* @__PURE__ */ new WeakMap();
1253
- var normalizeManifest = (manifest) => {
1952
+ var normalizeManifest = (manifest, from) => {
1254
1953
  const cached = normalizeManifestCache.get(manifest);
1255
1954
  if (cached) {
1256
1955
  return cached;
1257
1956
  }
1957
+ if (manifest.name !== void 0) {
1958
+ assertPathSafeName(manifest.name, from);
1959
+ }
1258
1960
  manifest = fixManifestVersion(manifest);
1259
1961
  const normalizedAuthor = parsePerson(manifest.author);
1260
1962
  const normalizedFunding = normalizeFunding(manifest.funding);
@@ -1491,16 +2193,25 @@ var parse = (version) => {
1491
2193
  return void 0;
1492
2194
  }
1493
2195
  };
2196
+ var rangeCache = /* @__PURE__ */ new Map();
2197
+ var MAX_RANGE_CACHE = 4096;
1494
2198
  var parseRange = (range, includePrerelease = false) => {
1495
2199
  if (typeof range === "object") {
1496
2200
  if (range.includePrerelease === includePrerelease) return range;
1497
2201
  range = range.raw;
1498
2202
  }
2203
+ const key = `${+includePrerelease}\0${range}`;
2204
+ const cached = rangeCache.get(key);
2205
+ if (cached !== void 0 || rangeCache.has(key)) return cached;
2206
+ let parsed;
1499
2207
  try {
1500
- return new Range(range, includePrerelease);
2208
+ parsed = new Range(range, includePrerelease);
1501
2209
  } catch {
1502
- return void 0;
2210
+ parsed = void 0;
1503
2211
  }
2212
+ if (rangeCache.size >= MAX_RANGE_CACHE) rangeCache.clear();
2213
+ rangeCache.set(key, parsed);
2214
+ return parsed;
1504
2215
  };
1505
2216
  var satisfies = (version, range, includePrerelease = false) => {
1506
2217
  if (typeof version === "string") {
@@ -1536,14 +2247,24 @@ var eq = (versionA, versionB) => compare(versionA, versionB) === 0;
1536
2247
  var major = (version) => parse(version)?.major;
1537
2248
  var minor = (version) => parse(version)?.minor;
1538
2249
  var patch = (version) => parse(version)?.patch;
2250
+ var intersectsCache = /* @__PURE__ */ new WeakMap();
1539
2251
  var intersects = (r1, r2, includePrerelease) => {
1540
2252
  const range1 = typeof r1 === "string" ? parseRange(r1, includePrerelease) : r1;
1541
2253
  const range2 = typeof r2 === "string" ? parseRange(r2, includePrerelease) : r2;
1542
2254
  if (!range1 || !range2) return false;
1543
2255
  if (range1.isAny || range2.isAny) return true;
1544
- return range1.set.some(
2256
+ let inner = intersectsCache.get(range1);
2257
+ const cached = inner?.get(range2);
2258
+ if (cached !== void 0) return cached;
2259
+ const result = range1.set.some(
1545
2260
  (set1) => range2.set.some((set2) => intersectComparators(set1, set2))
1546
2261
  );
2262
+ if (!inner) {
2263
+ inner = /* @__PURE__ */ new WeakMap();
2264
+ intersectsCache.set(range1, inner);
2265
+ }
2266
+ inner.set(range2, result);
2267
+ return result;
1547
2268
  };
1548
2269
  var subset = (r1, r2, includePrerelease) => {
1549
2270
  const range1 = typeof r1 === "string" ? parseRange(r1, includePrerelease) : r1;
@@ -1738,6 +2459,19 @@ export {
1738
2459
  patch,
1739
2460
  intersects,
1740
2461
  subset,
2462
+ assertPathSafeName,
2463
+ kCustomInspect,
2464
+ defaultRegistryName,
2465
+ defaultRegistries,
2466
+ defaultJsrRegistries,
2467
+ defaultGitHosts,
2468
+ defaultGitHostArchives,
2469
+ gitHostWebsites,
2470
+ defaultScopeRegistries,
2471
+ getOptions,
2472
+ isSpec,
2473
+ currentDefaultRegistryName,
2474
+ Spec,
1741
2475
  asError,
1742
2476
  isError,
1743
2477
  isErrorWithCause,