@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,155 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { Journey } from "@jevitate/journey";
|
|
3
|
+
import type { Recording } from "@jevitate/recording";
|
|
4
|
+
import { type LayoutDeps } from "./project-dir.js";
|
|
5
|
+
import { type TargetConfig } from "./target-config.js";
|
|
6
|
+
/**
|
|
7
|
+
* Named environments (#247). A Journey is environment-free: its steps are app-relative paths
|
|
8
|
+
* (`/login`), and its recorded `site` is only its DEFAULT environment. Which app a run replays
|
|
9
|
+
* against is chosen at run time:
|
|
10
|
+
*
|
|
11
|
+
* - `--env <name>` — an entry of the repo's committed `.jevitate/environments.json`:
|
|
12
|
+
*
|
|
13
|
+
* ```json
|
|
14
|
+
* { "local": { "baseUrl": "http://localhost:3000" },
|
|
15
|
+
* "staging": { "baseUrl": "https://staging.example.com", "allow": ["https://auth.example.com"],
|
|
16
|
+
* "fixtures": "fixtures/staging.json", "hooks": { "before": "./scripts/seed.sh" } } }
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* `baseUrl` — the environment's origin (never a path, never credentials); `allow` — the other
|
|
20
|
+
* origins a Journey step may be on (an auth provider, say); `fixtures` — a mission fixtures file
|
|
21
|
+
* (relative to the environments file) used when `--fixtures` is absent; `hooks` — `before`/
|
|
22
|
+
* `after` shell hooks used when `--before`/`--after` are absent (they still need
|
|
23
|
+
* `--allow-shell-hooks`); `production: true` marks a live environment (`jevitate demo` refuses it,
|
|
24
|
+
* #249). Keys starting with `$` (`$comment`) are documentation. The file is
|
|
25
|
+
* committed, so it NEVER holds a secret or a session: a `storageState`/`secret`/`password`/
|
|
26
|
+
* `token`/`cookie`/`credential` key anywhere in it is refused.
|
|
27
|
+
* - `--base-url <origin>` — an ad-hoc environment (a preview deploy); with `--env`, it replaces
|
|
28
|
+
* that environment's `baseUrl` and keeps the rest.
|
|
29
|
+
*
|
|
30
|
+
* Per-environment sessions and secrets live in `~/.jevitate/targets.json`, keyed by the
|
|
31
|
+
* environment's origin — the same per-origin operator file (#175) `mission run` and `verify_fix`
|
|
32
|
+
* already read: `storageState` (the default session), `secretFields` (`env:VAR` bindings), and
|
|
33
|
+
* `personas: { "<name>": { storageState?, secretFields? } }` for one session per persona. No `--env`
|
|
34
|
+
* and no `--base-url` means exactly the pre-#247 behaviour: the Journey's recorded site.
|
|
35
|
+
*
|
|
36
|
+
* `resolveJourneyEnvironment` is THE one resolver every Journey-running command calls (`journey
|
|
37
|
+
* run`, `regression run`, `load run`, check-suite Journey items, and later `journey annotate` /
|
|
38
|
+
* `journey demo`); `applyJourneyEnvironment` rebases a Journey onto it and refuses a step on an
|
|
39
|
+
* origin the environment does not allow — before any browser opens.
|
|
40
|
+
*/
|
|
41
|
+
export { ENVIRONMENTS_FILE, ENVIRONMENTS_SCAFFOLD, scaffoldEnvironmentsFile } from "./project-dir.js";
|
|
42
|
+
/** One environment, as declared in `.jevitate/environments.json` (paths resolved absolute). */
|
|
43
|
+
export interface EnvironmentDef {
|
|
44
|
+
/** The environment's origin (`https://staging.example.com`), normalized. */
|
|
45
|
+
readonly baseUrl: string;
|
|
46
|
+
/** Other origins a Journey step may be on, normalized. */
|
|
47
|
+
readonly allow: readonly string[];
|
|
48
|
+
/** Mission fixtures file, absolute. */
|
|
49
|
+
readonly fixtures?: string;
|
|
50
|
+
/** Operator shell hooks (still gated by `--allow-shell-hooks`). */
|
|
51
|
+
readonly hooks?: {
|
|
52
|
+
readonly before?: string;
|
|
53
|
+
readonly after?: string;
|
|
54
|
+
};
|
|
55
|
+
/** `production: true` (#249): a live environment — `jevitate demo` refuses it. */
|
|
56
|
+
readonly production?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** `.jevitate/environments.json` is missing a named environment, or is not what it should be. */
|
|
59
|
+
export declare class EnvironmentConfigError extends Error {
|
|
60
|
+
readonly code: "E_ENV_CONFIG";
|
|
61
|
+
constructor(message: string);
|
|
62
|
+
}
|
|
63
|
+
/** `--env <name>` names no environment (exit 64, listing the known ones). */
|
|
64
|
+
export declare class UnknownEnvironmentError extends Error {
|
|
65
|
+
readonly env: string;
|
|
66
|
+
readonly known: readonly string[];
|
|
67
|
+
readonly code: "E_ENV_UNKNOWN";
|
|
68
|
+
constructor(env: string, known: readonly string[], where: string | null);
|
|
69
|
+
}
|
|
70
|
+
/** `--base-url` is not an origin. */
|
|
71
|
+
export declare class EnvironmentArgsError extends Error {
|
|
72
|
+
readonly code: "E_ENV_ARGS";
|
|
73
|
+
constructor(message: string);
|
|
74
|
+
}
|
|
75
|
+
/** A Journey step is on an origin the chosen environment does not allow (exit 64, nothing opened). */
|
|
76
|
+
export declare class EnvironmentOriginRefusedError extends Error {
|
|
77
|
+
readonly code: "E_ENV_ORIGIN_REFUSED";
|
|
78
|
+
constructor(message: string);
|
|
79
|
+
}
|
|
80
|
+
/** Every error the resolver or the rebase can throw — each a usage refusal (exit 64). */
|
|
81
|
+
export type EnvironmentError = EnvironmentConfigError | UnknownEnvironmentError | EnvironmentArgsError | EnvironmentOriginRefusedError;
|
|
82
|
+
export declare function isEnvironmentError(err: unknown): err is EnvironmentError;
|
|
83
|
+
/** Validates a parsed environments file (`where` names it in every error). */
|
|
84
|
+
export declare function parseEnvironments(parsed: unknown, where: string, baseDir: string): Readonly<Record<string, EnvironmentDef>>;
|
|
85
|
+
/** The repo's `.jevitate/environments.json` (found as `.jevitate/` is), or `null` outside a project. */
|
|
86
|
+
export declare function environmentsFilePath(deps?: LayoutDeps): string | null;
|
|
87
|
+
/** Reads and validates an environments file. A missing file is "no environments". */
|
|
88
|
+
export declare function loadEnvironmentsFile(path: string): Readonly<Record<string, EnvironmentDef>>;
|
|
89
|
+
/** The chosen environment for one run: where the Journey goes, what it may reach, and its local session. */
|
|
90
|
+
export interface ResolvedJourneyEnvironment {
|
|
91
|
+
/** The environment's name (`--env`), absent for a bare `--base-url`. */
|
|
92
|
+
readonly name?: string;
|
|
93
|
+
/** The origin the Journey's paths are moved onto. */
|
|
94
|
+
readonly baseUrl: string;
|
|
95
|
+
/** Every origin a step may be on: `baseUrl`, then the environment's `allow`. */
|
|
96
|
+
readonly allowedOrigins: readonly string[];
|
|
97
|
+
readonly fixtures?: string;
|
|
98
|
+
readonly hooks?: {
|
|
99
|
+
readonly before?: string;
|
|
100
|
+
readonly after?: string;
|
|
101
|
+
};
|
|
102
|
+
/** From `~/.jevitate/targets.json[baseUrl]` (or its `personas[persona]`): the default session. */
|
|
103
|
+
readonly storageState?: string;
|
|
104
|
+
/** From `~/.jevitate/targets.json[baseUrl]` (or its persona): `env:VAR` secret-field specs. */
|
|
105
|
+
readonly secretFields?: readonly string[];
|
|
106
|
+
/** Where the environment came from (`--env`'s file, or `--base-url`). */
|
|
107
|
+
readonly source: string;
|
|
108
|
+
/** The named environment is flagged `production: true` (#249: `demo` refuses it). */
|
|
109
|
+
readonly production?: true;
|
|
110
|
+
}
|
|
111
|
+
export interface JourneyEnvironmentRequest {
|
|
112
|
+
/** `--env <name>`. */
|
|
113
|
+
readonly env?: string;
|
|
114
|
+
/** `--base-url <origin>`. */
|
|
115
|
+
readonly baseUrl?: string;
|
|
116
|
+
/** A persona under the origin's `personas` in `~/.jevitate/targets.json` (its session and secrets). */
|
|
117
|
+
readonly persona?: string;
|
|
118
|
+
/** The environments file (default: the repo's `.jevitate/environments.json`). */
|
|
119
|
+
readonly environmentsFile?: string;
|
|
120
|
+
/** `~/.jevitate/targets.json` (the per-origin operator file). */
|
|
121
|
+
readonly targetsFile?: string;
|
|
122
|
+
/** An already-loaded targets file (wins over `targetsFile`). */
|
|
123
|
+
readonly targets?: Readonly<Record<string, TargetConfig>>;
|
|
124
|
+
readonly layout?: LayoutDeps;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* THE environment resolver (#247). `undefined` when neither `env` nor `baseUrl` is given — the
|
|
128
|
+
* caller then runs exactly as before, on the Journey's recorded site. Throws `UnknownEnvironmentError`
|
|
129
|
+
* (listing the known names), `EnvironmentConfigError` (a bad file, path-precise; a persona the
|
|
130
|
+
* origin does not declare), or `EnvironmentArgsError` (a `baseUrl` that is not an origin).
|
|
131
|
+
*/
|
|
132
|
+
export declare function resolveJourneyEnvironment(req: JourneyEnvironmentRequest): ResolvedJourneyEnvironment | undefined;
|
|
133
|
+
/**
|
|
134
|
+
* Moves a Recording onto `env` (#247): its `site` becomes the environment's `baseUrl`; every
|
|
135
|
+
* absolute URL on the recorded site's origin (page urls, `navigate` urls, `urlIncludes` texts)
|
|
136
|
+
* keeps its path/query/fragment on the new origin; app-relative paths are left as they are (they
|
|
137
|
+
* resolve against the environment). A page or `navigate` step on any OTHER origin must be in the
|
|
138
|
+
* environment's `allow` — otherwise `EnvironmentOriginRefusedError`, before anything opens.
|
|
139
|
+
* Never guesses, never mutates the input.
|
|
140
|
+
*/
|
|
141
|
+
export declare function rebaseRecording(recording: Recording, env: ResolvedJourneyEnvironment): Recording;
|
|
142
|
+
/** `rebaseRecording` for a whole Journey (its metadata, incl. origin-bound secretRefs, is untouched: fail closed). */
|
|
143
|
+
export declare function applyJourneyEnvironment(journey: Journey, env: ResolvedJourneyEnvironment | undefined): Journey;
|
|
144
|
+
/** Raw commander values of `--env` / `--base-url`. */
|
|
145
|
+
export interface EnvironmentFlags {
|
|
146
|
+
readonly env?: string;
|
|
147
|
+
readonly baseUrl?: string;
|
|
148
|
+
}
|
|
149
|
+
/** Adds `--env <name>` and `--base-url <origin>` (#247). */
|
|
150
|
+
export declare function withEnvironmentFlags(cmd: Command): Command;
|
|
151
|
+
/** The environment a command's `--env`/`--base-url` flags choose (see `resolveJourneyEnvironment`). */
|
|
152
|
+
export declare function environmentFromFlags(flags: EnvironmentFlags, seams?: {
|
|
153
|
+
readonly environmentsFile?: string;
|
|
154
|
+
readonly targetsFile?: string;
|
|
155
|
+
}): ResolvedJourneyEnvironment | undefined;
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve as resolvePath } from "node:path";
|
|
3
|
+
import { ENVIRONMENTS_FILE, findProjectDir } from "./project-dir.js";
|
|
4
|
+
import { loadTargetsFile, TargetConfigError } from "./target-config.js";
|
|
5
|
+
/**
|
|
6
|
+
* Named environments (#247). A Journey is environment-free: its steps are app-relative paths
|
|
7
|
+
* (`/login`), and its recorded `site` is only its DEFAULT environment. Which app a run replays
|
|
8
|
+
* against is chosen at run time:
|
|
9
|
+
*
|
|
10
|
+
* - `--env <name>` — an entry of the repo's committed `.jevitate/environments.json`:
|
|
11
|
+
*
|
|
12
|
+
* ```json
|
|
13
|
+
* { "local": { "baseUrl": "http://localhost:3000" },
|
|
14
|
+
* "staging": { "baseUrl": "https://staging.example.com", "allow": ["https://auth.example.com"],
|
|
15
|
+
* "fixtures": "fixtures/staging.json", "hooks": { "before": "./scripts/seed.sh" } } }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* `baseUrl` — the environment's origin (never a path, never credentials); `allow` — the other
|
|
19
|
+
* origins a Journey step may be on (an auth provider, say); `fixtures` — a mission fixtures file
|
|
20
|
+
* (relative to the environments file) used when `--fixtures` is absent; `hooks` — `before`/
|
|
21
|
+
* `after` shell hooks used when `--before`/`--after` are absent (they still need
|
|
22
|
+
* `--allow-shell-hooks`); `production: true` marks a live environment (`jevitate demo` refuses it,
|
|
23
|
+
* #249). Keys starting with `$` (`$comment`) are documentation. The file is
|
|
24
|
+
* committed, so it NEVER holds a secret or a session: a `storageState`/`secret`/`password`/
|
|
25
|
+
* `token`/`cookie`/`credential` key anywhere in it is refused.
|
|
26
|
+
* - `--base-url <origin>` — an ad-hoc environment (a preview deploy); with `--env`, it replaces
|
|
27
|
+
* that environment's `baseUrl` and keeps the rest.
|
|
28
|
+
*
|
|
29
|
+
* Per-environment sessions and secrets live in `~/.jevitate/targets.json`, keyed by the
|
|
30
|
+
* environment's origin — the same per-origin operator file (#175) `mission run` and `verify_fix`
|
|
31
|
+
* already read: `storageState` (the default session), `secretFields` (`env:VAR` bindings), and
|
|
32
|
+
* `personas: { "<name>": { storageState?, secretFields? } }` for one session per persona. No `--env`
|
|
33
|
+
* and no `--base-url` means exactly the pre-#247 behaviour: the Journey's recorded site.
|
|
34
|
+
*
|
|
35
|
+
* `resolveJourneyEnvironment` is THE one resolver every Journey-running command calls (`journey
|
|
36
|
+
* run`, `regression run`, `load run`, check-suite Journey items, and later `journey annotate` /
|
|
37
|
+
* `journey demo`); `applyJourneyEnvironment` rebases a Journey onto it and refuses a step on an
|
|
38
|
+
* origin the environment does not allow — before any browser opens.
|
|
39
|
+
*/
|
|
40
|
+
export { ENVIRONMENTS_FILE, ENVIRONMENTS_SCAFFOLD, scaffoldEnvironmentsFile } from "./project-dir.js";
|
|
41
|
+
/** `.jevitate/environments.json` is missing a named environment, or is not what it should be. */
|
|
42
|
+
export class EnvironmentConfigError extends Error {
|
|
43
|
+
code = "E_ENV_CONFIG";
|
|
44
|
+
constructor(message) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = "EnvironmentConfigError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** `--env <name>` names no environment (exit 64, listing the known ones). */
|
|
50
|
+
export class UnknownEnvironmentError extends Error {
|
|
51
|
+
env;
|
|
52
|
+
known;
|
|
53
|
+
code = "E_ENV_UNKNOWN";
|
|
54
|
+
constructor(env, known, where) {
|
|
55
|
+
super(`unknown environment ${JSON.stringify(env)}: ${known.length === 0
|
|
56
|
+
? `no environments are declared${where === null ? " (no .jevitate/environments.json — run `jevitate init` in the repo)" : ` in ${where}`}`
|
|
57
|
+
: `known environments: ${known.join(", ")}${where === null ? "" : ` (${where})`}`}`);
|
|
58
|
+
this.env = env;
|
|
59
|
+
this.known = known;
|
|
60
|
+
this.name = "UnknownEnvironmentError";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** `--base-url` is not an origin. */
|
|
64
|
+
export class EnvironmentArgsError extends Error {
|
|
65
|
+
code = "E_ENV_ARGS";
|
|
66
|
+
constructor(message) {
|
|
67
|
+
super(message);
|
|
68
|
+
this.name = "EnvironmentArgsError";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** A Journey step is on an origin the chosen environment does not allow (exit 64, nothing opened). */
|
|
72
|
+
export class EnvironmentOriginRefusedError extends Error {
|
|
73
|
+
code = "E_ENV_ORIGIN_REFUSED";
|
|
74
|
+
constructor(message) {
|
|
75
|
+
super(message);
|
|
76
|
+
this.name = "EnvironmentOriginRefusedError";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function isEnvironmentError(err) {
|
|
80
|
+
return (err instanceof EnvironmentConfigError ||
|
|
81
|
+
err instanceof UnknownEnvironmentError ||
|
|
82
|
+
err instanceof EnvironmentArgsError ||
|
|
83
|
+
err instanceof EnvironmentOriginRefusedError);
|
|
84
|
+
}
|
|
85
|
+
const ENV_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
86
|
+
const ENV_KEYS = new Set(["baseUrl", "allow", "fixtures", "hooks", "production"]);
|
|
87
|
+
const HOOK_KEYS = new Set(["before", "after"]);
|
|
88
|
+
/** A key that would put a secret or a session into a committed file. */
|
|
89
|
+
const SECRET_KEY = /storage.?state|secret|passw(or)?d|token|cookie|credential|api.?key|session|auth(orization)?$/i;
|
|
90
|
+
/** An `http(s)` origin — no path, query, fragment or credentials. `null` + the reason otherwise. */
|
|
91
|
+
function originOf(raw) {
|
|
92
|
+
if (typeof raw !== "string" || raw.trim() === "")
|
|
93
|
+
return { reason: "must be an http(s) origin string" };
|
|
94
|
+
let u;
|
|
95
|
+
try {
|
|
96
|
+
u = new URL(raw);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return { reason: `must be an http(s) origin (got ${JSON.stringify(raw)})` };
|
|
100
|
+
}
|
|
101
|
+
if (u.protocol !== "http:" && u.protocol !== "https:")
|
|
102
|
+
return { reason: `must be an http(s) origin (got ${JSON.stringify(raw)})` };
|
|
103
|
+
if (u.username !== "" || u.password !== "")
|
|
104
|
+
return { reason: "must not carry credentials (user:password@) — sessions and secrets live in ~/.jevitate/targets.json" };
|
|
105
|
+
if ((u.pathname !== "/" && u.pathname !== "") || u.search !== "" || u.hash !== "") {
|
|
106
|
+
return { reason: `must be an origin with no path, query or fragment (got ${JSON.stringify(raw)}; Journeys carry app-relative paths)` };
|
|
107
|
+
}
|
|
108
|
+
return { origin: u.origin };
|
|
109
|
+
}
|
|
110
|
+
/** Refuses any secret-looking key, anywhere in the value (path-precise). */
|
|
111
|
+
function refuseSecretKeys(v, where) {
|
|
112
|
+
if (Array.isArray(v)) {
|
|
113
|
+
v.forEach((x, i) => refuseSecretKeys(x, `${where}[${i}]`));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (v === null || typeof v !== "object")
|
|
117
|
+
return;
|
|
118
|
+
for (const [k, x] of Object.entries(v)) {
|
|
119
|
+
if (SECRET_KEY.test(k)) {
|
|
120
|
+
throw new EnvironmentConfigError(`${where}.${k}: environments.json is committed with the app's code and never holds secrets or sessions — ` +
|
|
121
|
+
`put storage states and secret fields in ~/.jevitate/targets.json under the environment's origin ("storageState", "secretFields", "personas")`);
|
|
122
|
+
}
|
|
123
|
+
refuseSecretKeys(x, `${where}.${k}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function parseEnvironment(v, where, baseDir) {
|
|
127
|
+
if (v === null || typeof v !== "object" || Array.isArray(v))
|
|
128
|
+
throw new EnvironmentConfigError(`${where} must be an object { baseUrl, allow?, fixtures?, hooks? }`);
|
|
129
|
+
refuseSecretKeys(v, where);
|
|
130
|
+
const o = v;
|
|
131
|
+
for (const k of Object.keys(o)) {
|
|
132
|
+
if (!ENV_KEYS.has(k) && !k.startsWith("$"))
|
|
133
|
+
throw new EnvironmentConfigError(`${where}.${k}: unknown key (allowed: baseUrl, allow, fixtures, hooks, production)`);
|
|
134
|
+
}
|
|
135
|
+
if (o.baseUrl === undefined)
|
|
136
|
+
throw new EnvironmentConfigError(`${where}.baseUrl is required`);
|
|
137
|
+
const base = originOf(o.baseUrl);
|
|
138
|
+
if ("reason" in base)
|
|
139
|
+
throw new EnvironmentConfigError(`${where}.baseUrl ${base.reason}`);
|
|
140
|
+
const allow = [];
|
|
141
|
+
if (o.allow !== undefined) {
|
|
142
|
+
if (!Array.isArray(o.allow))
|
|
143
|
+
throw new EnvironmentConfigError(`${where}.allow must be an array of http(s) origins`);
|
|
144
|
+
o.allow.forEach((a, i) => {
|
|
145
|
+
const r = originOf(a);
|
|
146
|
+
if ("reason" in r)
|
|
147
|
+
throw new EnvironmentConfigError(`${where}.allow[${i}] ${r.reason}`);
|
|
148
|
+
if (!allow.includes(r.origin))
|
|
149
|
+
allow.push(r.origin);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
let fixtures;
|
|
153
|
+
if (o.fixtures !== undefined) {
|
|
154
|
+
if (typeof o.fixtures !== "string" || o.fixtures === "")
|
|
155
|
+
throw new EnvironmentConfigError(`${where}.fixtures must be a file path`);
|
|
156
|
+
fixtures = resolvePath(baseDir, o.fixtures);
|
|
157
|
+
}
|
|
158
|
+
let hooks;
|
|
159
|
+
if (o.hooks !== undefined) {
|
|
160
|
+
if (o.hooks === null || typeof o.hooks !== "object" || Array.isArray(o.hooks))
|
|
161
|
+
throw new EnvironmentConfigError(`${where}.hooks must be an object { before?, after? }`);
|
|
162
|
+
hooks = {};
|
|
163
|
+
for (const [k, h] of Object.entries(o.hooks)) {
|
|
164
|
+
if (k.startsWith("$"))
|
|
165
|
+
continue;
|
|
166
|
+
if (!HOOK_KEYS.has(k))
|
|
167
|
+
throw new EnvironmentConfigError(`${where}.hooks.${k}: unknown key (allowed: before, after)`);
|
|
168
|
+
if (typeof h !== "string" || h.trim() === "")
|
|
169
|
+
throw new EnvironmentConfigError(`${where}.hooks.${k} must be a shell command string`);
|
|
170
|
+
hooks[k] = h;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (o.production !== undefined && typeof o.production !== "boolean")
|
|
174
|
+
throw new EnvironmentConfigError(`${where}.production must be true or false`);
|
|
175
|
+
return {
|
|
176
|
+
baseUrl: base.origin,
|
|
177
|
+
allow: allow.filter((a) => a !== base.origin),
|
|
178
|
+
...(fixtures === undefined ? {} : { fixtures }),
|
|
179
|
+
...(hooks === undefined ? {} : { hooks }),
|
|
180
|
+
...(o.production === true ? { production: true } : {}),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/** Validates a parsed environments file (`where` names it in every error). */
|
|
184
|
+
export function parseEnvironments(parsed, where, baseDir) {
|
|
185
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
186
|
+
throw new EnvironmentConfigError(`${where} must be an object keyed by environment name ({ "local": { "baseUrl": "http://localhost:3000" } })`);
|
|
187
|
+
}
|
|
188
|
+
const out = {};
|
|
189
|
+
for (const [name, v] of Object.entries(parsed)) {
|
|
190
|
+
if (name.startsWith("$"))
|
|
191
|
+
continue;
|
|
192
|
+
if (!ENV_NAME.test(name) || name.includes("..") || name.length > 64) {
|
|
193
|
+
throw new EnvironmentConfigError(`${where}[${JSON.stringify(name)}]: an environment name is letters, digits, '.', '_' or '-', starting with a letter or digit`);
|
|
194
|
+
}
|
|
195
|
+
out[name] = parseEnvironment(v, `${where}[${name}]`, baseDir);
|
|
196
|
+
}
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
/** The repo's `.jevitate/environments.json` (found as `.jevitate/` is), or `null` outside a project. */
|
|
200
|
+
export function environmentsFilePath(deps = {}) {
|
|
201
|
+
const dir = findProjectDir(deps);
|
|
202
|
+
return dir === null ? null : join(dir, ENVIRONMENTS_FILE);
|
|
203
|
+
}
|
|
204
|
+
/** Reads and validates an environments file. A missing file is "no environments". */
|
|
205
|
+
export function loadEnvironmentsFile(path) {
|
|
206
|
+
let raw;
|
|
207
|
+
try {
|
|
208
|
+
raw = readFileSync(path, "utf8");
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT")
|
|
212
|
+
return {};
|
|
213
|
+
throw new EnvironmentConfigError(`cannot read ${path}: ${e instanceof Error ? e.message : String(e)}`);
|
|
214
|
+
}
|
|
215
|
+
let parsed;
|
|
216
|
+
try {
|
|
217
|
+
parsed = JSON.parse(raw);
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
throw new EnvironmentConfigError(`${path} is not valid JSON`);
|
|
221
|
+
}
|
|
222
|
+
return parseEnvironments(parsed, path, dirname(path));
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* THE environment resolver (#247). `undefined` when neither `env` nor `baseUrl` is given — the
|
|
226
|
+
* caller then runs exactly as before, on the Journey's recorded site. Throws `UnknownEnvironmentError`
|
|
227
|
+
* (listing the known names), `EnvironmentConfigError` (a bad file, path-precise; a persona the
|
|
228
|
+
* origin does not declare), or `EnvironmentArgsError` (a `baseUrl` that is not an origin).
|
|
229
|
+
*/
|
|
230
|
+
export function resolveJourneyEnvironment(req) {
|
|
231
|
+
if (req.env === undefined && req.baseUrl === undefined) {
|
|
232
|
+
if (req.persona !== undefined)
|
|
233
|
+
throw new EnvironmentArgsError("a persona needs an environment (--env <name> or --base-url <origin>)");
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
let def;
|
|
237
|
+
let source = "--base-url";
|
|
238
|
+
if (req.env !== undefined) {
|
|
239
|
+
const file = req.environmentsFile ?? environmentsFilePath(req.layout);
|
|
240
|
+
const envs = file === null ? {} : loadEnvironmentsFile(file);
|
|
241
|
+
def = Object.prototype.hasOwnProperty.call(envs, req.env) ? envs[req.env] : undefined;
|
|
242
|
+
if (def === undefined)
|
|
243
|
+
throw new UnknownEnvironmentError(req.env, Object.keys(envs).sort(), file !== null && existsSync(file) ? file : null);
|
|
244
|
+
source = `${file}[${req.env}]`;
|
|
245
|
+
}
|
|
246
|
+
let baseUrl = def?.baseUrl;
|
|
247
|
+
if (req.baseUrl !== undefined) {
|
|
248
|
+
const r = originOf(req.baseUrl);
|
|
249
|
+
if ("reason" in r)
|
|
250
|
+
throw new EnvironmentArgsError(`--base-url ${r.reason}`);
|
|
251
|
+
baseUrl = r.origin;
|
|
252
|
+
}
|
|
253
|
+
if (baseUrl === undefined)
|
|
254
|
+
throw new EnvironmentArgsError("no base URL"); // unreachable: env or baseUrl is set
|
|
255
|
+
const allow = (def?.allow ?? []).filter((a) => a !== baseUrl);
|
|
256
|
+
let targets;
|
|
257
|
+
try {
|
|
258
|
+
targets = req.targets ?? (req.targetsFile === undefined ? loadTargetsFile() : loadTargetsFile(req.targetsFile));
|
|
259
|
+
}
|
|
260
|
+
catch (e) {
|
|
261
|
+
if (e instanceof TargetConfigError)
|
|
262
|
+
throw new EnvironmentConfigError(e.message);
|
|
263
|
+
throw e;
|
|
264
|
+
}
|
|
265
|
+
const local = targets[baseUrl];
|
|
266
|
+
let session = local;
|
|
267
|
+
if (req.persona !== undefined) {
|
|
268
|
+
session = local?.personas?.[req.persona];
|
|
269
|
+
if (session === undefined) {
|
|
270
|
+
const known = Object.keys(local?.personas ?? {});
|
|
271
|
+
throw new EnvironmentConfigError(`persona ${JSON.stringify(req.persona)} has no session for ${baseUrl} in ~/.jevitate/targets.json` +
|
|
272
|
+
(known.length === 0 ? "" : ` (known personas: ${known.join(", ")})`));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
...(req.env === undefined ? {} : { name: req.env }),
|
|
277
|
+
baseUrl,
|
|
278
|
+
allowedOrigins: [baseUrl, ...allow],
|
|
279
|
+
...(def?.fixtures === undefined ? {} : { fixtures: def.fixtures }),
|
|
280
|
+
...(def?.hooks === undefined ? {} : { hooks: def.hooks }),
|
|
281
|
+
...(session?.storageState === undefined ? {} : { storageState: session.storageState }),
|
|
282
|
+
...(session?.secretFields === undefined ? {} : { secretFields: session.secretFields }),
|
|
283
|
+
source,
|
|
284
|
+
...(def?.production === true ? { production: true } : {}),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function absoluteUrl(s) {
|
|
288
|
+
if (!/^https?:\/\//i.test(s))
|
|
289
|
+
return null;
|
|
290
|
+
try {
|
|
291
|
+
return new URL(s);
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Moves a Recording onto `env` (#247): its `site` becomes the environment's `baseUrl`; every
|
|
299
|
+
* absolute URL on the recorded site's origin (page urls, `navigate` urls, `urlIncludes` texts)
|
|
300
|
+
* keeps its path/query/fragment on the new origin; app-relative paths are left as they are (they
|
|
301
|
+
* resolve against the environment). A page or `navigate` step on any OTHER origin must be in the
|
|
302
|
+
* environment's `allow` — otherwise `EnvironmentOriginRefusedError`, before anything opens.
|
|
303
|
+
* Never guesses, never mutates the input.
|
|
304
|
+
*/
|
|
305
|
+
export function rebaseRecording(recording, env) {
|
|
306
|
+
const recordedOrigin = absoluteUrl(recording.site)?.origin;
|
|
307
|
+
const refusals = [];
|
|
308
|
+
const move = (raw, where, mustBeAllowed) => {
|
|
309
|
+
const u = absoluteUrl(raw);
|
|
310
|
+
if (u === null)
|
|
311
|
+
return raw;
|
|
312
|
+
if (recordedOrigin !== undefined && u.origin === recordedOrigin)
|
|
313
|
+
return `${env.baseUrl}${u.pathname}${u.search}${u.hash}`;
|
|
314
|
+
if (mustBeAllowed && !env.allowedOrigins.includes(u.origin))
|
|
315
|
+
refusals.push(`${where} is on ${u.origin}`);
|
|
316
|
+
return raw;
|
|
317
|
+
};
|
|
318
|
+
const walk = (v, where) => {
|
|
319
|
+
if (Array.isArray(v))
|
|
320
|
+
return v.map((x, i) => walk(x, `${where}[${i}]`));
|
|
321
|
+
if (v === null || typeof v !== "object")
|
|
322
|
+
return v;
|
|
323
|
+
const o = v;
|
|
324
|
+
const out = {};
|
|
325
|
+
for (const [k, x] of Object.entries(o))
|
|
326
|
+
out[k] = walk(x, `${where}.${k}`);
|
|
327
|
+
if (o.kind === "navigate" && typeof o.url === "string")
|
|
328
|
+
out.url = move(o.url, `${where} (navigate ${o.url})`, true);
|
|
329
|
+
if (o.kind === "urlIncludes" && typeof o.text === "string")
|
|
330
|
+
out.text = move(o.text, `${where}.text`, false);
|
|
331
|
+
return out;
|
|
332
|
+
};
|
|
333
|
+
const pages = recording.pages.map((p, i) => ({
|
|
334
|
+
...walk(p, `pages[${i}]`),
|
|
335
|
+
url: move(p.url, `pages[${i}] (${p.url})`, true),
|
|
336
|
+
}));
|
|
337
|
+
if (refusals.length > 0) {
|
|
338
|
+
throw new EnvironmentOriginRefusedError(`${refusals.join("; ")} — not allowed by the ${env.name === undefined ? `--base-url ${env.baseUrl}` : `environment '${env.name}'`} ` +
|
|
339
|
+
`(allowed: ${env.allowedOrigins.join(", ")}). Add the origin to its "allow" in .jevitate/environments.json to permit it; nothing was opened`);
|
|
340
|
+
}
|
|
341
|
+
return { ...recording, site: env.baseUrl, pages };
|
|
342
|
+
}
|
|
343
|
+
/** `rebaseRecording` for a whole Journey (its metadata, incl. origin-bound secretRefs, is untouched: fail closed). */
|
|
344
|
+
export function applyJourneyEnvironment(journey, env) {
|
|
345
|
+
if (env === undefined)
|
|
346
|
+
return journey;
|
|
347
|
+
return { ...journey, recording: rebaseRecording(journey.recording, env) };
|
|
348
|
+
}
|
|
349
|
+
/** Adds `--env <name>` and `--base-url <origin>` (#247). */
|
|
350
|
+
export function withEnvironmentFlags(cmd) {
|
|
351
|
+
return cmd
|
|
352
|
+
.option("--env <name>", "run against a named environment from the repo's .jevitate/environments.json (default: the Journey's recorded site)")
|
|
353
|
+
.option("--base-url <origin>", "run against this origin (an ad-hoc environment; with --env, replaces its baseUrl)");
|
|
354
|
+
}
|
|
355
|
+
/** The environment a command's `--env`/`--base-url` flags choose (see `resolveJourneyEnvironment`). */
|
|
356
|
+
export function environmentFromFlags(flags, seams = {}) {
|
|
357
|
+
return resolveJourneyEnvironment({
|
|
358
|
+
...(flags.env === undefined ? {} : { env: flags.env }),
|
|
359
|
+
...(flags.baseUrl === undefined ? {} : { baseUrl: flags.baseUrl }),
|
|
360
|
+
...(seams.environmentsFile === undefined ? {} : { environmentsFile: seams.environmentsFile }),
|
|
361
|
+
...(seams.targetsFile === undefined ? {} : { targetsFile: seams.targetsFile }),
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=environments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environments.js","sourceRoot":"","sources":["../src/environments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type MissionOutcome } from "@jevitate/domain";
|
|
2
|
+
/**
|
|
3
|
+
* THE exit-code table for every `jevitate` command (#210) — documented once, in
|
|
4
|
+
* docs/outcomes.md "Exit codes", and linked from everywhere else. Every command sets
|
|
5
|
+
* `process.exitCode` from this table (directly, or through `exitCodeForError` for a refused
|
|
6
|
+
* command), so CI can tell a typo from a defect from a run that proved nothing:
|
|
7
|
+
*
|
|
8
|
+
* | code | class | meaning |
|
|
9
|
+
* |------|---------------|--------------------------------------------------------------------------------|
|
|
10
|
+
* | 0 | ok | clean · succeeded · check passed · fixed · the command did what it was asked |
|
|
11
|
+
* | 1 | defects | defects found · a gating finding · still reproduces · a success check failed |
|
|
12
|
+
* | 2 | inconclusive | the run/command could not finish its work (inconclusive, crashed, an item |
|
|
13
|
+
* | | | errored, budget exceeded, an unexpected error) — it proves nothing |
|
|
14
|
+
* | 3 | hang | the app under test hung, and the hang reproduced on replay |
|
|
15
|
+
* | 4 | intermittent | a signal fired on some but not every replay |
|
|
16
|
+
* | 64 | usage | bad flags/arguments or unusable input (unknown id, invalid file, missing keys, |
|
|
17
|
+
* | | | refused target) — nothing ran. `EX_USAGE` from sysexits.h. |
|
|
18
|
+
* | 130/143 | killed | SIGINT / SIGTERM (kill-signal.ts); the partial result is still written |
|
|
19
|
+
*
|
|
20
|
+
* 0–4 are the pre-existing mission codes (`MISSION_EXIT_CODES`, @jevitate/domain) unchanged; the
|
|
21
|
+
* mission outcome → code mapping stays THERE (one place), and this table only names the classes.
|
|
22
|
+
* Usage errors get 64 rather than the next small integer so a future outcome code (5, 6, …) never
|
|
23
|
+
* collides with it.
|
|
24
|
+
*/
|
|
25
|
+
export declare const EXIT_CODES: {
|
|
26
|
+
readonly ok: 0;
|
|
27
|
+
readonly defects: 1;
|
|
28
|
+
readonly inconclusive: 2;
|
|
29
|
+
readonly hang: 3;
|
|
30
|
+
readonly intermittent: 4;
|
|
31
|
+
readonly usage: 64;
|
|
32
|
+
};
|
|
33
|
+
export type ExitClass = keyof typeof EXIT_CODES;
|
|
34
|
+
/** A canonical mission outcome's exit code (the domain table; re-exported so commands import one module). */
|
|
35
|
+
export declare function exitCodeForOutcome(outcome: MissionOutcome): number;
|
|
36
|
+
/** True when a refused command's error code is a usage/input error (exit 64). */
|
|
37
|
+
export declare function isUsageErrorCode(code: string): boolean;
|
|
38
|
+
/** A refused command's exit code: 64 for a usage/input error, else 2 (the command could not finish). */
|
|
39
|
+
export declare function exitCodeForError(code: string): number;
|
|
40
|
+
/** The exit code for a `{ok, error?}` envelope that carries no verdict of its own. */
|
|
41
|
+
export declare function exitCodeForEnvelope(envelope: {
|
|
42
|
+
readonly ok: boolean;
|
|
43
|
+
readonly error?: {
|
|
44
|
+
readonly code: string;
|
|
45
|
+
};
|
|
46
|
+
}): number;
|