@drupal-canvas/cli 0.5.1 → 0.6.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.
package/README.md CHANGED
@@ -40,7 +40,6 @@ to get started.
40
40
  | `--client-id` | `CANVAS_CLIENT_ID` | OAuth client ID. |
41
41
  | `--client-secret` | `CANVAS_CLIENT_SECRET` | OAuth client secret. |
42
42
  | `--dir` | `CANVAS_COMPONENT_DIR` | Directory where code components are stored in the filesystem. |
43
- | `--verbose` | `CANVAS_VERBOSE` | Verbose CLI output for troubleshooting. Defaults to `false`. |
44
43
  | `--scope` | `CANVAS_SCOPE` | (Optional) Space-separated list of OAuth scopes to request. |
45
44
 
46
45
  **Note:** The `--scope` parameter defaults to
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ import { parse } from '@babel/parser';
25
25
 
26
26
  // package.json
27
27
  var package_default = {
28
- version: "0.5.1"};
28
+ };
29
29
  function loadEnvFiles() {
30
30
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
31
31
  if (homeDir) {
@@ -46,7 +46,6 @@ var config = {
46
46
  clientSecret: process.env.CANVAS_CLIENT_SECRET || "",
47
47
  scope: process.env.CANVAS_SCOPE || "canvas:js_component canvas:asset_library",
48
48
  componentDir: process.env.CANVAS_COMPONENT_DIR || "./components",
49
- verbose: process.env.CANVAS_VERBOSE === "true",
50
49
  userAgent: process.env.CANVAS_USER_AGENT || ""
51
50
  };
52
51
  function getConfig() {
@@ -10672,107 +10671,138 @@ var ApiService = class _ApiService {
10672
10671
  throw new Error("Failed to update global asset library");
10673
10672
  }
10674
10673
  }
10675
- handleApiError(error) {
10676
- const config2 = getConfig();
10677
- const verbose = config2.verbose;
10678
- if (axios.isAxiosError(error)) {
10679
- if (error.response) {
10680
- const status = error.response.status;
10681
- const data = error.response.data;
10682
- if (verbose && status !== 404) {
10683
- console.error("API Error Details:");
10684
- console.error(`- Status: ${status}`);
10685
- console.error(`- URL: ${error.config?.url || "unknown"}`);
10686
- console.error(
10687
- `- Method: ${error.config?.method?.toUpperCase() || "unknown"}`
10688
- );
10689
- console.error("- Response data:", JSON.stringify(data, null, 2));
10690
- const safeHeaders = { ...error.config?.headers };
10691
- if (safeHeaders && safeHeaders.Authorization) {
10692
- safeHeaders.Authorization = "Bearer ********";
10693
- }
10694
- console.error(
10695
- "- Request headers:",
10696
- JSON.stringify(safeHeaders, null, 2)
10697
- );
10698
- }
10699
- if (status === 401) {
10700
- throw new Error(
10701
- "Authentication failed. Please check your client ID and secret."
10702
- );
10703
- } else if (status === 403) {
10704
- throw new Error(
10705
- "You do not have permission to perform this action. Check your configured scope."
10706
- );
10707
- } else if (data && (data.error || data.error_description || data.hint)) {
10708
- throw new Error(
10709
- `API Error (${status}): ${[
10710
- data.error,
10711
- data.error_description,
10712
- data.hint
10713
- ].filter(Boolean).join(" | ")}`
10714
- );
10715
- } else {
10716
- throw new Error(`API Error (${status}): ${error.message}`);
10674
+ /**
10675
+ * Parse Canvas API error responses into user-friendly messages.
10676
+ * Handles both structured validation errors and simple string errors.
10677
+ */
10678
+ parseCanvasErrors(data) {
10679
+ if (data && typeof data === "object" && "errors" in data && Array.isArray(data.errors)) {
10680
+ return data.errors.map((err) => {
10681
+ if (typeof err === "string") {
10682
+ return err.trim();
10717
10683
  }
10718
- } else if (error.request) {
10719
- if (verbose) {
10720
- console.error("Network Error Details:");
10721
- console.error(`- No response received from server`);
10722
- console.error(`- URL: ${error.config?.url || "unknown"}`);
10723
- console.error(
10724
- `- Method: ${error.config?.method?.toUpperCase() || "unknown"}`
10725
- );
10726
- const safeHeaders = { ...error.config?.headers };
10727
- if (safeHeaders && safeHeaders.Authorization) {
10728
- safeHeaders.Authorization = "Bearer ********";
10684
+ if (err && typeof err === "object" && "detail" in err) {
10685
+ let message = typeof err.detail === "string" ? err.detail : String(err.detail);
10686
+ message = message.replace(/<[^>]*>/g, "").replace(/&quot;/g, '"').replace(/&#039;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").trim();
10687
+ if (!message) {
10688
+ return "";
10729
10689
  }
10730
- console.error(
10731
- "- Request headers:",
10732
- JSON.stringify(safeHeaders, null, 2)
10733
- );
10734
- if (this.siteUrl.includes("ddev.site")) {
10735
- console.error("\nDDEV Local Development Troubleshooting Tips:");
10736
- console.error('1. Make sure DDEV is running: try "ddev status"');
10737
- console.error(
10738
- '2. Try using HTTP instead of HTTPS: use "http://drupal-dev.ddev.site" as URL'
10739
- );
10740
- console.error("3. Check if the site is accessible in your browser");
10741
- console.error(
10742
- '4. For HTTPS issues: Try "ddev auth ssl" to set up local SSL certificates'
10743
- );
10690
+ if ("source" in err && err.source && typeof err.source === "object" && "pointer" in err.source && typeof err.source.pointer === "string" && err.source.pointer !== "") {
10691
+ message = `[${err.source.pointer}] ${message}`;
10744
10692
  }
10693
+ return message;
10745
10694
  }
10746
- if (this.siteUrl.includes("ddev.site")) {
10747
- throw new Error(
10748
- `Network error: No response from DDEV site. Is DDEV running? Try using HTTP instead of HTTPS.`
10749
- );
10750
- } else {
10751
- throw new Error(
10752
- `Network error: No response from server. Check your site URL and internet connection.`
10753
- );
10754
- }
10695
+ return "";
10696
+ }).filter((msg) => msg !== "");
10697
+ }
10698
+ return [];
10699
+ }
10700
+ /**
10701
+ * Throws an appropriate error based on the API response.
10702
+ */
10703
+ throwApiError(status, data, error, canvasErrors) {
10704
+ if (canvasErrors.length > 0) {
10705
+ const errorList = canvasErrors.join("\n\n").trim();
10706
+ if (errorList) {
10707
+ throw new Error(errorList);
10708
+ }
10709
+ }
10710
+ if (status === 401) {
10711
+ let message = "Authentication failed. Please check your client ID and secret.";
10712
+ if (data && typeof data === "object" && "error_description" in data && typeof data.error_description === "string") {
10713
+ message = `Authentication Error: ${data.error_description}
10714
+
10715
+ ${message}`;
10716
+ }
10717
+ throw new Error(message);
10718
+ }
10719
+ if (status === 403) {
10720
+ throw new Error(
10721
+ "You do not have permission to perform this action. Check your configured scope."
10722
+ );
10723
+ }
10724
+ if (status === 404) {
10725
+ const url2 = error.config?.url || "unknown";
10726
+ let message = `API endpoint not found: ${url2}
10727
+
10728
+ `;
10729
+ if (this.siteUrl.includes("ddev.site")) {
10730
+ message += "Possible causes:\n";
10731
+ message += " \u2022 DDEV is not running (run: ddev start)\n";
10732
+ message += " \u2022 Canvas module is not enabled (run: ddev drush en canvas -y)\n";
10733
+ message += " \u2022 Site URL is incorrect";
10755
10734
  } else {
10756
- if (verbose) {
10757
- console.error("Request Setup Error:");
10758
- console.error(`- Error: ${error.message}`);
10759
- console.error("- Stack:", error.stack);
10760
- }
10761
- throw new Error(`Request setup error: ${error.message}`);
10735
+ message += "Possible causes:\n";
10736
+ message += " \u2022 Canvas module is not enabled\n";
10737
+ message += " \u2022 Site URL is incorrect\n";
10738
+ message += " \u2022 Server is not responding correctly";
10739
+ }
10740
+ throw new Error(message);
10741
+ }
10742
+ if (data && typeof data === "object" && "message" in data && typeof data.message === "string") {
10743
+ throw new Error(data.message);
10744
+ }
10745
+ if (data && typeof data === "object") {
10746
+ const errorParts = [];
10747
+ if ("error" in data && typeof data.error === "string") {
10748
+ errorParts.push(data.error);
10762
10749
  }
10763
- } else if (error instanceof Error) {
10764
- if (verbose) {
10765
- console.error("General Error:");
10766
- console.error(`- Message: ${error.message}`);
10767
- console.error("- Stack:", error.stack);
10750
+ if ("error_description" in data && typeof data.error_description === "string") {
10751
+ errorParts.push(data.error_description);
10768
10752
  }
10769
- throw new Error(`Network error: ${error.message}`);
10753
+ if ("hint" in data && typeof data.hint === "string") {
10754
+ errorParts.push(data.hint);
10755
+ }
10756
+ if (errorParts.length > 0) {
10757
+ throw new Error(`API Error (${status}): ${errorParts.join(" | ")}`);
10758
+ }
10759
+ }
10760
+ const url = error.config?.url || "unknown";
10761
+ const method = error.config?.method?.toUpperCase() || "unknown";
10762
+ throw new Error(
10763
+ `API Error (${status}): ${error.message}
10764
+
10765
+ URL: ${url}
10766
+ Method: ${method}`
10767
+ );
10768
+ }
10769
+ /**
10770
+ * Handles network errors (no response from server).
10771
+ */
10772
+ handleNetworkError() {
10773
+ let message = `No response from: ${this.siteUrl}
10774
+
10775
+ `;
10776
+ if (this.siteUrl.includes("ddev.site")) {
10777
+ message += "Troubleshooting tips:\n";
10778
+ message += " \u2022 Check if DDEV is running: ddev status\n";
10779
+ message += " \u2022 Try HTTP instead of HTTPS\n";
10780
+ message += " \u2022 Verify site is accessible in browser\n";
10781
+ message += " \u2022 For HTTPS issues, try: ddev auth ssl";
10770
10782
  } else {
10771
- if (verbose) {
10772
- console.error("Unknown Error:", error);
10783
+ message += "Check your site URL and internet connection.";
10784
+ }
10785
+ throw new Error(message);
10786
+ }
10787
+ /**
10788
+ * Main error handler for API requests.
10789
+ */
10790
+ handleApiError(error) {
10791
+ if (!axios.isAxiosError(error)) {
10792
+ if (error instanceof Error) {
10793
+ throw error;
10773
10794
  }
10774
10795
  throw new Error("Unknown API error occurred");
10775
10796
  }
10797
+ if (error.response) {
10798
+ const { status, data } = error.response;
10799
+ const canvasErrors = this.parseCanvasErrors(data);
10800
+ this.throwApiError(status, data, error, canvasErrors);
10801
+ }
10802
+ if (error.request) {
10803
+ this.handleNetworkError();
10804
+ }
10805
+ throw new Error(`Request setup error: ${error.message}`);
10776
10806
  }
10777
10807
  };
10778
10808
  function createApiService() {
@@ -11114,7 +11144,6 @@ function updateConfigFromOptions(options) {
11114
11144
  if (options.dir) setConfig({ componentDir: options.dir });
11115
11145
  if (options.scope) setConfig({ scope: options.scope });
11116
11146
  if (options.all) setConfig({ all: options.all });
11117
- if (options.verbose) setConfig({ verbose: true });
11118
11147
  }
11119
11148
  function pluralizeComponent(count) {
11120
11149
  return count === 1 ? "component" : "components";
@@ -18091,7 +18120,7 @@ function buildCommand(program2) {
18091
18120
  ).option("--all", "Build all components").option(
18092
18121
  "-c, --components <names>",
18093
18122
  "Specific component(s) to build (comma-separated)"
18094
- ).option("--no-tailwind", "Skip Tailwind CSS building").option("-y, --yes", "Skip confirmation prompts").option("--client-id <id>", "Client ID").option("--client-secret <secret>", "Client Secret").option("--site-url <url>", "Site URL").option("--verbose", "Enable verbose output").action(async (options) => {
18123
+ ).option("--no-tailwind", "Skip Tailwind CSS building").option("-y, --yes", "Skip confirmation prompts").option("--client-id <id>", "Client ID").option("--client-secret <secret>", "Client Secret").option("--site-url <url>", "Site URL").action(async (options) => {
18095
18124
  try {
18096
18125
  p.intro(chalk2.bold("Drupal Canvas CLI: build"));
18097
18126
  validateComponentOptions(options);
@@ -18161,7 +18190,7 @@ function downloadCommand(program2) {
18161
18190
  ).option("--all", "Download all components").option("-y, --yes", "Skip all confirmation prompts").option(
18162
18191
  "--skip-overwrite",
18163
18192
  "Skip downloading components that already exist locally"
18164
- ).option("--skip-css", "Skip downloading global CSS").option("--css-only", "Download only global CSS (skip components)").option("--verbose", "Enable verbose output").action(async (options) => {
18193
+ ).option("--skip-css", "Skip downloading global CSS").option("--css-only", "Download only global CSS (skip components)").action(async (options) => {
18165
18194
  p.intro(chalk2.bold("Drupal Canvas CLI: download"));
18166
18195
  try {
18167
18196
  validateComponentOptions(options);
@@ -18351,11 +18380,10 @@ function scaffoldCommand(program2) {
18351
18380
  ).option(
18352
18381
  "-d, --dir <directory>",
18353
18382
  "Component directory to create component in"
18354
- ).option("--verbose", "Enable verbose output").action(async (options) => {
18383
+ ).action(async (options) => {
18355
18384
  p.intro(chalk2.bold("Drupal Canvas CLI: scaffold"));
18356
18385
  try {
18357
18386
  if (options.dir) setConfig({ componentDir: options.dir });
18358
- if (options.verbose) setConfig({ verbose: options.verbose });
18359
18387
  const config2 = getConfig();
18360
18388
  const baseDir = config2.componentDir;
18361
18389
  let componentName = options.name;
@@ -18450,7 +18478,7 @@ var getDataDependenciesFromAst = (ast) => ast.program.body.filter((d2) => d2.typ
18450
18478
  const source = d2.source.value;
18451
18479
  if (
18452
18480
  // Only consider imports from these two modules.
18453
- source !== "@/lib/drupal-utils" && source !== "@drupal-api-client/json-api-client"
18481
+ source !== "@/lib/drupal-utils" && source !== "@drupal-api-client/json-api-client" && source !== "drupal-canvas"
18454
18482
  ) {
18455
18483
  return carry;
18456
18484
  }
@@ -18707,7 +18735,7 @@ function uploadCommand(program2) {
18707
18735
  program2.command("upload").description("build and upload local components and global CSS assets").option("--client-id <id>", "Client ID").option("--client-secret <secret>", "Client Secret").option("--site-url <url>", "Site URL").option("--scope <scope>", "Scope").option("-d, --dir <directory>", "Component directory").option(
18708
18736
  "-c, --components <names>",
18709
18737
  "Specific component(s) to upload (comma-separated)"
18710
- ).option("--all", "Upload all components").option("-y, --yes", "Skip confirmation prompts").option("--verbose", "Verbose output").option("--no-tailwind", "Skip Tailwind CSS building").option("--skip-css", "Skip global CSS upload").option("--css-only", "Upload only global CSS (skip components)").action(async (options) => {
18738
+ ).option("--all", "Upload all components").option("-y, --yes", "Skip confirmation prompts").option("--no-tailwind", "Skip Tailwind CSS building").option("--skip-css", "Skip global CSS upload").option("--css-only", "Upload only global CSS (skip components)").action(async (options) => {
18711
18739
  const allFlag = options.all || options.yes && !options.components || false;
18712
18740
  const skipTailwind = !options.tailwind;
18713
18741
  try {
@@ -18738,6 +18766,7 @@ function uploadCommand(program2) {
18738
18766
  selectMessage: "Select items to upload"
18739
18767
  });
18740
18768
  const apiService = await createApiService();
18769
+ await apiService.listComponents();
18741
18770
  let componentResults = [];
18742
18771
  if (!options.cssOnly && componentsToUpload.length > 0) {
18743
18772
  componentResults = await getBuildAndUploadResults(
@@ -18924,12 +18953,13 @@ async function getBuildAndUploadResults(componentsToUpload, apiService, includeG
18924
18953
  ]
18925
18954
  });
18926
18955
  } else {
18956
+ const errorMessage = uploadResult.error?.message || "Unknown upload error";
18927
18957
  results.push({
18928
18958
  itemName: component.componentName,
18929
18959
  success: false,
18930
18960
  details: [
18931
18961
  {
18932
- content: uploadResult.error?.message || "Unknown upload error"
18962
+ content: errorMessage.trim() || "Unknown upload error"
18933
18963
  }
18934
18964
  ]
18935
18965
  });
@@ -19009,7 +19039,7 @@ function validateCommand(program2) {
19009
19039
  ).option(
19010
19040
  "-c, --components <names>",
19011
19041
  "Specific component(s) to validate (comma-separated)"
19012
- ).option("--all", "Validate all components").option("-y, --yes", "Skip confirmation prompts").option("--verbose", "Enable verbose output").option(
19042
+ ).option("--all", "Validate all components").option("-y, --yes", "Skip confirmation prompts").option(
19013
19043
  "--fix",
19014
19044
  "Apply available automatic fixes for linting issues",
19015
19045
  false
@@ -19060,7 +19090,7 @@ function validateCommand(program2) {
19060
19090
  // src/index.ts
19061
19091
  var version = package_default.version;
19062
19092
  var program = new Command();
19063
- program.name("canvas").description("CLI tool for managing Drupal Canvas code components").version(version);
19093
+ program.name("canvas").description("CLI tool for managing Drupal Canvas code components").version(version ?? "0.0.0");
19064
19094
  downloadCommand(program);
19065
19095
  scaffoldCommand(program);
19066
19096
  uploadCommand(program);
@@ -19076,5 +19106,3 @@ try {
19076
19106
  process.exit(1);
19077
19107
  }
19078
19108
  }
19079
- //# sourceMappingURL=index.js.map
19080
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@drupal-canvas/cli",
3
- "version": "0.5.1",
4
3
  "description": "CLI tool for managing Drupal Canvas code components",
4
+ "version": "0.6.1",
5
5
  "license": "GPL-2.0-or-later",
6
6
  "repository": {
7
7
  "type": "git",
@@ -51,7 +51,7 @@
51
51
  "dependencies": {
52
52
  "@babel/parser": "^7.26.9",
53
53
  "@clack/prompts": "^0.11.0",
54
- "@drupal-canvas/eslint-config": "^0.0.1",
54
+ "@drupal-canvas/eslint-config": "^0.1.0",
55
55
  "@swc/wasm": "^1.12.1",
56
56
  "axios": "^1.9.0",
57
57
  "chalk": "^5.4.1",