@reshotdev/screenshot 0.0.1-beta.1 → 0.0.1-beta.11
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 +65 -7
- package/package.json +9 -2
- package/src/commands/auth.js +108 -26
- package/src/commands/certify.js +62 -0
- package/src/commands/ci-run.js +57 -2
- package/src/commands/ci-setup.js +5 -5
- package/src/commands/doctor-release.js +67 -0
- package/src/commands/doctor-target.js +49 -0
- package/src/commands/drifts.js +5 -70
- package/src/commands/import-tests.js +13 -13
- package/src/commands/ingest.js +10 -10
- package/src/commands/init.js +16 -277
- package/src/commands/publish.js +204 -237
- package/src/commands/pull.js +253 -23
- package/src/commands/run.js +292 -12
- package/src/commands/setup-wizard.js +277 -499
- package/src/commands/setup.js +41 -13
- package/src/commands/status.js +313 -125
- package/src/commands/sync.js +28 -236
- package/src/commands/ui.js +1 -1
- package/src/commands/verify-publish.js +46 -0
- package/src/index.js +194 -94
- package/src/lib/api-client.js +121 -35
- package/src/lib/capture-engine.js +103 -7
- package/src/lib/capture-script-runner.js +359 -58
- package/src/lib/certification.js +865 -0
- package/src/lib/config.js +181 -76
- package/src/lib/record-cdp.js +288 -16
- package/src/lib/record-config.js +1 -1
- package/src/lib/release-doctor.js +313 -0
- package/src/lib/run-manifest.js +103 -0
- package/src/lib/standalone-mode.js +1 -1
- package/src/lib/storage-providers.js +4 -4
- package/src/lib/target-contract.js +292 -0
- package/src/lib/ui-api.js +6 -7
- package/web/manager/dist/assets/{index--ZgioErz.js → index-D2qqcFNN.js} +1 -1
- package/web/manager/dist/index.html +1 -1
- 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 >
|
|
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 "
|
|
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
|
|
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
|
|
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\/?$/, "") || "
|
|
2854
|
+
apiBaseUrl.replace(/\/api\/?$/, "") || "https://reshot.dev";
|
|
2856
2855
|
|
|
2857
2856
|
config.writeSettings({
|
|
2858
2857
|
projectId: project.id,
|