@jevitate/cli 0.1.0 → 0.3.0
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 +23 -0
- package/dist/ai-cli.d.ts +31 -11
- package/dist/ai-cli.js +131 -88
- package/dist/ai-cli.js.map +1 -1
- package/dist/author-journey-cli.d.ts +4 -0
- package/dist/author-journey-cli.js +111 -0
- package/dist/author-journey-cli.js.map +1 -0
- package/dist/bin.js +60349 -16477
- package/dist/bin.js.map +1 -1
- package/dist/browser-run-options.d.ts +89 -0
- package/dist/browser-run-options.js +175 -0
- package/dist/browser-run-options.js.map +1 -0
- package/dist/build-info.generated.d.ts +2 -0
- package/dist/build-info.generated.js +10 -0
- package/dist/build-info.generated.js.map +1 -0
- package/dist/campaign-api.d.ts +151 -0
- package/dist/campaign-api.js +446 -0
- package/dist/campaign-api.js.map +1 -0
- package/dist/campaign-cli.d.ts +6 -0
- package/dist/campaign-cli.js +66 -0
- package/dist/campaign-cli.js.map +1 -0
- package/dist/check-api.d.ts +5 -0
- package/dist/check-api.js +234 -0
- package/dist/check-api.js.map +1 -0
- package/dist/check-budget.d.ts +26 -0
- package/dist/check-budget.js +90 -0
- package/dist/check-budget.js.map +1 -0
- package/dist/check-cli.d.ts +31 -0
- package/dist/check-cli.js +109 -0
- package/dist/check-cli.js.map +1 -0
- package/dist/check-execute.d.ts +29 -0
- package/dist/check-execute.js +420 -0
- package/dist/check-execute.js.map +1 -0
- package/dist/check-plan.d.ts +118 -0
- package/dist/check-plan.js +516 -0
- package/dist/check-plan.js.map +1 -0
- package/dist/check-suite.d.ts +184 -0
- package/dist/check-suite.js +540 -0
- package/dist/check-suite.js.map +1 -0
- package/dist/check-types.d.ts +181 -0
- package/dist/check-types.js +35 -0
- package/dist/check-types.js.map +1 -0
- package/dist/cli-args.d.ts +26 -0
- package/dist/cli-args.js +50 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-output.d.ts +106 -0
- package/dist/cli-output.js +563 -0
- package/dist/cli-output.js.map +1 -0
- package/dist/cli-reference.d.ts +3 -0
- package/dist/cli-reference.js +81 -0
- package/dist/cli-reference.js.map +1 -0
- package/dist/cli-refusal.d.ts +12 -0
- package/dist/cli-refusal.js +52 -0
- package/dist/cli-refusal.js.map +1 -0
- package/dist/cli-shared.d.ts +340 -0
- package/dist/cli-shared.js +537 -0
- package/dist/cli-shared.js.map +1 -0
- package/dist/cli-surface.d.ts +33 -0
- package/dist/cli-surface.js +48 -0
- package/dist/cli-surface.js.map +1 -0
- package/dist/conversation-options.d.ts +15 -0
- package/dist/conversation-options.js +10 -0
- package/dist/conversation-options.js.map +1 -0
- package/dist/credentials-file.d.ts +15 -0
- package/dist/credentials-file.js +56 -0
- package/dist/credentials-file.js.map +1 -0
- package/dist/data-dir.d.ts +1 -1
- package/dist/data-dir.js +1 -1
- package/dist/defect-evidence.d.ts +141 -0
- package/dist/defect-evidence.js +505 -0
- package/dist/defect-evidence.js.map +1 -0
- package/dist/demo-aspect-api.d.ts +209 -0
- package/dist/demo-aspect-api.js +398 -0
- package/dist/demo-aspect-api.js.map +1 -0
- package/dist/demo-aspect-cli.d.ts +3 -0
- package/dist/demo-aspect-cli.js +243 -0
- package/dist/demo-aspect-cli.js.map +1 -0
- package/dist/demo-capture.d.ts +142 -0
- package/dist/demo-capture.js +537 -0
- package/dist/demo-capture.js.map +1 -0
- package/dist/engine.d.ts +35 -0
- package/dist/engine.js +25 -0
- package/dist/engine.js.map +1 -0
- package/dist/environments.d.ts +155 -0
- package/dist/environments.js +364 -0
- package/dist/environments.js.map +1 -0
- package/dist/exit-codes.d.ts +46 -0
- package/dist/exit-codes.js +91 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/explore-adversarial.d.ts +144 -0
- package/dist/explore-adversarial.js +227 -0
- package/dist/explore-adversarial.js.map +1 -0
- package/dist/explore-api.d.ts +7 -187
- package/dist/explore-api.js +7 -301
- package/dist/explore-api.js.map +1 -1
- package/dist/explore-author.d.ts +79 -0
- package/dist/explore-author.js +86 -0
- package/dist/explore-author.js.map +1 -0
- package/dist/explore-cli.d.ts +7 -0
- package/dist/explore-cli.js +1199 -0
- package/dist/explore-cli.js.map +1 -0
- package/dist/explore-coverage.d.ts +173 -0
- package/dist/explore-coverage.js +246 -0
- package/dist/explore-coverage.js.map +1 -0
- package/dist/explore-feature.d.ts +125 -0
- package/dist/explore-feature.js +218 -0
- package/dist/explore-feature.js.map +1 -0
- package/dist/explore-goal.d.ts +271 -0
- package/dist/explore-goal.js +417 -0
- package/dist/explore-goal.js.map +1 -0
- package/dist/explore-shared.d.ts +177 -0
- package/dist/explore-shared.js +149 -0
- package/dist/explore-shared.js.map +1 -0
- package/dist/explore-specs.d.ts +53 -0
- package/dist/explore-specs.js +333 -0
- package/dist/explore-specs.js.map +1 -0
- package/dist/findings-filing.d.ts +64 -0
- package/dist/findings-filing.js +108 -0
- package/dist/findings-filing.js.map +1 -0
- package/dist/fixture-auth.d.ts +63 -0
- package/dist/fixture-auth.js +95 -0
- package/dist/fixture-auth.js.map +1 -0
- package/dist/fixture-cli.d.ts +99 -0
- package/dist/fixture-cli.js +292 -0
- package/dist/fixture-cli.js.map +1 -0
- package/dist/github-issue-filer.d.ts +62 -0
- package/dist/github-issue-filer.js +189 -0
- package/dist/github-issue-filer.js.map +1 -0
- package/dist/host-health-run.d.ts +25 -0
- package/dist/host-health-run.js +33 -0
- package/dist/host-health-run.js.map +1 -0
- package/dist/http-5xx-outcome.d.ts +6 -0
- package/dist/http-5xx-outcome.js +39 -0
- package/dist/http-5xx-outcome.js.map +1 -0
- package/dist/inbox-cli.d.ts +7 -0
- package/dist/inbox-cli.js +197 -0
- package/dist/inbox-cli.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init-cli.d.ts +4 -0
- package/dist/init-cli.js +156 -0
- package/dist/init-cli.js.map +1 -0
- package/dist/init-keys.d.ts +30 -2
- package/dist/init-keys.js +19 -5
- package/dist/init-keys.js.map +1 -1
- package/dist/init-next-steps.d.ts +35 -0
- package/dist/init-next-steps.js +79 -0
- package/dist/init-next-steps.js.map +1 -0
- package/dist/invariants-file.d.ts +34 -0
- package/dist/invariants-file.js +68 -0
- package/dist/invariants-file.js.map +1 -0
- package/dist/invariants-validate.d.ts +30 -0
- package/dist/invariants-validate.js +105 -0
- package/dist/invariants-validate.js.map +1 -0
- package/dist/journey-annotate-api.d.ts +76 -0
- package/dist/journey-annotate-api.js +269 -0
- package/dist/journey-annotate-api.js.map +1 -0
- package/dist/journey-annotate-cli.d.ts +9 -0
- package/dist/journey-annotate-cli.js +181 -0
- package/dist/journey-annotate-cli.js.map +1 -0
- package/dist/journey-api.d.ts +104 -2
- package/dist/journey-api.js +163 -20
- package/dist/journey-api.js.map +1 -1
- package/dist/journey-cli.d.ts +4 -0
- package/dist/journey-cli.js +411 -0
- package/dist/journey-cli.js.map +1 -0
- package/dist/journey-demo-api.d.ts +114 -0
- package/dist/journey-demo-api.js +405 -0
- package/dist/journey-demo-api.js.map +1 -0
- package/dist/journey-demo-cli.d.ts +10 -0
- package/dist/journey-demo-cli.js +158 -0
- package/dist/journey-demo-cli.js.map +1 -0
- package/dist/journey-prefix.d.ts +194 -0
- package/dist/journey-prefix.js +279 -0
- package/dist/journey-prefix.js.map +1 -0
- package/dist/key-report.d.ts +49 -0
- package/dist/key-report.js +101 -0
- package/dist/key-report.js.map +1 -0
- package/dist/kill-signal.d.ts +193 -0
- package/dist/kill-signal.js +283 -0
- package/dist/kill-signal.js.map +1 -0
- package/dist/launch-armed.d.ts +37 -0
- package/dist/launch-armed.js +31 -0
- package/dist/launch-armed.js.map +1 -0
- package/dist/ledger-api.d.ts +106 -0
- package/dist/ledger-api.js +239 -0
- package/dist/ledger-api.js.map +1 -0
- package/dist/ledger-cli.d.ts +18 -0
- package/dist/ledger-cli.js +107 -0
- package/dist/ledger-cli.js.map +1 -0
- package/dist/load-api.d.ts +29 -11
- package/dist/load-api.js +23 -15
- package/dist/load-api.js.map +1 -1
- package/dist/load-cli.d.ts +4 -0
- package/dist/load-cli.js +97 -0
- package/dist/load-cli.js.map +1 -0
- package/dist/log-correlation.d.ts +200 -0
- package/dist/log-correlation.js +394 -0
- package/dist/log-correlation.js.map +1 -0
- package/dist/log-lines.d.ts +131 -0
- package/dist/log-lines.js +389 -0
- package/dist/log-lines.js.map +1 -0
- package/dist/log-sources.d.ts +71 -0
- package/dist/log-sources.js +236 -0
- package/dist/log-sources.js.map +1 -0
- package/dist/log-trace.d.ts +80 -0
- package/dist/log-trace.js +210 -0
- package/dist/log-trace.js.map +1 -0
- package/dist/logs-cli.d.ts +3 -0
- package/dist/logs-cli.js +51 -0
- package/dist/logs-cli.js.map +1 -0
- package/dist/logs-retention.d.ts +28 -0
- package/dist/logs-retention.js +85 -0
- package/dist/logs-retention.js.map +1 -0
- package/dist/masked-input.d.ts +22 -0
- package/dist/masked-input.js +99 -0
- package/dist/masked-input.js.map +1 -0
- package/dist/mcp-api.d.ts +91 -1
- package/dist/mcp-api.js +514 -18
- package/dist/mcp-api.js.map +1 -1
- package/dist/mcp-args.d.ts +50 -0
- package/dist/mcp-args.js +164 -0
- package/dist/mcp-args.js.map +1 -0
- package/dist/mcp-cli-bridge.d.ts +34 -0
- package/dist/mcp-cli-bridge.js +62 -0
- package/dist/mcp-cli-bridge.js.map +1 -0
- package/dist/mcp-cli-runner.d.ts +29 -0
- package/dist/mcp-cli-runner.js +44 -0
- package/dist/mcp-cli-runner.js.map +1 -0
- package/dist/mcp-cli-tools.d.ts +129 -0
- package/dist/mcp-cli-tools.js +737 -0
- package/dist/mcp-cli-tools.js.map +1 -0
- package/dist/mcp-paths.d.ts +28 -0
- package/dist/mcp-paths.js +76 -0
- package/dist/mcp-paths.js.map +1 -0
- package/dist/mission-actors.d.ts +40 -0
- package/dist/mission-actors.js +72 -0
- package/dist/mission-actors.js.map +1 -0
- package/dist/mission-api.d.ts +35 -0
- package/dist/mission-api.js +60 -3
- package/dist/mission-api.js.map +1 -1
- package/dist/mission-cli.d.ts +4 -0
- package/dist/mission-cli.js +248 -0
- package/dist/mission-cli.js.map +1 -0
- package/dist/mission-exit.d.ts +22 -0
- package/dist/mission-exit.js +26 -0
- package/dist/mission-exit.js.map +1 -0
- package/dist/mission-fixtures.d.ts +234 -0
- package/dist/mission-fixtures.js +862 -0
- package/dist/mission-fixtures.js.map +1 -0
- package/dist/mission-journal.d.ts +60 -0
- package/dist/mission-journal.js +115 -0
- package/dist/mission-journal.js.map +1 -0
- package/dist/mission-queue-cli.d.ts +10 -0
- package/dist/mission-queue-cli.js +198 -0
- package/dist/mission-queue-cli.js.map +1 -0
- package/dist/mission-queue-runner.d.ts +126 -0
- package/dist/mission-queue-runner.js +406 -0
- package/dist/mission-queue-runner.js.map +1 -0
- package/dist/multi-run-cli.d.ts +37 -0
- package/dist/multi-run-cli.js +116 -0
- package/dist/multi-run-cli.js.map +1 -0
- package/dist/multi-run.d.ts +339 -0
- package/dist/multi-run.js +619 -0
- package/dist/multi-run.js.map +1 -0
- package/dist/openrouter-call.d.ts +22 -0
- package/dist/openrouter-call.js +64 -0
- package/dist/openrouter-call.js.map +1 -0
- package/dist/profile-cli.d.ts +4 -0
- package/dist/profile-cli.js +57 -0
- package/dist/profile-cli.js.map +1 -0
- package/dist/program.d.ts +3 -75
- package/dist/program.js +123 -1921
- package/dist/program.js.map +1 -1
- package/dist/project-dir.d.ts +96 -0
- package/dist/project-dir.js +221 -0
- package/dist/project-dir.js.map +1 -0
- package/dist/record-api.d.ts +13 -7
- package/dist/record-api.js +44 -30
- package/dist/record-api.js.map +1 -1
- package/dist/record-cli.d.ts +4 -0
- package/dist/record-cli.js +76 -0
- package/dist/record-cli.js.map +1 -0
- package/dist/recording-cli.d.ts +4 -0
- package/dist/recording-cli.js +248 -0
- package/dist/recording-cli.js.map +1 -0
- package/dist/regression-api.d.ts +107 -0
- package/dist/regression-api.js +387 -6
- package/dist/regression-api.js.map +1 -1
- package/dist/regression-cli.d.ts +4 -0
- package/dist/regression-cli.js +284 -0
- package/dist/regression-cli.js.map +1 -0
- package/dist/report-api.d.ts +146 -0
- package/dist/report-api.js +431 -0
- package/dist/report-api.js.map +1 -0
- package/dist/report-cli.d.ts +12 -0
- package/dist/report-cli.js +147 -0
- package/dist/report-cli.js.map +1 -0
- package/dist/resource-preflight.d.ts +87 -0
- package/dist/resource-preflight.js +160 -0
- package/dist/resource-preflight.js.map +1 -0
- package/dist/result-schema.d.ts +22 -0
- package/dist/result-schema.js +28 -0
- package/dist/result-schema.js.map +1 -0
- package/dist/run-index.d.ts +29 -0
- package/dist/run-index.js +70 -0
- package/dist/run-index.js.map +1 -0
- package/dist/run-key-preflight.d.ts +42 -0
- package/dist/run-key-preflight.js +82 -0
- package/dist/run-key-preflight.js.map +1 -0
- package/dist/run-screenshots.d.ts +123 -0
- package/dist/run-screenshots.js +235 -0
- package/dist/run-screenshots.js.map +1 -0
- package/dist/runtime-env.d.ts +8 -0
- package/dist/runtime-env.js +23 -0
- package/dist/runtime-env.js.map +1 -0
- package/dist/secret-args.d.ts +23 -0
- package/dist/secret-args.js +45 -0
- package/dist/secret-args.js.map +1 -0
- package/dist/serve-cli.d.ts +4 -0
- package/dist/serve-cli.js +95 -0
- package/dist/serve-cli.js.map +1 -0
- package/dist/server-log-verify.d.ts +36 -0
- package/dist/server-log-verify.js +120 -0
- package/dist/server-log-verify.js.map +1 -0
- package/dist/session-check.d.ts +14 -0
- package/dist/session-check.js +44 -0
- package/dist/session-check.js.map +1 -0
- package/dist/site-cli.d.ts +4 -0
- package/dist/site-cli.js +127 -0
- package/dist/site-cli.js.map +1 -0
- package/dist/site-gate-cli.d.ts +28 -0
- package/dist/site-gate-cli.js +59 -0
- package/dist/site-gate-cli.js.map +1 -0
- package/dist/source-api.js +20 -4
- package/dist/source-api.js.map +1 -1
- package/dist/source-cli.d.ts +4 -0
- package/dist/source-cli.js +284 -0
- package/dist/source-cli.js.map +1 -0
- package/dist/source-run-api.d.ts +27 -1
- package/dist/source-run-api.js +22 -11
- package/dist/source-run-api.js.map +1 -1
- package/dist/storage-state-snapshot.d.ts +50 -0
- package/dist/storage-state-snapshot.js +87 -0
- package/dist/storage-state-snapshot.js.map +1 -0
- package/dist/suite-explore-options.d.ts +321 -0
- package/dist/suite-explore-options.js +162 -0
- package/dist/suite-explore-options.js.map +1 -0
- package/dist/target-config.d.ts +115 -0
- package/dist/target-config.js +225 -0
- package/dist/target-config.js.map +1 -0
- package/dist/transcript-file.d.ts +12 -0
- package/dist/transcript-file.js +23 -0
- package/dist/transcript-file.js.map +1 -0
- package/dist/type-fixture-file.d.ts +9 -0
- package/dist/type-fixture-file.js +48 -0
- package/dist/type-fixture-file.js.map +1 -0
- package/dist/ui-api.d.ts +3 -0
- package/dist/ui-api.js +11 -4
- package/dist/ui-api.js.map +1 -1
- package/dist/usability-capture.d.ts +43 -0
- package/dist/usability-capture.js +327 -0
- package/dist/usability-capture.js.map +1 -0
- package/dist/usage-config.d.ts +36 -0
- package/dist/usage-config.js +114 -0
- package/dist/usage-config.js.map +1 -0
- package/dist/ux-api.d.ts +3 -75
- package/dist/ux-api.js +3 -220
- package/dist/ux-api.js.map +1 -1
- package/dist/ux-claim-probe.d.ts +45 -0
- package/dist/ux-claim-probe.js +386 -0
- package/dist/ux-claim-probe.js.map +1 -0
- package/dist/ux-cli.d.ts +4 -0
- package/dist/ux-cli.js +109 -0
- package/dist/ux-cli.js.map +1 -0
- package/dist/ux-config.d.ts +29 -0
- package/dist/ux-config.js +103 -0
- package/dist/ux-config.js.map +1 -0
- package/dist/ux-evidence.d.ts +54 -0
- package/dist/ux-evidence.js +197 -0
- package/dist/ux-evidence.js.map +1 -0
- package/dist/ux-product.d.ts +14 -0
- package/dist/ux-product.js +39 -0
- package/dist/ux-product.js.map +1 -0
- package/dist/ux-review.d.ts +116 -0
- package/dist/ux-review.js +171 -0
- package/dist/ux-review.js.map +1 -0
- package/dist/ux-usability.d.ts +263 -0
- package/dist/ux-usability.js +580 -0
- package/dist/ux-usability.js.map +1 -0
- package/dist/verify-fix-api.d.ts +194 -0
- package/dist/verify-fix-api.js +506 -0
- package/dist/verify-fix-api.js.map +1 -0
- package/dist/verify-fix-cli.d.ts +4 -0
- package/dist/verify-fix-cli.js +115 -0
- package/dist/verify-fix-cli.js.map +1 -0
- package/package.json +23 -18
- package/skills/jevitate-ci-check/SKILL.md +77 -0
- package/skills/jevitate-demo/SKILL.md +61 -0
- package/skills/jevitate-explore/SKILL.md +96 -87
- package/skills/jevitate-getting-started/SKILL.md +89 -0
- package/skills/jevitate-load-test/SKILL.md +11 -2
- package/skills/jevitate-mission-scope/SKILL.md +19 -11
- package/skills/jevitate-record/SKILL.md +23 -5
- package/skills/jevitate-run-journey/SKILL.md +61 -17
- package/skills/jevitate-sources/SKILL.md +57 -14
- package/skills/jevitate-test-campaign/SKILL.md +203 -0
- package/skills/jevitate-ux-review/SKILL.md +106 -16
- package/skills/jevitate-verify-fix/SKILL.md +76 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { RecordingInterpreter } from "@jevitate/interpreter";
|
|
2
|
+
import { perceive, verifyReplayVerdict } from "@jevitate/explore";
|
|
3
|
+
import { closeLogSources, openLogSources, parseLogSourceSpecs } from "./log-sources.js";
|
|
4
|
+
import { matchesLogDefect, matchesLogIgnore, normalizeLogMessage, parseLogDefectSpec, parseLogIgnoreSpec, parseLogLine } from "./log-lines.js";
|
|
5
|
+
import { clock } from "@jevitate/domain";
|
|
6
|
+
const DEFAULT_REPLAYS = 3;
|
|
7
|
+
function firstLine(e) {
|
|
8
|
+
return e instanceof Error ? e.message.split("\n")[0] ?? e.message : String(e);
|
|
9
|
+
}
|
|
10
|
+
function sleep(ms) {
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
const t = clock.setTimeout(resolve, ms);
|
|
13
|
+
t.unref?.();
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async function runOneServerLogReplay(params, sourceSpecs) {
|
|
17
|
+
const lines = [];
|
|
18
|
+
const handles = openLogSources(sourceSpecs, {
|
|
19
|
+
onLine: (raw, arrivalEpochMs) => {
|
|
20
|
+
if (lines.length >= 5_000)
|
|
21
|
+
return;
|
|
22
|
+
lines.push(parseLogLine(raw, arrivalEpochMs, ""));
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
let session;
|
|
26
|
+
try {
|
|
27
|
+
session = await params.openSession();
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
await closeLogSources(handles);
|
|
31
|
+
return {
|
|
32
|
+
ran: false,
|
|
33
|
+
fired: false,
|
|
34
|
+
detail: `could not open a fresh session: ${firstLine(e)}`,
|
|
35
|
+
replay: { outcome: "failed", at: -1, error: firstLine(e) },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const interpreter = new RecordingInterpreter(params.targetTimeoutMs === undefined ? {} : { targetTimeoutMs: params.targetTimeoutMs });
|
|
40
|
+
const outcome = await interpreter.runToCheckpoint(session.actor, params.recording, params.recordingStepIndex);
|
|
41
|
+
await perceive(session.page, {
|
|
42
|
+
...(params.settleCeilingMs === undefined ? {} : { renderWaitMs: params.settleCeilingMs }),
|
|
43
|
+
}).catch(() => undefined);
|
|
44
|
+
// Hold the log sources open for the SAME drain window the original run used, so async backend
|
|
45
|
+
// work that settles late is caught here too — never blocking anything but this one attempt.
|
|
46
|
+
await sleep(params.drainMs);
|
|
47
|
+
await closeLogSources(handles);
|
|
48
|
+
const matcher = parseLogDefectSpec(params.matcher);
|
|
49
|
+
const scope = (params.scope ?? []).map(parseLogIgnoreSpec);
|
|
50
|
+
const inScope = (l) => scope.length === 0 || scope.some((m) => matchesLogIgnore(l, m));
|
|
51
|
+
const fired = lines.some((l) => inScope(l) && matchesLogDefect(l, matcher) && normalizeLogMessage(l.message) === params.normalizedMessage);
|
|
52
|
+
if (outcome.outcome !== "completed") {
|
|
53
|
+
const replay = outcome.outcome === "failed"
|
|
54
|
+
? { outcome: "failed", at: outcome.at, error: outcome.error.split("\n")[0] ?? outcome.error, ...(outcome.reason === undefined ? {} : { reason: outcome.reason }) }
|
|
55
|
+
: { outcome: "failed", at: outcome.at, error: "replay paused for a human hand-back" };
|
|
56
|
+
const mismatch = outcome.outcome === "failed" && outcome.reason !== undefined;
|
|
57
|
+
return {
|
|
58
|
+
ran: false,
|
|
59
|
+
fired,
|
|
60
|
+
replay,
|
|
61
|
+
detail: mismatch
|
|
62
|
+
? `replay stopped at step ${outcome.at}: ${outcome.reason} — the recorded path was not reproduced, so this proves nothing`
|
|
63
|
+
: `replay could not reach step ${params.recordingStepIndex} (failed at ${outcome.at}); the log source was not re-checked against the intended step`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
ran: true,
|
|
68
|
+
fired,
|
|
69
|
+
replay: { outcome: "completed" },
|
|
70
|
+
detail: fired
|
|
71
|
+
? "a matching server log line reappeared during the drain window"
|
|
72
|
+
: "replay reached the defect's step and no matching server log line appeared within the drain window",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
await closeLogSources(handles).catch(() => undefined);
|
|
77
|
+
return { ran: false, fired: false, detail: `replay failed: ${firstLine(e)}`, replay: { outcome: "failed", at: -1, error: firstLine(e) } };
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
await session.close().catch(() => undefined);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export async function verifyServerLogDefect(params) {
|
|
84
|
+
const base = { fingerprint: params.fingerprint };
|
|
85
|
+
let sourceSpecs;
|
|
86
|
+
try {
|
|
87
|
+
sourceSpecs = parseLogSourceSpecs(params.sources, params.allowLogCmd);
|
|
88
|
+
parseLogDefectSpec(params.matcher); // validated once up front, fail closed
|
|
89
|
+
for (const s of params.scope ?? [])
|
|
90
|
+
parseLogIgnoreSpec(s);
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
return {
|
|
94
|
+
...base,
|
|
95
|
+
verdict: "inconclusive",
|
|
96
|
+
observedFingerprints: [],
|
|
97
|
+
replay: { outcome: "failed", at: -1, error: "not replayed" },
|
|
98
|
+
reason: `the defect's log source(s)/matcher no longer parse: ${firstLine(e)}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const replays = params.replays ?? DEFAULT_REPLAYS;
|
|
102
|
+
if (!Number.isInteger(replays) || replays < 1)
|
|
103
|
+
throw new Error(`verifyServerLogDefect: replays must be >= 1, got ${replays}`);
|
|
104
|
+
const runs = [];
|
|
105
|
+
for (let i = 0; i < replays; i++)
|
|
106
|
+
runs.push(await runOneServerLogReplay(params, sourceSpecs));
|
|
107
|
+
const last = runs[runs.length - 1];
|
|
108
|
+
const verdict = verifyReplayVerdict(runs);
|
|
109
|
+
const ran = runs.filter((r) => r.ran).length;
|
|
110
|
+
const fired = runs.filter((r) => r.ran && r.fired).length;
|
|
111
|
+
const reason = verdict === "inconclusive"
|
|
112
|
+
? last.detail
|
|
113
|
+
: verdict === "still-reproduces"
|
|
114
|
+
? `the matching server log line reappeared on all ${fired}/${ran} replay(s) that ran`
|
|
115
|
+
: verdict === "fixed"
|
|
116
|
+
? `no matching server log line appeared on any of the ${ran}/${runs.length} replay(s) that ran`
|
|
117
|
+
: `the matching server log line appeared on ${fired}/${ran} replay(s) that ran — intermittent on the current code, never reported as fixed`;
|
|
118
|
+
return { ...base, verdict, observedFingerprints: fired > 0 ? [params.fingerprint] : [], replay: last.replay, reason, attempts: runs.map((r) => ({ ran: r.ran, fired: r.fired, detail: r.detail })) };
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=server-log-verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-log-verify.js","sourceRoot":"","sources":["../src/server-log-verify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #213: was a run's `--storage-state` (a persona's) session honoured? A dead session (an expired or
|
|
3
|
+
* bogus cookie) does not fail the run by itself: the app shows its sign-in form, and a goal run's
|
|
4
|
+
* model may simply sign in on its own — the run then passes, silently testing as whoever it logged
|
|
5
|
+
* in as, not the persona. Code-decided from the FIRST page the run decided on (its seed landing):
|
|
6
|
+
* a login-like URL (the #82 pattern), or a sign-in form — a visible password field — on it.
|
|
7
|
+
*
|
|
8
|
+
* Returns why the session was not honoured, or undefined (no storage state given, or the first page
|
|
9
|
+
* was not a sign-in page). Never a verdict about the app: a warning on the result and the summary.
|
|
10
|
+
*/
|
|
11
|
+
export declare function sessionLostReason(data: {
|
|
12
|
+
readonly target?: unknown;
|
|
13
|
+
readonly transcript?: unknown;
|
|
14
|
+
}): string | undefined;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import { isLoginLikeUrl } from "@jevitate/explore";
|
|
3
|
+
/**
|
|
4
|
+
* #213: was a run's `--storage-state` (a persona's) session honoured? A dead session (an expired or
|
|
5
|
+
* bogus cookie) does not fail the run by itself: the app shows its sign-in form, and a goal run's
|
|
6
|
+
* model may simply sign in on its own — the run then passes, silently testing as whoever it logged
|
|
7
|
+
* in as, not the persona. Code-decided from the FIRST page the run decided on (its seed landing):
|
|
8
|
+
* a login-like URL (the #82 pattern), or a sign-in form — a visible password field — on it.
|
|
9
|
+
*
|
|
10
|
+
* Returns why the session was not honoured, or undefined (no storage state given, or the first page
|
|
11
|
+
* was not a sign-in page). Never a verdict about the app: a warning on the result and the summary.
|
|
12
|
+
*/
|
|
13
|
+
export function sessionLostReason(data) {
|
|
14
|
+
const target = isRecord(data.target) ? data.target : undefined;
|
|
15
|
+
const state = typeof target?.storageStatePath === "string" ? target.storageStatePath : undefined;
|
|
16
|
+
if (state === undefined)
|
|
17
|
+
return undefined;
|
|
18
|
+
const first = Array.isArray(data.transcript) ? data.transcript.find(isRecord) : undefined;
|
|
19
|
+
if (first === undefined)
|
|
20
|
+
return undefined;
|
|
21
|
+
const url = typeof first.url === "string" ? first.url : "";
|
|
22
|
+
const controls = Array.isArray(first.controls) ? first.controls.filter((c) => typeof c === "string") : [];
|
|
23
|
+
const loginUrl = url !== "" && isLoginLikeUrl(url);
|
|
24
|
+
const passwordField = controls.some((c) => PASSWORD_CONTROL.test(c));
|
|
25
|
+
if (!loginUrl && !passwordField)
|
|
26
|
+
return undefined;
|
|
27
|
+
const where = pathOf(url);
|
|
28
|
+
const what = loginUrl ? `the first page was a sign-in page (${where})` : `the first page (${where}) showed a sign-in form (a password field)`;
|
|
29
|
+
return `the session in ${basename(state)} was not honoured — ${what}; the run did not start signed in as that session (re-save the storage state, or check its cookie is still valid)`;
|
|
30
|
+
}
|
|
31
|
+
/** A password field's control identity (`textbox "Password"`, `textbox "Passcode"`, …). */
|
|
32
|
+
const PASSWORD_CONTROL = /^(?:textbox|searchbox)\s+"[^"]*\b(?:password|passcode|passwort|mot de passe)\b[^"]*"$/i;
|
|
33
|
+
function pathOf(url) {
|
|
34
|
+
try {
|
|
35
|
+
return new URL(url).pathname;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return url === "" ? "?" : url;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isRecord(v) {
|
|
42
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=session-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-check.js","sourceRoot":"","sources":["../src/session-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAkE;IAClG,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,MAAM,KAAK,GAAG,OAAO,MAAM,EAAE,gBAAgB,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC;IACjG,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1F,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvH,MAAM,QAAQ,GAAG,GAAG,KAAK,EAAE,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC,QAAQ,IAAI,CAAC,aAAa;QAAE,OAAO,SAAS,CAAC;IAClD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,sCAAsC,KAAK,GAAG,CAAC,CAAC,CAAC,mBAAmB,KAAK,4CAA4C,CAAC;IAC9I,OAAO,kBAAkB,QAAQ,CAAC,KAAK,CAAC,uBAAuB,IAAI,mHAAmH,CAAC;AACzL,CAAC;AAED,2FAA2F;AAC3F,MAAM,gBAAgB,GAAG,wFAAwF,CAAC;AAElH,SAAS,MAAM,CAAC,GAAW;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAChC,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC"}
|
package/dist/site-cli.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { SitePolicySchema, simulateTiming } from "@jevitate/domain";
|
|
3
|
+
import { ok, fail } from "./envelope.js";
|
|
4
|
+
import { sitePolicyKey } from "./site-gate-cli.js";
|
|
5
|
+
import { resolveDbPath, withSitePolicyRepository, parsePlannedScript, emitJson } from "./cli-shared.js";
|
|
6
|
+
/** Registers `jevitate site`: `policy get|set` and `simulate`. */
|
|
7
|
+
export function registerSiteCommands(program, deps) {
|
|
8
|
+
const site = program
|
|
9
|
+
.command("site")
|
|
10
|
+
.description("per-site policies for Journey runs: human-like pacing, throttles, run budgets and quiet hours");
|
|
11
|
+
const sitePolicy = site
|
|
12
|
+
.command("policy")
|
|
13
|
+
.description("read or set a site's policy (the site is the Journey's origin, e.g. https://app.example.com)");
|
|
14
|
+
sitePolicy
|
|
15
|
+
.command("get <site>")
|
|
16
|
+
.description("print the policy for a site (an origin) and account")
|
|
17
|
+
.option("--account <account>", "account id", "primary")
|
|
18
|
+
.option("--db <path>", "sqlite db path")
|
|
19
|
+
.option("--json", "emit a JSON envelope")
|
|
20
|
+
.action(async function (siteId) {
|
|
21
|
+
const { account, db, json } = this.opts();
|
|
22
|
+
try {
|
|
23
|
+
const dbPath = resolveDbPath(deps, db);
|
|
24
|
+
const policy = await withSitePolicyRepository(dbPath, (repository) => repository.get(sitePolicyKey(siteId), account));
|
|
25
|
+
const envelope = ok(policy);
|
|
26
|
+
if (json) {
|
|
27
|
+
emitJson(program, envelope);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
if (policy) {
|
|
31
|
+
program.configureOutput().writeOut?.(`policy for '${siteId}' (version ${policy.version}): ${JSON.stringify(policy)}\n`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
program.configureOutput().writeOut?.(`no policy configured for '${siteId}' (account '${account}')\n`);
|
|
35
|
+
}
|
|
36
|
+
process.exitCode = 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
emitJson(program, fail("E_SITE_POLICY_GET", String(err)));
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
sitePolicy
|
|
44
|
+
.command("set <site>")
|
|
45
|
+
.description("set the policy for a site (an origin): Journey runs there are paced, throttled, budgeted and kept out of quiet hours " +
|
|
46
|
+
"(journey run, source run, check, MCP run_journey); load run applies the pacing only")
|
|
47
|
+
.requiredOption("--file <path>", "path to a policy JSON file")
|
|
48
|
+
.option("--account <account>", "account id", "primary")
|
|
49
|
+
.option("--db <path>", "sqlite db path")
|
|
50
|
+
.option("--json", "emit a JSON envelope")
|
|
51
|
+
.action(async function (siteId) {
|
|
52
|
+
const { account, db, file, json } = this.opts();
|
|
53
|
+
let policy;
|
|
54
|
+
try {
|
|
55
|
+
const raw = await readFile(file, "utf8");
|
|
56
|
+
policy = SitePolicySchema.parse(JSON.parse(raw));
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
emitJson(program, fail("E_INVALID_POLICY", String(err)));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const dbPath = resolveDbPath(deps, db);
|
|
64
|
+
// The policy is stored (and reported) under the site's origin: a page URL names its origin.
|
|
65
|
+
const site = sitePolicyKey(siteId);
|
|
66
|
+
await withSitePolicyRepository(dbPath, (repository) => repository.set(site, account, policy));
|
|
67
|
+
const envelope = ok({ site, account, version: policy.version });
|
|
68
|
+
if (json) {
|
|
69
|
+
emitJson(program, envelope);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
program.configureOutput().writeOut?.(`policy for '${site}' (account '${account}') set to version ${policy.version}\n`);
|
|
73
|
+
process.exitCode = 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
emitJson(program, fail("E_SITE_POLICY_SET", String(err)));
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
site
|
|
81
|
+
.command("simulate <site>")
|
|
82
|
+
.description("estimate, offline, how long a planned step script takes under a site's pacing policy")
|
|
83
|
+
.requiredOption("--script <path>", "path to a planned-step script JSON file")
|
|
84
|
+
.option("--seed <n>", "deterministic RNG seed", "0")
|
|
85
|
+
.option("--account <account>", "account id", "primary")
|
|
86
|
+
.option("--db <path>", "sqlite db path")
|
|
87
|
+
.option("--json", "emit a JSON envelope")
|
|
88
|
+
.action(async function (siteId) {
|
|
89
|
+
const { account, db, script, seed, json } = this.opts();
|
|
90
|
+
let plannedScript;
|
|
91
|
+
try {
|
|
92
|
+
const raw = await readFile(script, "utf8");
|
|
93
|
+
plannedScript = parsePlannedScript(raw);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
emitJson(program, fail("E_INVALID_SCRIPT", String(err)));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const seedNum = Number(seed);
|
|
100
|
+
if (!Number.isFinite(seedNum)) {
|
|
101
|
+
emitJson(program, fail("E_INVALID_SEED", `--seed must be a finite number, got ${JSON.stringify(seed)}`));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const dbPath = resolveDbPath(deps, db);
|
|
106
|
+
const policy = await withSitePolicyRepository(dbPath, (repository) => repository.get(sitePolicyKey(siteId), account));
|
|
107
|
+
const interaction = policy?.interaction ?? {};
|
|
108
|
+
const profile = simulateTiming(interaction, seedNum, plannedScript);
|
|
109
|
+
const envelope = ok(profile);
|
|
110
|
+
if (json) {
|
|
111
|
+
emitJson(program, envelope);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
const out = program.configureOutput().writeOut;
|
|
115
|
+
for (const step of profile.steps) {
|
|
116
|
+
out?.(`${step.kind} '${step.label}': ${step.delayMs}ms\n`);
|
|
117
|
+
}
|
|
118
|
+
out?.(`totalMs: ${profile.totalMs}\n`);
|
|
119
|
+
process.exitCode = 0;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
emitJson(program, fail("E_SITE_SIMULATE", String(err)));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=site-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site-cli.js","sourceRoot":"","sources":["../src/site-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Recording } from "@jevitate/recording";
|
|
2
|
+
import type { Ability } from "@jevitate/screenplay";
|
|
3
|
+
import { type SiteGateDeps } from "@jevitate/runtime";
|
|
4
|
+
/**
|
|
5
|
+
* The site-policy gate's repositories (`jevitate site policy set`), opened from the policy database
|
|
6
|
+
* for the duration of `fn`. No database file means no policy was ever set: `fn` gets `undefined`,
|
|
7
|
+
* and nothing is created on disk.
|
|
8
|
+
*/
|
|
9
|
+
export declare function withSiteGate<T>(dbPath: string | undefined, fn: (deps: SiteGateDeps | undefined) => Promise<T>): Promise<T>;
|
|
10
|
+
/** A site policy's key: the origin of a URL (`https://app.example.com/login` → `https://app.example.com`); any other id as given. */
|
|
11
|
+
export declare function sitePolicyKey(site: string): string;
|
|
12
|
+
/** What a gated Journey run gives its actor, and records once it has run. */
|
|
13
|
+
export interface JourneyGate {
|
|
14
|
+
/** The pacing ability (none when no policy declares pacing), spread into `whoCan(...)`. */
|
|
15
|
+
readonly abilities: Ability[];
|
|
16
|
+
/** Records the run against the site's throttle class; call once the run executed, pass or fail. */
|
|
17
|
+
readonly done: () => Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The site-policy gate for one Journey run on `recording.site`'s origin — before any fixture or
|
|
21
|
+
* browser. Throws `SiteGateRefusedError` (quiet hours, min interval, budget) with when to retry.
|
|
22
|
+
* `enforceLimits: false` (a load run) applies only the pacing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function gateJourney(siteGate: SiteGateDeps | undefined, recording: Recording, opts: {
|
|
25
|
+
readonly account?: string;
|
|
26
|
+
readonly enforceLimits: boolean;
|
|
27
|
+
readonly runId?: string;
|
|
28
|
+
}): Promise<JourneyGate>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { openDatabase, migrateToLatest, SqliteActivityRepository, SqliteBudgetRepository, SqliteSitePolicyRepository } from "@jevitate/storage-sqlite";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { SiteGateRefusedError, enterSiteGate, throttleClassOf } from "@jevitate/runtime";
|
|
5
|
+
import { clock as sysClock } from "@jevitate/domain";
|
|
6
|
+
/**
|
|
7
|
+
* The site-policy gate's repositories (`jevitate site policy set`), opened from the policy database
|
|
8
|
+
* for the duration of `fn`. No database file means no policy was ever set: `fn` gets `undefined`,
|
|
9
|
+
* and nothing is created on disk.
|
|
10
|
+
*/
|
|
11
|
+
export async function withSiteGate(dbPath, fn) {
|
|
12
|
+
if (dbPath === undefined || !existsSync(dbPath))
|
|
13
|
+
return fn(undefined);
|
|
14
|
+
const db = openDatabase(dbPath);
|
|
15
|
+
try {
|
|
16
|
+
await migrateToLatest(db);
|
|
17
|
+
const clock = { nowIso: () => sysClock.nowIso(), monotonicMs: () => sysClock.now() };
|
|
18
|
+
return await fn({
|
|
19
|
+
policies: new SqliteSitePolicyRepository(db, clock),
|
|
20
|
+
budgets: new SqliteBudgetRepository(db),
|
|
21
|
+
activity: new SqliteActivityRepository(db),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
await db.destroy();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** A site policy's key: the origin of a URL (`https://app.example.com/login` → `https://app.example.com`); any other id as given. */
|
|
29
|
+
export function sitePolicyKey(site) {
|
|
30
|
+
try {
|
|
31
|
+
const u = new URL(site);
|
|
32
|
+
return u.origin === "null" ? site : u.origin;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return site;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const UNGATED = { abilities: [], done: async () => undefined };
|
|
39
|
+
/**
|
|
40
|
+
* The site-policy gate for one Journey run on `recording.site`'s origin — before any fixture or
|
|
41
|
+
* browser. Throws `SiteGateRefusedError` (quiet hours, min interval, budget) with when to retry.
|
|
42
|
+
* `enforceLimits: false` (a load run) applies only the pacing.
|
|
43
|
+
*/
|
|
44
|
+
export async function gateJourney(siteGate, recording, opts) {
|
|
45
|
+
if (siteGate === undefined)
|
|
46
|
+
return UNGATED;
|
|
47
|
+
const site = sitePolicyKey(recording.site);
|
|
48
|
+
const gate = await enterSiteGate(siteGate, {
|
|
49
|
+
site,
|
|
50
|
+
account: opts.account ?? "primary",
|
|
51
|
+
throttleClass: throttleClassOf(recording),
|
|
52
|
+
runId: opts.runId ?? randomUUID(),
|
|
53
|
+
enforceLimits: opts.enforceLimits,
|
|
54
|
+
});
|
|
55
|
+
if (!gate.ok)
|
|
56
|
+
throw new SiteGateRefusedError(site, gate.reason, gate.retryAfter);
|
|
57
|
+
return { abilities: gate.pace === null ? [] : [gate.pace], done: gate.done };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=site-gate-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site-gate-cli.js","sourceRoot":"","sources":["../src/site-gate-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACvJ,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,eAAe,EAAqB,MAAM,mBAAmB,CAAC;AAC5G,OAAO,EAAE,KAAK,IAAI,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,MAA0B,EAAE,EAAkD;IAClH,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IACtE,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,eAAe,CAAC,EAAE,CAAC,CAAC;QAC1B,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;QACrF,OAAO,MAAM,EAAE,CAAC;YACd,QAAQ,EAAE,IAAI,0BAA0B,CAAC,EAAE,EAAE,KAAK,CAAC;YACnD,OAAO,EAAE,IAAI,sBAAsB,CAAC,EAAE,CAAC;YACvC,QAAQ,EAAE,IAAI,wBAAwB,CAAC,EAAE,CAAC;SAC3C,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,qIAAqI;AACrI,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,OAAO,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAUD,MAAM,OAAO,GAAgB,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;AAE5E;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAkC,EAClC,SAAoB,EACpB,IAA6F;IAE7F,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAC3C,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE;QACzC,IAAI;QACJ,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,SAAS;QAClC,aAAa,EAAE,eAAe,CAAC,SAAS,CAAC;QACzC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,UAAU,EAAE;QACjC,aAAa,EAAE,IAAI,CAAC,aAAa;KAClC,CAAC,CAAC;IACH,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACjF,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;AAC/E,CAAC"}
|
package/dist/source-api.js
CHANGED
|
@@ -4,6 +4,7 @@ import { promisify } from "node:util";
|
|
|
4
4
|
import { FsJourneyStore, JourneyRegistry } from "@jevitate/journey";
|
|
5
5
|
import { GitSourceManager, RemoteSource, UnknownSourceError, collectNavigateOrigins, loadManifest, publishJourney, readLock, surfaceForAck, writeLock, } from "@jevitate/sources";
|
|
6
6
|
import { UnknownJourneyError } from "./journey-api.js";
|
|
7
|
+
import { clock } from "@jevitate/domain";
|
|
7
8
|
const execFileAsync = promisify(execFile);
|
|
8
9
|
/**
|
|
9
10
|
* A publish was requested for a Journey that exists locally but has not been
|
|
@@ -30,11 +31,20 @@ export class NoDeclaredOriginsError extends Error {
|
|
|
30
31
|
this.name = "NoDeclaredOriginsError";
|
|
31
32
|
}
|
|
32
33
|
}
|
|
34
|
+
/** Parses `site`'s origin, or `null` if it isn't a valid absolute URL. */
|
|
35
|
+
function originOf(site) {
|
|
36
|
+
try {
|
|
37
|
+
return new URL(site).origin;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
33
43
|
function mgrOf(deps) {
|
|
34
44
|
return new GitSourceManager(deps.sourcesDir, deps.git);
|
|
35
45
|
}
|
|
36
46
|
function nowIso(deps) {
|
|
37
|
-
return (deps.now ?? (() =>
|
|
47
|
+
return (deps.now ?? (() => clock.nowIso()))();
|
|
38
48
|
}
|
|
39
49
|
/**
|
|
40
50
|
* Resolves a source `name` to its recorded `SourceEntry`, or throws
|
|
@@ -171,9 +181,15 @@ export async function publishJourneyToSource(deps, req) {
|
|
|
171
181
|
if (!journey.metadata.promoted) {
|
|
172
182
|
throw new NotPromotedError(`journey '${req.id}' is not promoted; promote it before publishing`);
|
|
173
183
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
184
|
+
// #125: `explore-author-journey` writes RELATIVE `navigate` urls (the recorded steps are
|
|
185
|
+
// relative to `recording.site`), so `collectNavigateOrigins` — which only resolves ABSOLUTE
|
|
186
|
+
// navigate urls — finds nothing to derive from. Fall back to `recording.site` itself: it's
|
|
187
|
+
// the origin the whole Recording was authored against, and exactly what an explore-authored
|
|
188
|
+
// Journey's relative navigates implicitly stay within.
|
|
189
|
+
const navigateOrigins = collectNavigateOrigins(journey.recording);
|
|
190
|
+
const siteOrigin = originOf(journey.recording.site);
|
|
191
|
+
const derivedOrigins = navigateOrigins.length > 0 ? navigateOrigins : siteOrigin ? [siteOrigin] : [];
|
|
192
|
+
const declaredOrigins = req.declareOrigins && req.declareOrigins.length > 0 ? req.declareOrigins : derivedOrigins;
|
|
177
193
|
if (declaredOrigins.length === 0) {
|
|
178
194
|
throw new NoDeclaredOriginsError(`journey '${req.id}' declares no origins and navigates to no absolute origin; pass --declare-origin <origin>`);
|
|
179
195
|
}
|
package/dist/source-api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-api.js","sourceRoot":"","sources":["../src/source-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,aAAa,EACb,SAAS,GASV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"source-api.js","sourceRoot":"","sources":["../src/source-api.ts"],"names":[],"mappings":"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"}
|