@scrymore/scry-deployer 0.12.4-nightly.20261010032437 → 0.12.4

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
@@ -1073,6 +1073,10 @@ otherwise quote in full.
1073
1073
 
1074
1074
  Nothing is reported on a successful run.
1075
1075
 
1076
+ Your own mistakes (a missing or wrong `--dir`, a folder with no images, a missing key or
1077
+ env var) print a message and exit 1 but are not reported. Nothing is reported when
1078
+ `NODE_ENV=test` or `CI` is set to a true value.
1079
+
1076
1080
  **To opt out**, set either variable:
1077
1081
 
1078
1082
  ```bash
@@ -1080,7 +1084,7 @@ export SCRY_TELEMETRY=0 # Scry-specific
1080
1084
  export DO_NOT_TRACK=1 # respected across many CLI tools
1081
1085
  ```
1082
1086
 
1083
- Both are honoured everywhere, including CI.
1087
+ Both are honoured everywhere.
1084
1088
 
1085
1089
  ## 🔧 Troubleshooting the Init Command
1086
1090
 
package/bin/cli.js CHANGED
@@ -9,7 +9,7 @@ const os = require('os');
9
9
  const { zipDirectory } = require('../lib/archive.js');
10
10
  const { getApiClient, uploadBuild, sanitizeServerText } = require('../lib/apiClient.js');
11
11
  const { createLogger } = require('../lib/logger.js');
12
- const { ApiError } = require('../lib/errors.js');
12
+ const { ApiError, UserInputError } = require('../lib/errors.js');
13
13
  const { loadConfig } = require('../lib/config.js');
14
14
  const { captureScreenshots } = require('../lib/screencap.js');
15
15
  const { analyzeStorybook } = require('../lib/analysis.js');
@@ -651,11 +651,16 @@ async function handleError(error, argv) {
651
651
  logger.debug(err.stack);
652
652
  }
653
653
 
654
- // Report with an allowlisted subset of argv. Sending argv wholesale shipped
655
- // the customer's --api-key to Sentry on every error.
656
- captureCliError(err, argv);
657
- // Ensure the event is sent before the process exits
658
- try { await flushTelemetry(2000); } catch { /* telemetry must never mask the real error */ }
654
+ // A user's own mistake (wrong folder, no images, missing env var) is printed above with
655
+ // how to fix it and exits 1; it is not a defect, so it is not reported (it only spent
656
+ // error-reporting quota). Everything else is reported.
657
+ if (!(err instanceof UserInputError)) {
658
+ // Report with an allowlisted subset of argv. Sending argv wholesale shipped
659
+ // the customer's --api-key to Sentry on every error.
660
+ captureCliError(err, argv);
661
+ // Ensure the event is sent before the process exits
662
+ try { await flushTelemetry(2000); } catch { /* telemetry must never mask the real error */ }
663
+ }
659
664
 
660
665
  process.exit(1);
661
666
  }
