@reshotdev/screenshot 0.0.1-beta.24 → 0.0.1-beta.25

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/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@reshotdev/screenshot",
3
- "version": "0.0.1-beta.24",
3
+ "version": "0.0.1-beta.25",
4
4
  "description": "Screenshot and video capture CLI",
5
5
  "author": "Reshot <hello@reshot.dev>",
6
- "license": "MIT",
6
+ "license": "Apache-2.0",
7
7
  "homepage": "https://reshot.dev",
8
8
  "repository": {
9
9
  "type": "git",
@@ -22,11 +22,10 @@
22
22
  "playwright"
23
23
  ],
24
24
  "bin": {
25
- "reshot": "src/index.js"
25
+ "reshot": "./src/index.js"
26
26
  },
27
27
  "files": [
28
28
  "src/",
29
- "vendor/compose/dist/",
30
29
  "web/manager/dist/",
31
30
  "web/cropper/",
32
31
  "web/subtitle-editor/",
@@ -36,13 +35,26 @@
36
35
  "engines": {
37
36
  "node": ">=18.0.0"
38
37
  },
38
+ "scripts": {
39
+ "test": "node scripts/test.js",
40
+ "test:unit": "node --test tests/unit/*.test.js",
41
+ "test:integration": "node --test tests/integration/*.test.js",
42
+ "test:all": "node --test tests/unit/*.test.js tests/integration/*.test.js",
43
+ "test:dry-run": "node src/index.js --help && node src/index.js --version",
44
+ "test:source": "node src/index.js",
45
+ "prepublishOnly": "cd web/manager && npm install && npm run build",
46
+ "ui:build": "cd web/manager && npm install && npm run build",
47
+ "ui:dev": "cd web/manager && npm install && npm run dev",
48
+ "lint": "echo 'No linting configured yet'",
49
+ "pack:check": "npm pack --dry-run"
50
+ },
39
51
  "dependencies": {
52
+ "@reshot/compose": "workspace:*",
40
53
  "axios": "^1.6.2",
41
54
  "chalk": "^4.1.2",
42
55
  "commander": "^11.1.0",
43
56
  "cors": "^2.8.5",
44
57
  "dotenv": "^16.3.1",
45
- "esbuild": "^0.27.2",
46
58
  "express": "^4.18.2",
47
59
  "form-data": "^4.0.0",
48
60
  "fs-extra": "^11.2.0",
@@ -52,24 +64,10 @@
52
64
  "ora": "^7.0.1",
53
65
  "pixelmatch": "^5.3.0",
54
66
  "playwright": "^1.40.0",
55
- "playwright-core": "^1.57.0",
56
67
  "pngjs": "^7.0.0",
57
68
  "sharp": "^0.33.2",
58
69
  "socket.io": "^4.7.2",
59
70
  "uuid": "^9.0.1",
60
71
  "@aws-sdk/client-s3": "^3.650.0"
61
- },
62
- "scripts": {
63
- "test": "node scripts/test.js",
64
- "test:unit": "node --test tests/unit/*.test.js",
65
- "test:integration": "node --test tests/integration/*.test.js",
66
- "test:all": "node --test tests/unit/*.test.js tests/integration/*.test.js",
67
- "test:dry-run": "node src/index.js --help && node src/index.js --version",
68
- "test:source": "node src/index.js",
69
- "ui:build": "cd web/manager && npm install && npm run build",
70
- "ui:dev": "cd web/manager && npm install && npm run dev",
71
- "lint": "echo 'No linting configured yet'",
72
- "build": "pnpm run ui:build",
73
- "pack:check": "npm pack --dry-run"
74
72
  }
75
73
  }
@@ -31,7 +31,7 @@ async function doctorTargetCommand(options = {}) {
31
31
  chalk.red("\n ✖ Target doctor aborted: Config file not found."),
32
32
  );
33
33
  console.error(
34
- chalk.gray(" Run `reshot init` (or `reshot setup`) to create one."),
34
+ chalk.gray(" Run `reshot setup` to create one."),
35
35
  );
36
36
  }
37
37
  process.exitCode = 1;
@@ -95,17 +95,21 @@ async function doctorTargetCommand(options = {}) {
95
95
  continue;
96
96
  }
97
97
  // Build an actionable reason from whatever failed, instead of a bare ✖
98
- // with no explanation (audit run-16 F4).
98
+ // with no explanation (audit run-16 F4). The status / selector / ready
99
+ // fields live on the nested pageAudit, not the top-level audit object —
100
+ // reading them at the wrong level meant a server-down run printed only
101
+ // the generic "readiness check failed" with no cause (audit run-19 #2).
102
+ const pa = audit.pageAudit || {};
99
103
  const reasons = [];
