nxds-cli 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +59 -18
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -178,17 +178,42 @@ function readJson(file) {
178
178
  }
179
179
  }
180
180
 
181
+ // src/url.ts
182
+ function httpUrl(value) {
183
+ const url = URL.canParse(value) ? new URL(value) : void 0;
184
+ return url?.protocol === "http:" || url?.protocol === "https:" ? url : void 0;
185
+ }
186
+ function assertRegistryUrl(flag, value, privateRegistryHint) {
187
+ const url = httpUrl(value);
188
+ if (!url) {
189
+ throw new UsageError(
190
+ `${flag} is not a valid http or https URL. ${privateRegistryHint}`
191
+ );
192
+ }
193
+ if (url.username || url.password || /[?#]/.test(value)) {
194
+ throw new UsageError(
195
+ `${flag} can't include a user name, password, query or fragment. nxds-cli sends no registry login, and it adds file paths to the URL. ${privateRegistryHint}`
196
+ );
197
+ }
198
+ }
199
+
181
200
  // src/catalog.ts
182
201
  var SETUP = "setup";
183
202
  var DEFAULT_REGISTRY = "https://nxds.dev/r";
184
203
  var FETCH_TIMEOUT_MS = 3e4;
185
204
  var dispatcher = new EnvHttpProxyAgent();
186
205
  function isUrl(registry) {
187
- return /^https?:\/\//.test(registry);
206
+ return /^\s*[a-z][a-z\d+.-]+:/i.test(registry);
188
207
  }
189
208
  function resolveRegistry(option) {
190
209
  if (!option) return DEFAULT_REGISTRY;
191
- return isUrl(option) ? option.replace(/\/+$/, "") : path2.resolve(option);
210
+ if (!isUrl(option)) return path2.resolve(option);
211
+ assertRegistryUrl(
212
+ "--registry (or NXDS_REGISTRY_URL)",
213
+ option,
214
+ "For a private registry, download its latest.json and <version>.json files to a folder, and pass the folder with --registry."
215
+ );
216
+ return option.replace(/\/+$/, "");
192
217
  }
193
218
  function timeoutError(url, error) {
194
219
  if (!(error instanceof Error) || error.name !== "TimeoutError") return null;
@@ -244,7 +269,7 @@ async function fetchRelease(registry, version) {
244
269
  if (isNewerSchema(value)) {
245
270
  const release = version === "latest" ? "The latest nxds release" : `nxds ${version}`;
246
271
  throw new CliError(
247
- `${release} needs a newer nxds-cli than ${"0.4.0"}. Run \`${CLI_COMMAND}\` to get the newest one.`
272
+ `${release} needs a newer nxds-cli than ${"0.4.1"}. Run \`${CLI_COMMAND}\` to get the newest one.`
248
273
  );
249
274
  }
250
275
  const invalid = (problems) => new CliError(
@@ -1615,7 +1640,16 @@ var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
1615
1640
  var DEFAULT_EXPORT_DIR = "nxds-design-system";
1616
1641
  var FETCH_TIMEOUT_MS2 = 6e4;
1617
1642
  var dispatcher2 = new EnvHttpProxyAgent2();
1643
+ function redactUrl(url) {
1644
+ const redacted = httpUrl(url);
1645
+ if (!redacted) return "<invalid URL>";
1646
+ redacted.username = "";
1647
+ redacted.password = "";
1648
+ redacted.search = "";
1649
+ return redacted.href;
1650
+ }
1618
1651
  async function download(url) {
1652
+ const shown = redactUrl(url);
1619
1653
  let response;
1620
1654
  try {
1621
1655
  response = await fetch2(url, {
@@ -1624,14 +1658,14 @@ async function download(url) {
1624
1658
  });
1625
1659
  } catch (error) {
1626
1660
  const { message, cause } = error;
1627
- const reason = cause instanceof Error ? cause.message : message;
1661
+ const reason = (cause instanceof Error ? cause.message : message).replaceAll(url, () => shown);
1628
1662
  throw new CliError(
1629
- `Could not reach ${url} (${reason}). Check your connection, or set HTTPS_PROXY if you are behind a proxy, then run the command again.`
1663
+ `Could not reach ${shown} (${reason}). Check your connection, or set HTTPS_PROXY if you are behind a proxy, then run the command again.`
1630
1664
  );
1631
1665
  }
1632
1666
  if (!response.ok) {
1633
1667
  throw new CliError(
1634
- `${url} answered ${response.status}. Run the command again later.`
1668
+ `${shown} answered ${response.status}. Run the command again later.`
1635
1669
  );
1636
1670
  }
1637
1671
  return Buffer.from(await response.arrayBuffer());
@@ -1640,6 +1674,11 @@ function packageUrl(registry) {
1640
1674
  return `${registry.replace(/\/+$/, "")}/${CLAUDE_DESIGN_PACKAGE.replace("/", "%2f")}`;
1641
1675
  }
1642
1676
  async function resolveTarball(registry, release) {
1677
+ assertRegistryUrl(
1678
+ "--npm-registry (or npm_config_registry)",
1679
+ registry,
1680
+ `For a private registry, unpack the tarball from \`npm pack ${CLAUDE_DESIGN_PACKAGE}\` and pass its package folder with --source.`
1681
+ );
1643
1682
  const url = packageUrl(registry);
1644
1683
  const body = (await download(url)).toString("utf8");
1645
1684
  let packument;
@@ -1647,7 +1686,7 @@ async function resolveTarball(registry, release) {
1647
1686
  packument = JSON.parse(body);
1648
1687
  } catch {
1649
1688
  throw new CliError(
1650
- `${url} didn't answer with JSON. Check --npm-registry, or your proxy, then run the command again.`
1689
+ `${redactUrl(url)} didn't answer with JSON. Check --npm-registry, or your proxy, then run the command again.`
1651
1690
  );
1652
1691
  }
1653
1692
  const version = packument["dist-tags"]?.[release] ?? release;
@@ -1664,13 +1703,13 @@ function checkIntegrity(bytes, integrity, tarball) {
1664
1703
  const expected = integrity.split(/\s+/).find((entry) => entry.startsWith("sha512-"));
1665
1704
  if (!expected) {
1666
1705
  throw new CliError(
1667
- `${tarball} has no sha512 integrity to check it against.`
1706
+ `${redactUrl(tarball)} has no sha512 integrity to check it against.`
1668
1707
  );
1669
1708
  }
1670
1709
  const actual = `sha512-${createHash("sha512").update(bytes).digest("base64")}`;
1671
1710
  if (actual !== expected) {
1672
1711
  throw new CliError(
1673
- `${tarball} doesn't match its published integrity. Run the command again; if it keeps failing, report it.`
1712
+ `${redactUrl(tarball)} doesn't match its published integrity. Run the command again; if it keeps failing, report it.`
1674
1713
  );
1675
1714
  }
1676
1715
  }
@@ -2233,12 +2272,13 @@ async function update(cwd, registry, options) {
2233
2272
  }
2234
2273
 
2235
2274
  // src/cli.ts
2275
+ function cwdOf(command) {
2276
+ const { cwd } = command.optsWithGlobals();
2277
+ return path13.resolve(cwd ?? process.cwd());
2278
+ }
2236
2279
  function context(command) {
2237
- const { cwd, registry } = command.optsWithGlobals();
2238
- return {
2239
- cwd: path13.resolve(cwd ?? process.cwd()),
2240
- registry: resolveRegistry(registry)
2241
- };
2280
+ const { registry } = command.optsWithGlobals();
2281
+ return { cwd: cwdOf(command), registry: resolveRegistry(registry) };
2242
2282
  }
2243
2283
  function installOptions(command) {
2244
2284
  const flags = command.opts();
@@ -2258,7 +2298,7 @@ function program(done, write) {
2258
2298
  // Errors are printed once, by `main`, as text or JSON.
2259
2299
  outputError: () => {
2260
2300
  }
2261
- }).exitOverride().name(CLI_COMMAND).description("Add nxds to your app.").version("0.4.0", "-v, --version", "print the version").helpOption("-h, --help", "show help").helpCommand("help [command]", "show help for a command").option("--json", "print machine-readable JSON").option("--cwd <path>", "run in another folder").addOption(
2301
+ }).exitOverride().name(CLI_COMMAND).description("Add nxds to your app.").version("0.4.1", "-v, --version", "print the version").helpOption("-h, --help", "show help").helpCommand("help [command]", "show help for a command").option("--json", "print machine-readable JSON").option("--cwd <path>", "run in another folder").addOption(
2262
2302
  new Option(
2263
2303
  "--registry <url|path>",
2264
2304
  "where to get nxds releases (default: https://nxds.dev/r)"
@@ -2312,7 +2352,7 @@ Docs: https://nxds.dev/getting-started/install`
2312
2352
  done(await view(cwd, registry, item));
2313
2353
  });
2314
2354
  cli.command("info").description("show what the CLI detects in this app").action((_options, command) => {
2315
- done(info(context(command).cwd));
2355
+ done(info(cwdOf(command)));
2316
2356
  });
2317
2357
  cli.command("diff").description("compare your nxds files with the latest release").argument("[items...]", "item names (default: every installed item)").action(async (items, _options, command) => {
2318
2358
  const { cwd, registry } = context(command);
@@ -2337,8 +2377,9 @@ Docs: https://nxds.dev/getting-started/install`
2337
2377
  `npm registry to download from (default: ${DEFAULT_NPM_REGISTRY})`
2338
2378
  ).env("npm_config_registry")
2339
2379
  ).action(async (_target, _options, command) => {
2340
- const { cwd } = context(command);
2341
- done(await exportClaudeDesign(cwd, command.opts()));
2380
+ done(
2381
+ await exportClaudeDesign(cwdOf(command), command.opts())
2382
+ );
2342
2383
  });
2343
2384
  cli.command("doctor").description("check that nxds is wired up correctly").action(async (_options, command) => {
2344
2385
  const { cwd, registry } = context(command);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nxds-cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "Install nxds components, blocks and setup into your app.",
6
6
  "keywords": [
@@ -45,8 +45,8 @@
45
45
  "@types/semver": "^7.8.0",
46
46
  "tsup": "^8.5.1",
47
47
  "typescript": "^5.9.3",
48
- "@nxds/catalog": "0.0.0",
49
- "@nxds/claude-design": "0.6.0"
48
+ "@nxds/claude-design": "0.8.1",
49
+ "@nxds/catalog": "0.0.0"
50
50
  },
51
51
  "scripts": {
52
52
  "build": "tsup",