@geolonia/geonicdb-cli 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -77,6 +77,7 @@ geonic entities list --help
77
77
  | `-f, --format <fmt>` | Output format: `json`, `table`, `geojson` |
78
78
  | `--no-color` | Disable color output |
79
79
  | `-v, --verbose` | Verbose output |
80
+ | `--dry-run` | Print the equivalent `curl` command without executing |
80
81
 
81
82
  Options are resolved in this order (first wins):
82
83
 
@@ -388,6 +389,31 @@ Specify the output format with `--format` or `geonic config set format <fmt>`.
388
389
 
389
390
  Use `--key-values` on `entities list` and `entities get` to request simplified key-value format from the API.
390
391
 
392
+ ## Dry Run
393
+
394
+ Use `--dry-run` on any command to print the equivalent `curl` command instead of executing the request. The output can be copied and run directly in a terminal.
395
+
396
+ ```bash
397
+ $ geonic entities list --type Sensor --dry-run
398
+ curl \
399
+ -H 'Content-Type: application/ld+json' \
400
+ -H 'Accept: application/ld+json' \
401
+ -H 'Authorization: Bearer <token>' \
402
+ 'http://localhost:3000/ngsi-ld/v1/entities?type=Sensor'
403
+ ```
404
+
405
+ Works with all operations including POST with body:
406
+
407
+ ```bash
408
+ $ geonic entities create '{"id":"Room1","type":"Room"}' --dry-run
409
+ curl \
410
+ -X POST \
411
+ -H 'Content-Type: application/ld+json' \
412
+ -H 'Accept: application/ld+json' \
413
+ -d '{"id":"Room1","type":"Room"}' \
414
+ 'http://localhost:3000/ngsi-ld/v1/entities'
415
+ ```
416
+
391
417
  ## Configuration
392
418
 
393
419
  The CLI stores configuration in `~/.config/geonic/config.json`.