100
104
  if (audit.contractFailure) reasons.push(audit.contractFailure);
101
- if (typeof audit.status === "number" && audit.status >= 400) {
102
- reasons.push(`HTTP ${audit.status}`);
105
+ if (typeof pa.status === "number" && pa.status >= 400) {
106
+ reasons.push(`HTTP ${pa.status}`);
103
107
  }
104
- if (audit.missingSelectors && audit.missingSelectors.length > 0) {
105
- reasons.push(`missing selector(s): ${audit.missingSelectors.join(", ")}`);
108
+ if (pa.missingSelectors && pa.missingSelectors.length > 0) {
109
+ reasons.push(`missing selector(s): ${pa.missingSelectors.join(", ")}`);
106
110
  }
107
- if (audit.readyFailure) reasons.push(audit.readyFailure);
108
- if (audit.ready === false && !audit.readyFailure) {
111
+ if (pa.readyFailure) reasons.push(pa.readyFailure);
112
+ if (pa.ready === false && !pa.readyFailure) {
109
113
  reasons.push("readiness signal not satisfied");
110
114
  }
111
115
  const reason = reasons.length > 0 ? reasons.join("; ") : "readiness check failed";
@@ -294,7 +294,7 @@ async function driftsCommand(subcommand, args = [], options = {}) {
294
294
  try {
295
295
  reshotConfig = config.readConfigLenient();
296
296
  } catch (error) {
297
- console.error(chalk.red("Error:"), "reshot.config.json not found. Run `reshot init` first.");
297
+ console.error(chalk.red("Error:"), "reshot.config.json not found. Run `reshot setup` first.");
298
298
  process.exit(1);
299
299
  }
300
300
 
@@ -312,7 +312,7 @@ async function driftsCommand(subcommand, args = [], options = {}) {
312
312
  }
313
313
 
314
314
  if (!projectId) {
315
- console.error(chalk.red("Error:"), "Project ID not found. Set RESHOT_PROJECT_ID or run `reshot init`.");
315
+ console.error(chalk.red("Error:"), "Project ID not found. Set RESHOT_PROJECT_ID or run `reshot setup`.");
316
316
  process.exit(1);
317
317
  }
318
318
 
@@ -114,7 +114,17 @@ function normalizeAssetMap(assets) {
114
114
  * printed usage example is copy-pasteable for THIS project (prefers the
115
115
  * "default" context). Returns null if the map is empty.
116
116
  */
117
+ // A `step-N`/`step0Initial` key is an intermediate capture from a multi-step
118
+ // scenario, not something a user wants to embed in their docs. Prefer a
119
+ // meaningful named capture so the printed `<img>` example doesn't point at the
120
+ // wrong/duplicate intermediate asset (audit run-19 #1).
121
+ function isStepIntermediateKey(key) {
122
+ return /^step[-_]?\d/i.test(key) || /step[-_]?0/i.test(key);
123
+ }
124
+
117
125
  function deriveUsageSample(assets) {
126
+ let firstAny = null;
127
+ let firstNonStep = null;
118
128
  for (const group of Object.keys(assets || {})) {
119
129
  for (const visualKey of Object.keys(assets[group] || {})) {
120
130
  const contexts = Object.keys(assets[group][visualKey] || {});
@@ -126,10 +136,16 @@ function deriveUsageSample(assets) {
126
136
  // produce an undefined src (audit run-12 MED-1).
127
137
  const entry = assets[group][visualKey][context];
128
138
  const stepped = !!(entry && Array.isArray(entry.steps));
129
- return { group, visualKey, context, stepped };
139
+ const candidate = { group, visualKey, context, stepped };
140
+ if (!firstAny) firstAny = candidate;
141
+ if (isStepIntermediateKey(visualKey)) continue;
142
+ // The canonical scenario capture is keyed the same as its group; prefer it
143
+ // outright, otherwise fall back to the first non-intermediate capture.
144
+ if (visualKey === group) return candidate;
145
+ if (!firstNonStep) firstNonStep = candidate;
130
146
  }
131
147
  }
132
- return null;
148
+ return firstNonStep || firstAny;
133
149
  }
134
150
 
135
151
  function validateHostedAssetUrl(urlString) {
@@ -290,7 +306,7 @@ async function pullCommand(options = {}) {
290
306
  projectConfig = config.readConfig();
291
307
  } catch (e) {
292
308
  console.error(
293
- chalk.red("Error: No reshot.config.json found. Run 'reshot init' first.")
309
+ chalk.red("Error: No reshot.config.json found. Run 'reshot setup' first.")
294
310
  );
295
311
  if (!noExit) process.exit(1);
296
312
  return { success: false, error: "No reshot.config.json found" };
@@ -517,7 +517,7 @@ async function setupWizard(options = {}) {
517
517
  ` ${chalk.cyan(finalSupportedLocalCommand || "npm run build && npm run start")}`,
518
518
  );
519
519
  console.log(
520
- ` ${chalk.gray("Unsupported for launch reliability:")} ${chalk.yellow("next dev")}\n`,
520
+ ` ${chalk.gray("Less reliable for capture (works, but prefer the above):")} ${chalk.yellow("next dev")}\n`,
521
521
  );
522
522
 
523
523
  console.log(chalk.cyan("Setup mode:\n"));
@@ -280,7 +280,7 @@ async function buildStatusReport(options = {}) {
280
280
  createIssue(
281
281
  "config",
282
282
  "error",
283
- "reshot.config.json not found. Run `reshot init` or `reshot setup` first.",
283
+ "reshot.config.json not found. Run `reshot setup` first.",
284
284
  { detail: error.message },
285
285
  ),
286
286
  );
@@ -488,14 +488,23 @@ async function runDoctorTarget(options = {}) {
488
488
  `Page readiness audit for ${scenario.key}`,
489
489
  );
490
490
  } catch (error) {
491
+ const auditUrl = resolveContractUrl(target.baseUrl, scenario.url);
492
+ // Surface "could not reach <url>" for connection failures instead of the
493
+ // raw Playwright net:: jargon, so `reshot doctor target` names an
494
+ // actionable cause when the dev server is down (audit run-19 #2).
495
+ const isUnreachable = /ERR_CONNECTION|ECONNREFUSED|ENOTFOUND|net::/i.test(
496
+ error.message || "",
497
+ );
491
498
  pageAudit = {
492
499
  ok: false,
493
500
  scenario: scenario.key,
494
- url: resolveContractUrl(target.baseUrl, scenario.url),
501
+ url: auditUrl,
495
502
  status: 0,
496
503
  missingSelectors: [],
497
504
  ready: false,
498
- readyFailure: error.message,
505
+ readyFailure: isUnreachable
506
+ ? `could not reach ${auditUrl} (is the dev server running?)`
507
+ : error.message,
499
508
  diagnostics: [
500
509
  {
501
510
  kind: "timeout",
package/src/lib/config.js CHANGED
@@ -79,7 +79,7 @@ const WORKSPACE_PATH = path.join(process.cwd(), SETTINGS_DIR, "workspace.json");
79
79
  function readSettings() {
80
80
  if (!fs.existsSync(SETTINGS_PATH)) {
81
81
  throw new Error(
82
- "Reshot is not initialized in this directory. Run `reshot init` after authenticating."
82
+ "Reshot is not initialized in this directory. Run `reshot setup` after authenticating."
83
83
  );
84
84
  }
85
85
  return fs.readJSONSync(SETTINGS_PATH);
@@ -280,7 +280,7 @@ function getWorkspaceWithScenarios() {
280
280
  function readConfig() {
281
281
  if (!fs.existsSync(CONFIG_PATH)) {
282
282
  throw new Error(
283
- `Config file not found at ${CONFIG_PATH}. Run \`reshot init\` to create one.`
283
+ `Config file not found at ${CONFIG_PATH}. Run \`reshot setup\` to create one.`
284
284
  );
285
285
  }
286
286
 
@@ -492,7 +492,7 @@ function readConfig() {
492
492
  function readConfigLenient() {
493
493
  if (!fs.existsSync(CONFIG_PATH)) {
494
494
  throw new Error(
495
- `Config file not found at ${CONFIG_PATH}. Run \`reshot init\` to create one.`
495
+ `Config file not found at ${CONFIG_PATH}. Run \`reshot setup\` to create one.`
496
496
  );
497
497
  }
498
498
 
@@ -329,7 +329,7 @@ function validateCaptureRequirements(config) {
329
329
  const warnings = [];
330
330
 
331
331
  if (!config) {
332
- errors.push("No configuration found. Run `reshot init` first.");
332
+ errors.push("No configuration found. Run `reshot setup` first.");
333
333
  return { valid: false, errors, warnings };
334
334
  }
335
335