@@ -775,15 +780,15 @@ async function main() {
775
780
 
776
781
  // Validate required fields
777
782
  if (!config.dir) {
778
- throw new Error('--dir is required. You can provide it via CLI arguments, config file, or environment variables.');
783
+ throw new UserInputError('--dir is required. You can provide it via CLI arguments, config file, or environment variables.');
779
784
  }
780
785
 
781
786
  // Validate directory exists and is valid
782
787
  if (!fs.existsSync(config.dir)) {
783
- throw new Error(`Directory not found at path: ${config.dir}`);
788
+ throw new UserInputError(`Directory not found at path: ${config.dir}`);
784
789
  }
785
790
  if (!fs.lstatSync(config.dir).isDirectory()) {
786
- throw new Error(`Path is not a directory: ${config.dir}`);
791
+ throw new UserInputError(`Path is not a directory: ${config.dir}`);
787
792
  }
788
793
 
789
794
  // Advisory, bounded to 2 s, never fails the deploy.
@@ -1119,14 +1124,14 @@ async function main() {
1119
1124
  const config = loadConfig(argv);
1120
1125
 
1121
1126
  if (!config.dir) {
1122
- throw new Error('--dir is required. Provide a path to the image directory.');
1127
+ throw new UserInputError('--dir is required. Provide a path to the image directory.');
1123
1128
  }
1124
1129
 
1125
1130
  if (!fs.existsSync(config.dir)) {
1126
- throw new Error(`Directory not found: ${config.dir}`);
1131
+ throw new UserInputError(`Directory not found: ${config.dir}`);
1127
1132
  }
1128
1133
  if (!fs.lstatSync(config.dir).isDirectory()) {
1129
- throw new Error(`Path is not a directory: ${config.dir}`);
1134
+ throw new UserInputError(`Path is not a directory: ${config.dir}`);
1130
1135
  }
1131
1136
 
1132
1137
  if (config.local) {
@@ -1182,7 +1187,7 @@ function resolveLocalProcessingKeys(config) {
1182
1187
  const envName = env.split(' ')[0];
1183
1188
  resolved[key] = config[key] || process.env[envName] || (key === 'jinaApiKey' ? process.env.JINA_API_KEY : undefined);
1184
1189
  if (!resolved[key]) {
1185
- throw new Error(`${flag} or ${env} env var is required for local mode`);
1190
+ throw new UserInputError(`${flag} or ${env} env var is required for local mode`);
1186
1191
  }
1187
1192
  }
1188
1193
 
package/lib/errors.js CHANGED
@@ -43,8 +43,22 @@ class UploadError extends AppError {
43
43
  }
44
44
  }
45
45
 
46
+ /**
47
+ * The user's own mistake, with a message that already says how to fix it: a
48
+ * missing or wrong folder, a folder with no images, a required key or env var
49
+ * that was not given. The CLI prints the message and exits 1 like any other
50
+ * error, but it is not a defect in the CLI, so it is never sent to error
51
+ * reporting (it would only spend quota on something we cannot fix).
52
+ */
53
+ class UserInputError extends AppError {
54
+ constructor(message) {
55
+ super(message);
56
+ }
57
+ }
58
+
46
59
  module.exports = {
47
60
  AppError,
61
+ UserInputError,
48
62
  FileSystemError,
49
63
  ApiError,
50
64
  UploadError,
@@ -4,6 +4,7 @@ const os = require('os');
4
4
  const { zipDirectory } = require('./archive.js');
5
5
  const { getApiClient, requestPresignedUrl, putToPresignedUrl } = require('./apiClient.js');
6
6
  const { createLogger } = require('./logger.js');
7
+ const { UserInputError } = require('./errors.js');
7
8
 
8
9
  const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg']);
9
10
 
@@ -59,7 +60,7 @@ async function runQueueImageUpload(config) {
59
60
  logger.info('Scanning for images...');
60
61
  const imageFiles = findImageFiles(config.dir);
61
62
  if (imageFiles.length === 0) {
62
- throw new Error(`No image files (.png, .jpg, .jpeg) found in: ${config.dir}`);
63
+ throw new UserInputError(`No image files (.png, .jpg, .jpeg) found in: ${config.dir}`);
63
64
  }
64
65
  logger.success(`Found ${imageFiles.length} images`);
65
66
 
@@ -3,6 +3,7 @@ const path = require('path');
3
3
  const crypto = require('crypto');
4
4
  const { XMLParser } = require('fast-xml-parser');
5
5
  const { createLogger } = require('./logger.js');
6
+ const { UserInputError } = require('./errors.js');
6
7
  const { findImageFiles } = require('./imageUpload.js');
7
8
  const { sanitizeServerText } = require('./apiClient.js');
8
9
 
@@ -659,7 +660,7 @@ async function runLocalImageProcessing(config) {
659
660
  logger.info('Step 1: Scanning for images...');
660
661
  const imageFiles = findImageFiles(config.dir);
661
662
  if (imageFiles.length === 0) {
662
- throw new Error(`No image files (.png, .jpg, .jpeg) found in: ${config.dir}`);
663
+ throw new UserInputError(`No image files (.png, .jpg, .jpeg) found in: ${config.dir}`);
663
664
  }
664
665
  logger.success(`Found ${imageFiles.length} images (${elapsed()})`);
665
666
 
package/lib/telemetry.js CHANGED
@@ -22,6 +22,7 @@ const Sentry = require('@sentry/node');
22
22
  */
23
23
 
24
24
  const { version: PACKAGE_VERSION } = require('../package.json');
25
+ const { UserInputError } = require('./errors.js');
25
26
 
26
27
  const DSN =
27
28
  'https://c66ce229a1db2289f145eebd02436d9c@o4507889391828992.ingest.us.sentry.io/4510699330732032';
@@ -115,7 +116,19 @@ function scrub(value) {
115
116
  function telemetryDisabled() {
116
117
  const off = (v) => v === '1' || v === 'true' || v === 'yes';
117
118
  return off(process.env.DO_NOT_TRACK) || process.env.SCRY_TELEMETRY === '0' ||
118
- process.env.SCRY_TELEMETRY === 'false';
119
+ process.env.SCRY_TELEMETRY === 'false' || isAutomatedRun();
120
+ }
121
+
122
+ /**
123
+ * A test run or a CI job: failures there are expected and routine (our own
124
+ * suites run the real CLI against deliberately broken input, and a CI job
125
+ * retries), so they never use error-reporting quota. `CI` counts when it is
126
+ * set to anything but an explicit false value.
127
+ */
128
+ function isAutomatedRun() {
129
+ const ci = process.env.CI;
130
+ const ciOn = ci !== undefined && ci !== '' && ci !== '0' && ci.toLowerCase() !== 'false';
131
+ return process.env.NODE_ENV === 'test' || ciOn;
119
132
  }
120
133
 
121
134
  /** Only the fields on the allowlist, and scrubbed even then. */
@@ -185,6 +198,8 @@ function initTelemetry() {
185
198
  /** Report an error with only the context that is safe to leave the machine. */
186
199
  function captureCliError(error, argv) {
187
200
  if (telemetryDisabled()) return;
201
+ // Second line of defence behind handleError: a user's own mistake is never reported.
202
+ if (error instanceof UserInputError) return;
188
203
 
189
204
  Sentry.withScope((scope) => {
190
205
  const safe = sanitizeArgv(argv);
@@ -210,6 +225,7 @@ module.exports = {
210
225
  captureCliError,
211
226
  flushTelemetry,
212
227
  telemetryDisabled,
228
+ isAutomatedRun,
213
229
  sanitizeArgv,
214
230
  redactArgv,
215
231
  scrub,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrymore/scry-deployer",
3
- "version": "0.12.4-nightly.20261010032437",
3
+ "version": "0.12.4",
4
4
  "description": "A CLI to automate the deployment of Storybook static builds.",
5
5
  "main": "index.js",
6
6
  "bin": {