package/dist/index.js CHANGED
@@ -585,6 +585,12 @@ function registerConfigCommand(program2) {
585
585
  import { Command } from "commander";
586
586
 
587
587
  // src/client.ts
588
+ var DryRunSignal = class extends Error {
589
+ constructor() {
590
+ super("dry-run");
591
+ this.name = "DryRunSignal";
592
+ }
593
+ };
588
594
  var GdbClient = class _GdbClient {
589
595
  baseUrl;
590
596
  service;
@@ -593,6 +599,7 @@ var GdbClient = class _GdbClient {
593
599
  apiKey;
594
600
  onTokenRefresh;
595
601
  verbose;
602
+ dryRun;
596
603
  refreshPromise;
597
604
  constructor(options) {
598
605
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
@@ -602,6 +609,7 @@ var GdbClient = class _GdbClient {
602
609
  this.apiKey = options.apiKey;
603
610
  this.onTokenRefresh = options.onTokenRefresh;
604
611
  this.verbose = options.verbose ?? false;
612
+ this.dryRun = options.dryRun ?? false;
605
613
  }
606
614
  buildHeaders(extra) {
607
615
  const headers = {};
@@ -682,6 +690,28 @@ var GdbClient = class _GdbClient {
682
690
  });
683
691
  process.stderr.write("\n");
684
692
  }
693
+ static shellQuote(value) {
694
+ return `'${value.split("'").join(`'"'"'`)}'`;
695
+ }
696
+ static buildCurlCommand(method, url, headers, body) {
697
+ const parts = ["curl"];
698
+ if (method !== "GET") {
699
+ parts.push(`-X ${method}`);
700
+ }
701
+ for (const [key, value] of Object.entries(headers)) {
702
+ parts.push(`-H ${_GdbClient.shellQuote(`${key}: ${value}`)}`);
703
+ }
704
+ if (body) {
705
+ parts.push(`-d ${_GdbClient.shellQuote(body)}`);
706
+ }
707
+ parts.push(_GdbClient.shellQuote(url));
708
+ return parts.join(" \\\n ");
709
+ }
710
+ handleDryRun(method, url, headers, body) {
711
+ if (!this.dryRun) return;
712
+ console.log(_GdbClient.buildCurlCommand(method, url, headers, body));
713
+ throw new DryRunSignal();
714
+ }
685
715
  canRefresh() {
686
716
  return !!this.refreshToken && !this.apiKey;
687
717
  }
@@ -721,6 +751,7 @@ var GdbClient = class _GdbClient {
721
751
  const headers = this.buildHeaders(options?.headers);
722
752
  const body = options?.body ? JSON.stringify(options.body) : void 0;
723
753
  this.logRequest(method, url, headers, body);
754
+ this.handleDryRun(method, url, headers, body);
724
755
  const response = await fetch(url, { method, headers, body });
725
756
  this.logResponse(response);
726
757
  const countHeader = response.headers.get("NGSILD-Results-Count");
@@ -745,6 +776,7 @@ var GdbClient = class _GdbClient {
745
776
  const headers = this.buildHeaders(options?.headers);
746
777
  const body = options?.body ? JSON.stringify(options.body) : void 0;
747
778
  this.logRequest(method, url, headers, body);
779
+ this.handleDryRun(method, url, headers, body);
748
780
  const response = await fetch(url, { method, headers, body });
749
781
  this.logResponse(response);
750
782
  let data;
@@ -826,7 +858,8 @@ function resolveOptions(cmd) {
826
858
  color: opts.color,
827
859
  verbose: opts.verbose,
828
860
  profile: opts.profile,
829
- apiKey: opts.apiKey ?? process.env.GDB_API_KEY ?? config.apiKey
861
+ apiKey: opts.apiKey ?? process.env.GDB_API_KEY ?? config.apiKey,
862
+ dryRun: opts.dryRun
830
863
  };
831
864
  }
832
865
  function createClient(cmd) {
@@ -851,7 +884,8 @@ function createClient(cmd) {
851
884
  if (refreshToken) cfg.refreshToken = refreshToken;
852
885
  saveConfig(cfg, opts.profile);
853
886
  },
854
- verbose: opts.verbose
887
+ verbose: opts.verbose,
888
+ dryRun: opts.dryRun
855
889
  });
856
890
  }
857
891
  function getFormat(cmd) {
@@ -871,6 +905,9 @@ function withErrorHandler(fn) {
871
905
  try {
872
906
  await fn(...args);
873
907
  } catch (err) {
908
+ if (err instanceof DryRunSignal) {
909
+ return;
910
+ }
874
911
  if (err instanceof GdbClientError && err.status === 401) {
875
912
  printError("Authentication failed. Please run `geonic login` to re-authenticate.");
876
913
  } else if (err instanceof Error) {
@@ -3379,7 +3416,7 @@ function createProgram() {
3379
3416
  const require2 = createRequire3(import.meta.url);
3380
3417
  const pkg = require2("../package.json");
3381
3418
  const program2 = new Command2();
3382
- program2.name("geonic").description(pkg.description).option("-u, --url <url>", "Base URL of the GeonicDB server").option("-s, --service <name>", "NGSILD-Tenant header").option("--token <token>", "Authentication token").option("-p, --profile <name>", "Use a named profile").option("--api-key <key>", "API key for authentication").option("-f, --format <fmt>", "Output format: json, table, geojson").option("--no-color", "Disable color output").option("-v, --verbose", "Verbose output");
3419
+ program2.name("geonic").description(pkg.description).option("-u, --url <url>", "Base URL of the GeonicDB server").option("-s, --service <name>", "NGSILD-Tenant header").option("--token <token>", "Authentication token").option("-p, --profile <name>", "Use a named profile").option("--api-key <key>", "API key for authentication").option("-f, --format <fmt>", "Output format: json, table, geojson").option("--no-color", "Disable color output").option("-v, --verbose", "Verbose output").option("--dry-run", "Print the equivalent curl command without executing");
3383
3420
  registerHelpCommand(program2);
3384
3421
  registerConfigCommand(program2);
3385
3422
  registerAuthCommands(program2);