@reshotdev/screenshot 0.0.1-beta.1 → 0.0.1-beta.10

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 (38) hide show
  1. package/README.md +65 -7
  2. package/package.json +9 -2
  3. package/src/commands/auth.js +108 -26
  4. package/src/commands/certify.js +62 -0
  5. package/src/commands/ci-run.js +57 -2
  6. package/src/commands/ci-setup.js +5 -5
  7. package/src/commands/doctor-release.js +67 -0
  8. package/src/commands/doctor-target.js +49 -0
  9. package/src/commands/drifts.js +5 -70
  10. package/src/commands/import-tests.js +13 -13
  11. package/src/commands/ingest.js +10 -10
  12. package/src/commands/init.js +16 -277
  13. package/src/commands/publish.js +204 -237
  14. package/src/commands/pull.js +253 -23
  15. package/src/commands/run.js +292 -12
  16. package/src/commands/setup-wizard.js +277 -499
  17. package/src/commands/setup.js +41 -13
  18. package/src/commands/status.js +313 -125
  19. package/src/commands/sync.js +28 -236
  20. package/src/commands/ui.js +1 -1
  21. package/src/commands/verify-publish.js +46 -0
  22. package/src/index.js +194 -94
  23. package/src/lib/api-client.js +121 -35
  24. package/src/lib/capture-engine.js +103 -7
  25. package/src/lib/capture-script-runner.js +305 -58
  26. package/src/lib/certification.js +865 -0
  27. package/src/lib/config.js +181 -76
  28. package/src/lib/record-cdp.js +288 -16
  29. package/src/lib/record-config.js +1 -1
  30. package/src/lib/release-doctor.js +313 -0
  31. package/src/lib/run-manifest.js +103 -0
  32. package/src/lib/standalone-mode.js +1 -1
  33. package/src/lib/storage-providers.js +4 -4
  34. package/src/lib/target-contract.js +292 -0
  35. package/src/lib/ui-api.js +6 -7
  36. package/web/manager/dist/assets/{index--ZgioErz.js → index-D2qqcFNN.js} +1 -1
  37. package/web/manager/dist/index.html +1 -1
  38. package/src/commands/validate-docs.js +0 -529
@@ -0,0 +1,292 @@
1
+ "use strict";
2
+
3
+ const TARGET_TIERS = new Set(["certified", "candidate", "custom"]);
4
+ const TARGET_AUTH_MODES = new Set(["public", "fixture", "live-auth"]);
5
+ const SCENARIO_CAPTURE_CLASSES = new Set([
6
+ "public",
7
+ "fixture-auth",
8
+ "live-auth",
9
+ ]);
10
+ const PUBLISH_POLICIES = new Set(["required", "optional"]);
11
+
12
+ function normalizeTargetTier(value) {
13
+ const normalized = String(value || "custom").trim().toLowerCase();
14
+ return TARGET_TIERS.has(normalized) ? normalized : "custom";
15
+ }
16
+
17
+ function normalizeTargetAuthMode(value) {
18
+ const normalized = String(value || "public").trim().toLowerCase();
19
+ if (normalized === "fixture-auth") return "fixture";
20
+ if (normalized === "authenticated" || normalized === "auth") {
21
+ return "live-auth";
22
+ }
23
+ return TARGET_AUTH_MODES.has(normalized) ? normalized : "public";
24
+ }
25
+
26
+ function normalizeScenarioCaptureClass(value, requiresAuth, defaultAuthMode) {
27
+ const normalized = String(value || "").trim().toLowerCase();
28
+
29
+ if (!normalized) {
30
+ if (requiresAuth) {
31
+ return defaultAuthMode === "fixture" ? "fixture-auth" : "live-auth";
32
+ }
33
+ return "public";
34
+ }
35
+
36
+ if (
37
+ normalized === "fixture" ||
38
+ normalized === "docs-fixture" ||
39
+ normalized === "fixture-auth"
40
+ ) {
41
+ return "fixture-auth";
42
+ }
43
+
44
+ if (
45
+ normalized === "live-auth" ||
46
+ normalized === "auth" ||
47
+ normalized === "authenticated"
48
+ ) {
49
+ return "live-auth";
50
+ }
51
+
52
+ if (
53
+ normalized === "public" ||
54
+ normalized === "public-docs" ||
55
+ normalized === "public-explorer"
56
+ ) {
57
+ return "public";
58
+ }
59
+
60
+ return requiresAuth
61
+ ? defaultAuthMode === "fixture"
62
+ ? "fixture-auth"
63
+ : "live-auth"
64
+ : "public";
65
+ }
66
+
67
+ function normalizeReadyContract(scenario) {
68
+ const ready = scenario.ready && typeof scenario.ready === "object"
69
+ ? scenario.ready
70
+ : {};
71
+ const waitForReady =
72
+ scenario.waitForReady && typeof scenario.waitForReady === "object"
73
+ ? scenario.waitForReady
74
+ : {};
75
+
76
+ const selector =
77
+ ready.selector ||
78
+ scenario.readySelector ||
79
+ waitForReady.selector ||
80
+ null;
81
+ const expression =
82
+ ready.expression ||
83
+ scenario.readyExpression ||
84
+ waitForReady.expression ||
85
+ null;
86
+ const timeout =
87
+ ready.timeout ||
88
+ waitForReady.timeout ||
89
+ scenario.readyTimeout ||
90
+ null;
91
+
92
+ if (!selector && !expression && !timeout) {
93
+ return null;
94
+ }
95
+
96
+ return {
97
+ ...(selector ? { selector } : {}),
98
+ ...(expression ? { expression } : {}),
99
+ ...(timeout ? { timeout } : {}),
100
+ };
101
+ }
102
+
103
+ function normalizeStringArray(value) {
104
+ if (!Array.isArray(value)) {
105
+ return [];
106
+ }
107
+
108
+ return value
109
+ .map((item) => String(item || "").trim())
110
+ .filter(Boolean);
111
+ }
112
+
113
+ function normalizeOneOrManyStrings(value) {
114
+ if (Array.isArray(value)) {
115
+ return normalizeStringArray(value);
116
+ }
117
+
118
+ const normalized = String(value || "").trim();
119
+ return normalized ? [normalized] : [];
120
+ }
121
+
122
+ function inferExpectedArtifacts(scenario) {
123
+ return (scenario.steps || [])
124
+ .filter((step) => step.action === "screenshot" && step.key)
125
+ .map((step) => String(step.key));
126
+ }
127
+
128
+ function normalizePublishPolicy(value) {
129
+ const normalized = String(value || "required").trim().toLowerCase();
130
+ return PUBLISH_POLICIES.has(normalized) ? normalized : "required";
131
+ }
132
+
133
+ function normalizeScenarioContract(scenario, target) {
134
+ const defaultAuthMode = target?.defaultAuthMode || "public";
135
+ const captureClass = normalizeScenarioCaptureClass(
136
+ scenario.captureClass,
137
+ Boolean(scenario.requiresAuth),
138
+ defaultAuthMode,
139
+ );
140
+ const ready = normalizeReadyContract(scenario);
141
+ const requiredSelectors = normalizeStringArray(scenario.requiredSelectors);
142
+ const readySelector = ready?.selector || null;
143
+ const expectedArtifacts = normalizeStringArray(scenario.expectedArtifacts);
144
+
145
+ return {
146
+ ...scenario,
147
+ captureClass,
148
+ requiresAuth: captureClass !== "public",
149
+ ready,
150
+ readySelector: readySelector || undefined,
151
+ readyExpression: ready?.expression || undefined,
152
+ readyTimeout: ready?.timeout || scenario.readyTimeout,
153
+ waitForReady: ready || scenario.waitForReady || null,
154
+ requiredRoutes: normalizeStringArray(
155
+ scenario.requiredRoutes && scenario.requiredRoutes.length > 0
156
+ ? scenario.requiredRoutes
157
+ : scenario.url
158
+ ? [scenario.url]
159
+ : [],
160
+ ),
161
+ requiredSelectors:
162
+ requiredSelectors.length > 0
163
+ ? requiredSelectors
164
+ : readySelector
165
+ ? [readySelector]
166
+ : [],
167
+ needsWorkspaceInjection:
168
+ scenario.needsWorkspaceInjection !== undefined
169
+ ? Boolean(scenario.needsWorkspaceInjection)
170
+ : captureClass !== "public",
171
+ expectedArtifacts:
172
+ expectedArtifacts.length > 0 ? expectedArtifacts : inferExpectedArtifacts(scenario),
173
+ publishPolicy: normalizePublishPolicy(scenario.publishPolicy),
174
+ };
175
+ }
176
+
177
+ function normalizeTargetBlock(config) {
178
+ const raw = config.target && typeof config.target === "object"
179
+ ? config.target
180
+ : {};
181
+
182
+ const fixture =
183
+ raw.fixture && typeof raw.fixture === "object" ? raw.fixture : {};
184
+ const authPreflightUrls = normalizeOneOrManyStrings(
185
+ raw.authPreflightUrls || raw.authPreflightUrl,
186
+ );
187
+
188
+ return {
189
+ key: String(raw.key || config.name || config.projectId || "local-target"),
190
+ displayName: String(raw.displayName || raw.key || config.name || "Local Target"),
191
+ tier: normalizeTargetTier(raw.tier),
192
+ owner: String(raw.owner || "local"),
193
+ baseUrl: String(raw.baseUrl || config.baseUrl || "").replace(/\/+$/, ""),
194
+ captureSafe: Boolean(raw.captureSafe),
195
+ defaultAuthMode: normalizeTargetAuthMode(raw.defaultAuthMode),
196
+ supportedLocalCommand: String(
197
+ raw.supportedLocalCommand ||
198
+ raw.localServerCommand ||
199
+ raw.startCommand ||
200
+ "",
201
+ ).trim() || null,
202
+ fixture:
203
+ fixture.command || fixture.script || fixture.healthUrl
204
+ ? {
205
+ ...(fixture.command ? { command: String(fixture.command) } : {}),
206
+ ...(fixture.script ? { script: String(fixture.script) } : {}),
207
+ ...(fixture.healthUrl ? { healthUrl: String(fixture.healthUrl) } : {}),
208
+ }
209
+ : null,
210
+ requiredEnv: normalizeStringArray(raw.requiredEnv),
211
+ certificationScenarioKeys: normalizeStringArray(
212
+ raw.certificationScenarioKeys || raw.certifiedScenarios || [],
213
+ ),
214
+ authPreflightUrl: authPreflightUrls[0] || null,
215
+ authPreflightUrls,
216
+ };
217
+ }
218
+
219
+ function normalizeConfigContract(config) {
220
+ const target = normalizeTargetBlock(config);
221
+ const scenarios = Array.isArray(config.scenarios)
222
+ ? config.scenarios.map((scenario) => normalizeScenarioContract(scenario, target))
223
+ : [];
224
+
225
+ return {
226
+ ...config,
227
+ target,
228
+ scenarios,
229
+ };
230
+ }
231
+
232
+ function validateNormalizedConfig(config) {
233
+ const errors = [];
234
+
235
+ if (!config.target || typeof config.target !== "object") {
236
+ return {
237
+ valid: true,
238
+ errors,
239
+ };
240
+ }
241
+
242
+ if (!TARGET_TIERS.has(config.target.tier)) {
243
+ errors.push(`Invalid target tier "${config.target.tier}"`);
244
+ }
245
+
246
+ if (!TARGET_AUTH_MODES.has(config.target.defaultAuthMode)) {
247
+ errors.push(`Invalid target.defaultAuthMode "${config.target.defaultAuthMode}"`);
248
+ }
249
+
250
+ for (const scenario of config.scenarios || []) {
251
+ if (!SCENARIO_CAPTURE_CLASSES.has(scenario.captureClass)) {
252
+ errors.push(
253
+ `Scenario "${scenario.key}" has invalid captureClass "${scenario.captureClass}"`,
254
+ );
255
+ }
256
+ if (!PUBLISH_POLICIES.has(scenario.publishPolicy)) {
257
+ errors.push(
258
+ `Scenario "${scenario.key}" has invalid publishPolicy "${scenario.publishPolicy}"`,
259
+ );
260
+ }
261
+ }
262
+
263
+ return {
264
+ valid: errors.length === 0,
265
+ errors,
266
+ };
267
+ }
268
+
269
+ function getCertifiedScenarioKeys(config, explicitScenarioKeys = null) {
270
+ if (Array.isArray(explicitScenarioKeys) && explicitScenarioKeys.length > 0) {
271
+ return explicitScenarioKeys;
272
+ }
273
+
274
+ const configured = normalizeStringArray(config?.target?.certificationScenarioKeys);
275
+ if (configured.length > 0) {
276
+ return configured;
277
+ }
278
+
279
+ return (config?.scenarios || []).map((scenario) => scenario.key);
280
+ }
281
+
282
+ module.exports = {
283
+ TARGET_TIERS,
284
+ TARGET_AUTH_MODES,
285
+ SCENARIO_CAPTURE_CLASSES,
286
+ PUBLISH_POLICIES,
287
+ normalizeConfigContract,
288
+ normalizeTargetBlock,
289
+ normalizeScenarioContract,
290
+ validateNormalizedConfig,
291
+ getCertifiedScenarioKeys,
292
+ };
package/src/lib/ui-api.js CHANGED
@@ -43,17 +43,16 @@ const {
43
43
  * @returns {string} Platform URL
44
44
  */
45
45
  function getPlatformUrl(settings) {
46
- // Priority: settings.platformUrl > env var > localhost default
46
+ // Priority: settings.platformUrl > env var > production default
47
47
  if (settings?.platformUrl) {
48
48
  return settings.platformUrl;
49
49
  }
50
- const envUrl =
51
- process.env.RESHOT_API_BASE_URL || process.env.DOCSYNC_API_BASE_URL;
50
+ const envUrl = process.env.RESHOT_API_BASE_URL;
52
51
  if (envUrl) {
53
52
  // Remove /api suffix if present to get platform URL
54
53
  return envUrl.replace(/\/api\/?$/, "");
55
54
  }
56
- return "http://localhost:3000";
55
+ return "https://reshot.dev";
57
56
  }
58
57
 
59
58
  /**
@@ -431,7 +430,7 @@ function attachApiRoutes(app, context) {
431
430
 
432
431
  /**
433
432
  * PUT /api/privacy
434
- * Update privacy configuration in docsync.config.json
433
+ * Update privacy configuration in reshot.config.json
435
434
  */
436
435
  app.put("/api/privacy", async (req, res, next) => {
437
436
  try {
@@ -472,7 +471,7 @@ function attachApiRoutes(app, context) {
472
471
 
473
472
  /**
474
473
  * PUT /api/style
475
- * Update style configuration in docsync.config.json
474
+ * Update style configuration in reshot.config.json
476
475
  */
477
476
  app.put("/api/style", async (req, res, next) => {
478
477
  try {
@@ -2852,7 +2851,7 @@ function attachApiRoutes(app, context) {
2852
2851
  const apiBaseUrl = getApiBaseUrl();
2853
2852
  // Derive platformUrl from apiBaseUrl (remove /api suffix)
2854
2853
  const platformUrl =
2855
- apiBaseUrl.replace(/\/api\/?$/, "") || "http://localhost:3000";
2854
+ apiBaseUrl.replace(/\/api\/?$/, "") || "https://reshot.dev";
2856
2855
 
2857
2856
  config.writeSettings({
2858
2857
  projectId: project.id,