@monster-orange/den 0.0.0-stage → 0.1.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/CHANGELOG.md +67 -0
- package/LICENSE +21 -0
- package/README.md +166 -2
- package/bin/den +61 -0
- package/docs/distributions.md +256 -0
- package/make/demo.mk +82 -0
- package/make/den.mk +80 -0
- package/make/journeys.mk +57 -0
- package/make/local_dev.mk +154 -0
- package/make/security.mk +59 -0
- package/make/test.mk +405 -0
- package/package.json +104 -4
- package/scripts/auth-configure.ts +415 -0
- package/scripts/heal-config.ts +92 -0
- package/scripts/jsonl-playwright-reporter.js +70 -0
- package/scripts/manifest-read.cjs +91 -0
- package/scripts/setup-1password.ts +570 -0
- package/scripts/setup-secrets.ts +149 -0
- package/scripts/view-results.js +156 -0
- package/service/install.sh +112 -0
- package/src/pillars/api/fixtures/index.ts +128 -0
- package/src/pillars/api/fixtures/openapi-validator.ts +111 -0
- package/src/pillars/api/global-setup.ts +103 -0
- package/src/pillars/api/playwright.config.ts +105 -0
- package/src/pillars/api/schemas/example-api.json +110 -0
- package/src/pillars/api/tests/health/health.spec.ts +19 -0
- package/src/pillars/api/tests/health/manifest.yml +6 -0
- package/src/pillars/browser/fixtures/index.ts +232 -0
- package/src/pillars/browser/fixtures/package.json +10 -0
- package/src/pillars/browser/global-setup.ts +140 -0
- package/src/pillars/browser/global-teardown.ts +48 -0
- package/src/pillars/browser/playwright.config.ts +212 -0
- package/src/pillars/browser/setup.ts +219 -0
- package/src/pillars/journeys/app-config.ts +237 -0
- package/src/pillars/journeys/discover.ts +160 -0
- package/src/pillars/journeys/hooks/deny-shell.cjs +44 -0
- package/src/pillars/journeys/observability/events.ts +288 -0
- package/src/pillars/journeys/observability/sdk-mapper.ts +306 -0
- package/src/pillars/journeys/report/friction.ts +304 -0
- package/src/pillars/journeys/report/junit.ts +105 -0
- package/src/pillars/journeys/report/render.ts +273 -0
- package/src/pillars/journeys/report/results.ts +323 -0
- package/src/pillars/journeys/run.ts +673 -0
- package/src/pillars/journeys/runner.ts +1025 -0
- package/src/pillars/journeys/sandbox.ts +406 -0
- package/src/pillars/journeys/spec/loader.ts +152 -0
- package/src/pillars/journeys/spec/schema.ts +208 -0
- package/src/pillars/journeys/teardown.ts +98 -0
- package/src/pillars/journeys/tools/browser-session.ts +219 -0
- package/src/pillars/journeys/tools/browser-tool.ts +914 -0
- package/src/pillars/journeys/tools/http-tool.ts +564 -0
- package/src/pillars/journeys/tools/ledger.ts +278 -0
- package/src/pillars/journeys/tools/snapshot-store.ts +117 -0
- package/src/pillars/journeys/verify/assertions.ts +502 -0
- package/src/pillars/journeys/verify/verdict.ts +71 -0
- package/src/pillars/perf/build-report.ts +36 -0
- package/src/pillars/perf/k6.config.js +112 -0
- package/src/pillars/perf/run.ts +345 -0
- package/src/pillars/perf/scenarios/load-profile.js +97 -0
- package/src/pillars/perf/staging.ts +73 -0
- package/src/pillars/security/discover.ts +108 -0
- package/src/pillars/security/findings.ts +151 -0
- package/src/pillars/security/plan.ts +355 -0
- package/src/pillars/security/run.ts +729 -0
- package/src/pillars/smoke/admin-probe.ts +68 -0
- package/src/pillars/smoke/base-url.ts +56 -0
- package/src/pillars/smoke/cleanup.ts +8 -0
- package/src/pillars/smoke/discover.ts +237 -0
- package/src/pillars/smoke/ensure-smoke-teardown.ts +40 -0
- package/src/pillars/smoke/fixture-manager.ts +217 -0
- package/src/pillars/smoke/fixtures.ts +468 -0
- package/src/pillars/smoke/global-setup-all.ts +262 -0
- package/src/pillars/smoke/global-setup-global.ts +262 -0
- package/src/pillars/smoke/global-setup.ts +273 -0
- package/src/pillars/smoke/global-teardown-all.ts +8 -0
- package/src/pillars/smoke/global-teardown-global.ts +8 -0
- package/src/pillars/smoke/global-teardown.ts +139 -0
- package/src/pillars/smoke/playwright-all.config.ts +147 -0
- package/src/pillars/smoke/playwright-global.config.ts +141 -0
- package/src/pillars/smoke/playwright.config.ts +162 -0
- package/src/pillars/smoke/setup-env.ts +132 -0
- package/src/pillars/smoke/setup-global.ts +126 -0
- package/src/pillars/smoke/setup.ts +115 -0
- package/src/pillars/smoke/smoke-repo.ts +16 -0
- package/src/pillars/smoke/staging.ts +49 -0
- package/src/pillars/suites/run.ts +147 -0
- package/src/scripts/configure-aws-profiles.ts +114 -0
- package/src/scripts/register-repos.ts +307 -0
- package/src/scripts/setup-default-workspace.ts +203 -0
- package/src/shared/applications.ts +138 -0
- package/src/shared/auth/api-token.ts +416 -0
- package/src/shared/auth/auth0-helper.ts +284 -0
- package/src/shared/auth/headless-login.ts +265 -0
- package/src/shared/auth/jwt-helper.ts +186 -0
- package/src/shared/auth/sudo-vault.ts +69 -0
- package/src/shared/auth/test-accounts.ts +98 -0
- package/src/shared/auth/token-injection.ts +184 -0
- package/src/shared/auth/token-providers/auth0.ts +80 -0
- package/src/shared/auth/token-providers/index.ts +182 -0
- package/src/shared/auth/token-refresh.ts +273 -0
- package/src/shared/banner.ts +15 -0
- package/src/shared/brand.ts +79 -0
- package/src/shared/cli-tabs.ts +131 -0
- package/src/shared/constants.ts +128 -0
- package/src/shared/den-config.ts +566 -0
- package/src/shared/dev-metrics/emit.ts +354 -0
- package/src/shared/edge/config.ts +229 -0
- package/src/shared/edge/render.ts +221 -0
- package/src/shared/edge/runtime.ts +268 -0
- package/src/shared/edge/types.ts +62 -0
- package/src/shared/engine.ts +67 -0
- package/src/shared/environment/aws-profiles.ts +49 -0
- package/src/shared/environment/env-selector.ts +161 -0
- package/src/shared/environment/playwright-env.ts +82 -0
- package/src/shared/environment-manager/catalog.ts +77 -0
- package/src/shared/environment-manager/clone-guard.ts +163 -0
- package/src/shared/environment-manager/dag.ts +286 -0
- package/src/shared/environment-manager/default-workspace.ts +182 -0
- package/src/shared/environment-manager/derivation/alias.ts +90 -0
- package/src/shared/environment-manager/derivation/cache.ts +97 -0
- package/src/shared/environment-manager/derivation/derive-graph.ts +421 -0
- package/src/shared/environment-manager/derivation/derived-up.ts +354 -0
- package/src/shared/environment-manager/derivation/load-alias.ts +11 -0
- package/src/shared/environment-manager/derivation/rules-compose.ts +42 -0
- package/src/shared/environment-manager/derivation/rules-events.ts +50 -0
- package/src/shared/environment-manager/derivation/rules-http.ts +247 -0
- package/src/shared/environment-manager/derivation/rules-infra.ts +64 -0
- package/src/shared/environment-manager/derivation/rules-readiness.ts +96 -0
- package/src/shared/environment-manager/derivation/scan.ts +160 -0
- package/src/shared/environment-manager/derivation/text.ts +40 -0
- package/src/shared/environment-manager/derivation/types.ts +69 -0
- package/src/shared/environment-manager/health.ts +589 -0
- package/src/shared/environment-manager/index.ts +6 -0
- package/src/shared/environment-manager/load-applications.ts +78 -0
- package/src/shared/environment-manager/log-tail.ts +212 -0
- package/src/shared/environment-manager/make-targets.ts +78 -0
- package/src/shared/environment-manager/opctl.ts +334 -0
- package/src/shared/environment-manager/readiness.ts +93 -0
- package/src/shared/environment-manager/register-local.ts +72 -0
- package/src/shared/environment-manager/secrets-check.ts +260 -0
- package/src/shared/environment-manager/service-env.ts +110 -0
- package/src/shared/environment-manager/service-runner.ts +1588 -0
- package/src/shared/environment-manager/up-plan.ts +302 -0
- package/src/shared/environment-manager/workspace-manager.ts +905 -0
- package/src/shared/environment-manager/workspaces.ts +860 -0
- package/src/shared/manifest/deps.ts +27 -0
- package/src/shared/manifest/migrate-manifest.ts +101 -0
- package/src/shared/manifest/read-manifest.ts +160 -0
- package/src/shared/manifest/schema.ts +299 -0
- package/src/shared/manifest/service-links.ts +93 -0
- package/src/shared/manifest/validate-manifest.ts +140 -0
- package/src/shared/manifest/workspace-manifests.ts +92 -0
- package/src/shared/open-url.ts +122 -0
- package/src/shared/org.ts +44 -0
- package/src/shared/paths.ts +178 -0
- package/src/shared/perf/optional-fields.ts +105 -0
- package/src/shared/perf/report-normalizer.ts +404 -0
- package/src/shared/perf/report-paths.ts +19 -0
- package/src/shared/perf/report-store.ts +110 -0
- package/src/shared/perf/report-types.ts +70 -0
- package/src/shared/perf/test-paths.ts +25 -0
- package/src/shared/process/log-rotation.ts +147 -0
- package/src/shared/process/spawn-streaming.ts +229 -0
- package/src/shared/product.ts +92 -0
- package/src/shared/profile.ts +141 -0
- package/src/shared/repo-kind.ts +32 -0
- package/src/shared/reporting/jsonl-reporter.ts +131 -0
- package/src/shared/reporting/slack-reporter.ts +340 -0
- package/src/shared/results/result-reader.ts +266 -0
- package/src/shared/results/result-writer.ts +168 -0
- package/src/shared/secrets/doppler.ts +126 -0
- package/src/shared/secrets/env.ts +48 -0
- package/src/shared/secrets/index.ts +197 -0
- package/src/shared/secrets/keys.ts +33 -0
- package/src/shared/secrets/onepassword.ts +75 -0
- package/src/shared/secrets/types.ts +52 -0
- package/src/shared/service-url.ts +119 -0
- package/src/shared/smoke/branch-resolver.ts +141 -0
- package/src/shared/smoke/git-remote.ts +70 -0
- package/src/shared/smoke/repo-cloner.ts +151 -0
- package/src/shared/stacks/config.ts +137 -0
- package/src/shared/stacks/manifest-commands.ts +88 -0
- package/src/shared/stacks/render.ts +253 -0
- package/src/shared/stacks/runtime.ts +334 -0
- package/src/shared/stacks/types.ts +53 -0
- package/src/shared/terminal/tabs.ts +212 -0
- package/src/shared/test-discovery/module-scanner.ts +569 -0
- package/src/shared/types/index.ts +678 -0
- package/src/shared/ui-marker.ts +19 -0
- package/src/ui/cli/applications-command.ts +116 -0
- package/src/ui/cli/config-command.ts +68 -0
- package/src/ui/cli/create-main.ts +9 -0
- package/src/ui/cli/create.ts +360 -0
- package/src/ui/cli/edge-command.ts +91 -0
- package/src/ui/cli/flag-parser.ts +246 -0
- package/src/ui/cli/graph-command.ts +524 -0
- package/src/ui/cli/health-display.ts +63 -0
- package/src/ui/cli/index.ts +3656 -0
- package/src/ui/cli/init.ts +855 -0
- package/src/ui/cli/invocation-target.ts +175 -0
- package/src/ui/cli/logs-command.ts +104 -0
- package/src/ui/cli/module-selection.ts +31 -0
- package/src/ui/cli/prompts.ts +767 -0
- package/src/ui/cli/results-viewer.ts +436 -0
- package/src/ui/cli/secrets-preflight.ts +91 -0
- package/src/ui/cli/stack-command.ts +144 -0
- package/src/ui/cli/stalled-setup-recovery.ts +129 -0
- package/src/ui/cli/test-runner.ts +1312 -0
- package/src/ui/cli/web-command.ts +1073 -0
- package/src/ui/server/changelog-parser.ts +94 -0
- package/src/ui/server/daemon-reaper.ts +129 -0
- package/src/ui/server/editor-manager.ts +301 -0
- package/src/ui/server/github-service.ts +223 -0
- package/src/ui/server/http-helpers.ts +98 -0
- package/src/ui/server/index.ts +3236 -0
- package/src/ui/server/log-history.ts +452 -0
- package/src/ui/server/perf-report.ts +42 -0
- package/src/ui/server/public/environments.html +494 -0
- package/src/ui/server/public/favicon.ico +0 -0
- package/src/ui/server/public/header.js +1371 -0
- package/src/ui/server/public/index.html +2595 -0
- package/src/ui/server/public/local-dev.html +7405 -0
- package/src/ui/server/public/logs.html +1489 -0
- package/src/ui/server/public/perf-report.js +359 -0
- package/src/ui/server/public/release.html +2111 -0
- package/src/ui/server/public/services.html +1098 -0
- package/src/ui/server/public/workspace-picker.js +69 -0
- package/src/ui/server/release-deploy-session.ts +246 -0
- package/src/ui/server/release-service.ts +1125 -0
- package/src/ui/server/sudo-store.ts +111 -0
- package/src/ui/server/workspace-routes.ts +2154 -0
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TypeScript types for Den
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface EnvironmentConfig {
|
|
6
|
+
name: string;
|
|
7
|
+
baseUrls: {
|
|
8
|
+
web: string;
|
|
9
|
+
api: string;
|
|
10
|
+
services: Record<string, string>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Which identity provider mints test tokens for this environment.
|
|
14
|
+
* Strategy, not code: see src/shared/auth/token-providers.
|
|
15
|
+
* Defaults to "auth0" when an `auth0` block is present, else "none".
|
|
16
|
+
*/
|
|
17
|
+
auth?: AuthConfig;
|
|
18
|
+
/** Auth0 settings — required only when auth.provider is "auth0". */
|
|
19
|
+
auth0?: {
|
|
20
|
+
domain: string;
|
|
21
|
+
clientId: string;
|
|
22
|
+
audience: string;
|
|
23
|
+
/**
|
|
24
|
+
* Optional dotenv file (relative to the den root, e.g. an app
|
|
25
|
+
* checkout's `.env.local`) whose AUTH0_CLIENT_SECRET is the local-dev
|
|
26
|
+
* fallback for the client secret.
|
|
27
|
+
*/
|
|
28
|
+
clientSecretEnvFile?: string;
|
|
29
|
+
};
|
|
30
|
+
timeouts: {
|
|
31
|
+
api: number;
|
|
32
|
+
pageLoad: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type AuthProviderName = "auth0" | "cognito" | "local-jwt" | "none";
|
|
37
|
+
|
|
38
|
+
export interface AuthConfig {
|
|
39
|
+
provider: AuthProviderName;
|
|
40
|
+
/**
|
|
41
|
+
* How the headless browser login reaches the IdP and recognises success.
|
|
42
|
+
* Defaults: start at "/" (the app redirects to its IdP) and treat any
|
|
43
|
+
* page back on the app origin as signed in.
|
|
44
|
+
*/
|
|
45
|
+
browser?: BrowserLoginConfig;
|
|
46
|
+
/** AWS Cognito user pool app client (USER_PASSWORD_AUTH flow). */
|
|
47
|
+
cognito?: {
|
|
48
|
+
region: string;
|
|
49
|
+
clientId: string;
|
|
50
|
+
/** Use the ID token instead of the access token as the bearer. */
|
|
51
|
+
useIdToken?: boolean;
|
|
52
|
+
};
|
|
53
|
+
/** Self-signed HS256 JWT for local stacks that verify a shared secret. */
|
|
54
|
+
localJwt?: {
|
|
55
|
+
/** Env var / secrets flat key holding the signing secret. */
|
|
56
|
+
secretKey: string;
|
|
57
|
+
issuer?: string;
|
|
58
|
+
audience?: string;
|
|
59
|
+
ttlSeconds?: number;
|
|
60
|
+
/** Extra claims merged into every token. */
|
|
61
|
+
claims?: Record<string, unknown>;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface BrowserLoginConfig {
|
|
66
|
+
/** App path that starts the login redirect (e.g. "/auth/login"). Default "/". */
|
|
67
|
+
loginPath?: string;
|
|
68
|
+
/**
|
|
69
|
+
* App path a signed-in session can open (session checks navigate here and
|
|
70
|
+
* expect to stay on it). Default "/".
|
|
71
|
+
*/
|
|
72
|
+
signedInPath?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface Credentials {
|
|
76
|
+
regular: {
|
|
77
|
+
username: string;
|
|
78
|
+
password: string;
|
|
79
|
+
auth0ClientId?: string;
|
|
80
|
+
};
|
|
81
|
+
elevated?: {
|
|
82
|
+
username: string;
|
|
83
|
+
password: string;
|
|
84
|
+
};
|
|
85
|
+
lastUpdated: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface TestResult {
|
|
89
|
+
timestamp: string;
|
|
90
|
+
pillar: Pillar;
|
|
91
|
+
environment: string;
|
|
92
|
+
test: string;
|
|
93
|
+
status: "passed" | "failed" | "skipped";
|
|
94
|
+
duration: number;
|
|
95
|
+
user: string;
|
|
96
|
+
error?: string;
|
|
97
|
+
screenshot?: string;
|
|
98
|
+
trace?: string;
|
|
99
|
+
metadata?: Record<string, unknown>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface SlackConfig {
|
|
103
|
+
webhookUrl: string;
|
|
104
|
+
enabled: boolean;
|
|
105
|
+
notifyOn: {
|
|
106
|
+
testComplete: boolean;
|
|
107
|
+
testFailure: boolean;
|
|
108
|
+
thresholdExceeded: boolean;
|
|
109
|
+
};
|
|
110
|
+
thresholds: {
|
|
111
|
+
failurePercentage: number;
|
|
112
|
+
};
|
|
113
|
+
channel: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface TestSummary {
|
|
117
|
+
pillar: string;
|
|
118
|
+
environment: string;
|
|
119
|
+
total: number;
|
|
120
|
+
passed: number;
|
|
121
|
+
failed: number;
|
|
122
|
+
skipped: number;
|
|
123
|
+
duration: number;
|
|
124
|
+
passRate: number;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface FlakyTest {
|
|
128
|
+
test: string;
|
|
129
|
+
runs: number;
|
|
130
|
+
failures: number;
|
|
131
|
+
flakyRate: number;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface TrendData {
|
|
135
|
+
date: string;
|
|
136
|
+
passRate: number;
|
|
137
|
+
avgDuration: number;
|
|
138
|
+
totalTests: number;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type Environment =
|
|
142
|
+
| "local"
|
|
143
|
+
| "dev"
|
|
144
|
+
| "sandbox"
|
|
145
|
+
| "staging"
|
|
146
|
+
| "beta"
|
|
147
|
+
| "prod"
|
|
148
|
+
| "production";
|
|
149
|
+
export type Pillar =
|
|
150
|
+
| "synthetic"
|
|
151
|
+
| "integration"
|
|
152
|
+
| "performance"
|
|
153
|
+
| "smoke"
|
|
154
|
+
| "journeys"
|
|
155
|
+
| "security"
|
|
156
|
+
| "suites";
|
|
157
|
+
|
|
158
|
+
// ── Schema validation types ───────────────────────────────────────────────────
|
|
159
|
+
|
|
160
|
+
export interface ValidationError {
|
|
161
|
+
/** Dot-separated path to the offending field, e.g. "services.api.health.local". Empty string for top-level parse errors. */
|
|
162
|
+
path: string;
|
|
163
|
+
/** Human-readable description of the problem. */
|
|
164
|
+
message: string;
|
|
165
|
+
/** Optional remediation hint, e.g. "Did you mean X?" */
|
|
166
|
+
suggestion?: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface ValidationResult {
|
|
170
|
+
/** True when the manifest passes all checks with no errors. Warnings do not affect validity. */
|
|
171
|
+
valid: boolean;
|
|
172
|
+
/** Detected schema version (defaults to 1 when no version field is present). */
|
|
173
|
+
version: number;
|
|
174
|
+
/** Fatal validation errors — must be fixed before the manifest can be used. */
|
|
175
|
+
errors: ValidationError[];
|
|
176
|
+
/** Non-fatal warnings — e.g. unknown future version, deprecated patterns. */
|
|
177
|
+
warnings: ValidationError[];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ── .den.json manifest types ─────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
export type LogSource =
|
|
183
|
+
| { type: "process"; distinct?: boolean }
|
|
184
|
+
| { type: "shell"; cmd: string; distinct?: boolean }
|
|
185
|
+
| {
|
|
186
|
+
type: "cloudwatch";
|
|
187
|
+
logGroup: string;
|
|
188
|
+
logStream?: string;
|
|
189
|
+
region?: string;
|
|
190
|
+
/**
|
|
191
|
+
* Marks a SUBSYSTEM's log as its own listed source in the /logs view
|
|
192
|
+
* (e.g. shop/db runs shop's own postgres, not infra-stack's shared
|
|
193
|
+
* one). Without it, only a system's primary service log is listed.
|
|
194
|
+
*/
|
|
195
|
+
distinct?: boolean;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Health check config for a service in a given environment.
|
|
200
|
+
*
|
|
201
|
+
* HTTP (default):
|
|
202
|
+
* url: "https://api.example.com/healthz"
|
|
203
|
+
* -- or explicitly --
|
|
204
|
+
* type: http
|
|
205
|
+
* url: "https://api.example.com/healthz"
|
|
206
|
+
*
|
|
207
|
+
* Shell command (for services without an HTTP endpoint, e.g. Postgres):
|
|
208
|
+
* type: shell
|
|
209
|
+
* cmd: "docker exec $(docker ps --filter ancestor=postgres:16 --format '{{.ID}}' | head -1) pg_isready -U postgres"
|
|
210
|
+
* label: "postgres" # optional — shown in UI instead of cmd
|
|
211
|
+
*/
|
|
212
|
+
export type ServiceHealthConfig =
|
|
213
|
+
| { type?: "http"; url: string; label?: string }
|
|
214
|
+
| { type: "shell"; cmd: string; label?: string };
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* A command can be a plain shell string (detached by default) or an object
|
|
218
|
+
* that explicitly controls behaviour:
|
|
219
|
+
*
|
|
220
|
+
* up: make up # string — detached: true (default)
|
|
221
|
+
* seed:
|
|
222
|
+
* cmd: make db-seed
|
|
223
|
+
* detachable: false # wait for exit, stream output until done
|
|
224
|
+
* setup:
|
|
225
|
+
* cmd: make auth-login
|
|
226
|
+
* detachable: false
|
|
227
|
+
* interactive: true # hand full stdin/stdout/stderr to the user's TTY
|
|
228
|
+
* # required when the command prompts for input (HITL)
|
|
229
|
+
*/
|
|
230
|
+
export type CommandDef =
|
|
231
|
+
| string
|
|
232
|
+
| { cmd: string; detachable?: boolean; interactive?: boolean };
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* A `depends_on` entry. String form for the common case; object form to opt
|
|
236
|
+
* into blocking startup on the dep's health check (`wait: true`).
|
|
237
|
+
*
|
|
238
|
+
* depends_on:
|
|
239
|
+
* - tasks-runner # string — fire-and-forget (default)
|
|
240
|
+
* - { service: shop/db, wait: true } # block this service's start until shop/db is healthy
|
|
241
|
+
*/
|
|
242
|
+
export type DependsOnEntry = string | { service: string; wait?: boolean };
|
|
243
|
+
|
|
244
|
+
export interface ServiceManagementConfig {
|
|
245
|
+
/** env → command-name → command definition. Omit env key if not supported. */
|
|
246
|
+
commands?: Partial<Record<Environment, Record<string, CommandDef>>>;
|
|
247
|
+
/** env → log source. Omit env key if not supported. */
|
|
248
|
+
logs?: Partial<Record<Environment, LogSource>>;
|
|
249
|
+
/** env → health check URL. Omit env key if not supported. */
|
|
250
|
+
health?: Partial<Record<Environment, ServiceHealthConfig>>;
|
|
251
|
+
/**
|
|
252
|
+
* env → where the app opens in a browser (the UI's open-in-new-tab link).
|
|
253
|
+
* Unset: the local edge route, else the origin of the env's HTTP health URL.
|
|
254
|
+
*/
|
|
255
|
+
urls?: Partial<Record<Environment, string>>;
|
|
256
|
+
/** Extra named links per env (docs, admin, API explorer…). */
|
|
257
|
+
links?: ServiceLink[];
|
|
258
|
+
/**
|
|
259
|
+
* Other managed services this service depends on.
|
|
260
|
+
* Use service addresses: "tasks-runner", "shop/api", etc.
|
|
261
|
+
* Den will start dependencies before this service.
|
|
262
|
+
*
|
|
263
|
+
* Default is fire-and-forget (5-second detach). To block on a dep's health
|
|
264
|
+
* check before starting this service, use the object form: { service, wait: true }.
|
|
265
|
+
*/
|
|
266
|
+
depends_on?: DependsOnEntry[];
|
|
267
|
+
/** OWASP ZAP options: `openapi` per env turns on the API scan; `skip` leaves it out. */
|
|
268
|
+
security?: { openapi?: Partial<Record<Environment, string>>; skip?: boolean };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export interface ServiceLink {
|
|
272
|
+
label: string;
|
|
273
|
+
urls: Partial<Record<Environment, string>>;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Where the deployed commit for one environment is read from. The first that
|
|
278
|
+
* answers wins: `version` (JSON endpoint; `field` holds the SHA, default
|
|
279
|
+
* "build"), then `deployment` (a GitHub environment), then the newest
|
|
280
|
+
* successful run of the repo's release `workflow` on main.
|
|
281
|
+
*/
|
|
282
|
+
export interface ReleaseSourceConfig {
|
|
283
|
+
version?: string;
|
|
284
|
+
field?: string;
|
|
285
|
+
deployment?: string;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export interface ReleaseManifestConfig {
|
|
289
|
+
workflow?: string;
|
|
290
|
+
environments?: Partial<Record<Environment, ReleaseSourceConfig>>;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** A repo-owned test suite Den can run from the checkout. */
|
|
294
|
+
export interface TestSuiteConfig {
|
|
295
|
+
cmd: string;
|
|
296
|
+
cwd?: string;
|
|
297
|
+
label?: string;
|
|
298
|
+
/** Den environments it may run against (default: local only). */
|
|
299
|
+
environments?: Environment[];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface SmokeStorageFixtureConfig {
|
|
303
|
+
endpoint?: string;
|
|
304
|
+
endpointFromEnv?: string;
|
|
305
|
+
apiEndpoint?: string;
|
|
306
|
+
apiEndpointFromEnv?: string;
|
|
307
|
+
bucket?: string;
|
|
308
|
+
bucketFromEnv?: string;
|
|
309
|
+
accessKey?: string;
|
|
310
|
+
accessKeyFromEnv?: string;
|
|
311
|
+
secretKey?: string;
|
|
312
|
+
secretKeyFromEnv?: string;
|
|
313
|
+
cleanupContext?: SmokeCleanupContextConfig;
|
|
314
|
+
setup?: CommandDef;
|
|
315
|
+
teardown?: CommandDef;
|
|
316
|
+
/**
|
|
317
|
+
* If set, Den GETs `{baseUrl}{adminProbePath}` before tests when this storage fixture is active.
|
|
318
|
+
* Use a lightweight admin route that shares the same guard as teardown (e.g. files-api
|
|
319
|
+
* `GET /api/v1/admin/ingest-queue/status`). Omit when teardown does not call admin HTTP APIs.
|
|
320
|
+
*/
|
|
321
|
+
adminProbePath?: string;
|
|
322
|
+
/**
|
|
323
|
+
* Service-authored remediation text appended to the error when `adminProbePath` returns 403.
|
|
324
|
+
* Den does not interpret this string — it is passed verbatim to the operator. Example:
|
|
325
|
+
* "Set ENABLE_ADMIN_ENDPOINTS in stack.yml for this env, run make infra-sync, and redeploy."
|
|
326
|
+
* Omit to fall back to the raw 403 response body in the error message.
|
|
327
|
+
*/
|
|
328
|
+
adminProbe403Hint?: string;
|
|
329
|
+
/**
|
|
330
|
+
* Extra env vars merged into the fixture process env for `setup` / `teardown`
|
|
331
|
+
* (e.g. `PG_*` for repo-owned cleanup scripts). Values should be strings in
|
|
332
|
+
* `.den.yml`; YAML numbers are coerced to strings.
|
|
333
|
+
*/
|
|
334
|
+
teardownEnv?: Record<string, string | number | boolean>;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export interface SmokeObjectStoreCleanupTargetConfig {
|
|
338
|
+
endpoint?: string;
|
|
339
|
+
endpointFromEnv?: string;
|
|
340
|
+
bucket?: string;
|
|
341
|
+
bucketFromEnv?: string;
|
|
342
|
+
accessKey?: string;
|
|
343
|
+
accessKeyFromEnv?: string;
|
|
344
|
+
secretKey?: string;
|
|
345
|
+
secretKeyFromEnv?: string;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export interface SmokeCleanupContextConfig {
|
|
349
|
+
objectStores?: Record<string, SmokeObjectStoreCleanupTargetConfig>;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Teardown-only smoke fixture: runs a repo-owned sweep command after the
|
|
354
|
+
* suite, with no object-storage payload. Unlike the storage fixture, it is
|
|
355
|
+
* acquired AFTER JWT warming, so the teardown env includes SMOKE_*_TOKEN —
|
|
356
|
+
* required by repos (e.g. shop) whose sweep goes through JWT-authed APIs.
|
|
357
|
+
*/
|
|
358
|
+
export interface SmokeCleanupFixtureConfig {
|
|
359
|
+
setup?: CommandDef;
|
|
360
|
+
teardown: CommandDef;
|
|
361
|
+
/** Same semantics as the storage fixture's adminProbePath. */
|
|
362
|
+
adminProbePath?: string;
|
|
363
|
+
/** Same semantics as the storage fixture's adminProbe403Hint. */
|
|
364
|
+
adminProbe403Hint?: string;
|
|
365
|
+
/**
|
|
366
|
+
* Extra env vars merged into the fixture process env for `setup` /
|
|
367
|
+
* `teardown` (e.g. `ENVIRONMENT` so the script can refuse production).
|
|
368
|
+
*/
|
|
369
|
+
teardownEnv?: Record<string, string | number | boolean>;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export interface SmokeFixturesConfig {
|
|
373
|
+
storage?: Partial<Record<Environment, SmokeStorageFixtureConfig>>;
|
|
374
|
+
cleanup?: Partial<Record<Environment, SmokeCleanupFixtureConfig>>;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** Smoke test config for a single service (lives under `smoke.<name>` in the manifest). */
|
|
378
|
+
export interface SmokeServiceConfig {
|
|
379
|
+
testDir: string;
|
|
380
|
+
testMatch: string;
|
|
381
|
+
baseUrlKey: "api" | "web";
|
|
382
|
+
auth: ("admin" | "user" | "beta")[];
|
|
383
|
+
fixtures?: SmokeFixturesConfig;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Declarative launch-time option for a perf test, surfaced as a form control in
|
|
388
|
+
* the web UI and resolved into an env var on THIS test's k6 process. Tests
|
|
389
|
+
* declare these in their co-located `manifest.yml` (Den-local) or under
|
|
390
|
+
* `performance.<name>.optionalFields` in `.den.yml` (repo-owned).
|
|
391
|
+
*/
|
|
392
|
+
export type PerfOptionalFieldType = "boolean" | "select" | "string" | "number";
|
|
393
|
+
|
|
394
|
+
export interface PerfOptionalField {
|
|
395
|
+
/** Field id, unique within a test. Used as the values map key + localStorage key. */
|
|
396
|
+
name: string;
|
|
397
|
+
/** Form label shown in the UI. */
|
|
398
|
+
label: string;
|
|
399
|
+
/** Control type → which form widget renders + how the value is resolved. */
|
|
400
|
+
type: PerfOptionalFieldType;
|
|
401
|
+
/** Env var set on THIS test's k6 process when the field resolves to a value. */
|
|
402
|
+
env: string;
|
|
403
|
+
/** Seed value when the user has not chosen one. */
|
|
404
|
+
default?: string | number | boolean;
|
|
405
|
+
/** Tooltip / help text. */
|
|
406
|
+
description?: string;
|
|
407
|
+
/** Allowed values for `type: select`. */
|
|
408
|
+
options?: Array<{ value: string; label: string }>;
|
|
409
|
+
/** For `type: boolean`: env value emitted when true (default "1"); env omitted when false. */
|
|
410
|
+
emit?: string;
|
|
411
|
+
/** Greys out the control (and skips the env at runtime) when the referenced field equals the given value. */
|
|
412
|
+
disabledWhen?: { field: string; equals: string | number | boolean };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Performance test config for a single module (lives under `performance.<name>` in the manifest). */
|
|
416
|
+
export interface PerformanceServiceConfig {
|
|
417
|
+
/** When false, Den skips this module (no k6 run, no storage fixture acquire). Default: enabled. */
|
|
418
|
+
enabled?: boolean;
|
|
419
|
+
testDir: string;
|
|
420
|
+
testMatch: string;
|
|
421
|
+
baseUrlKey: "api" | "web";
|
|
422
|
+
service: string;
|
|
423
|
+
tags?: string[];
|
|
424
|
+
fixtures?: SmokeFixturesConfig;
|
|
425
|
+
/** Declarative launch-time options for repo-owned perf tests (via .den.yml). */
|
|
426
|
+
optionalFields?: PerfOptionalField[];
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Alias for {@link PerformanceServiceConfig}. The module scanner historically
|
|
431
|
+
* imports this name; kept as an alias so both spellings resolve to one shape.
|
|
432
|
+
*/
|
|
433
|
+
export type PerformanceModuleConfig = PerformanceServiceConfig;
|
|
434
|
+
|
|
435
|
+
/** Synthetics config (lives under `synthetics` in the manifest). */
|
|
436
|
+
export interface SyntheticsConfig {
|
|
437
|
+
testDir: string;
|
|
438
|
+
testMatch: string;
|
|
439
|
+
baseUrlKey: "api" | "web";
|
|
440
|
+
auth: ("admin" | "user" | "beta")[];
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Journeys config (lives under top-level `journeys` in the manifest).
|
|
445
|
+
* Deliberately thinner than SyntheticsConfig: no baseUrlKey (the journeys
|
|
446
|
+
* runner resolves both web and api base URLs from env config) and no auth
|
|
447
|
+
* array (each journey spec's persona.role declares its own role).
|
|
448
|
+
*/
|
|
449
|
+
export interface JourneysConfig {
|
|
450
|
+
testDir: string;
|
|
451
|
+
testMatch: string;
|
|
452
|
+
/**
|
|
453
|
+
* The app under test (resources, session token, web-origin API feed).
|
|
454
|
+
* Raw here; parsed and validated by the journeys pillar
|
|
455
|
+
* (src/pillars/journeys/app-config.ts).
|
|
456
|
+
*/
|
|
457
|
+
app?: unknown;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Optional GitHub metadata in .den.yml.
|
|
462
|
+
* Owner/repo are auto-derived from git remote, so this section is only
|
|
463
|
+
* needed when the den environment name differs from the GitHub environment
|
|
464
|
+
* name (rare — by convention they match).
|
|
465
|
+
*/
|
|
466
|
+
export interface GitHubManifestConfig {
|
|
467
|
+
/**
|
|
468
|
+
* Map den environment names → GitHub environment names.
|
|
469
|
+
* Only needed for overrides; unspecified envs default to the den name.
|
|
470
|
+
* e.g. production: prod
|
|
471
|
+
*/
|
|
472
|
+
environments?: Partial<Record<Environment, string>>;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** ZAP scan modes, least to most intrusive: passive-only, API active, full active. */
|
|
476
|
+
export type SecurityMode = "baseline" | "api" | "full";
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Security (ZAP) scan target for a single service (lives under
|
|
480
|
+
* `security.<name>` in the manifest). Either `baseUrlKey` or `hosts` must be
|
|
481
|
+
* present; explicit `hosts` win when both are given for an environment.
|
|
482
|
+
*/
|
|
483
|
+
export interface SecurityServiceConfig {
|
|
484
|
+
/** Resolve the target from the den environment config (baseUrls.api / baseUrls.web). */
|
|
485
|
+
baseUrlKey?: "api" | "web";
|
|
486
|
+
/** Explicit env → target base URLs; wins over baseUrlKey for that env. */
|
|
487
|
+
hosts?: Partial<Record<Environment, string[]>>;
|
|
488
|
+
/** Repo-relative OpenAPI spec path, or a URL template (`{baseUrl}` expands). */
|
|
489
|
+
openapi?: string;
|
|
490
|
+
/** Roles to authenticate as; empty/omitted = unauthenticated scan. */
|
|
491
|
+
auth?: ("admin" | "user" | "beta")[];
|
|
492
|
+
/** Regexes (no whitespace) over URLs ZAP must not touch. */
|
|
493
|
+
exclude?: string[];
|
|
494
|
+
/** Allowed modes per env; capped by the pillar's per-env ceiling regardless. */
|
|
495
|
+
modes?: Partial<Record<Environment, SecurityMode[]>>;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/** Parsed .den.yml/.den.json manifest — top-level shape. */
|
|
499
|
+
export interface RawManifest {
|
|
500
|
+
name: string;
|
|
501
|
+
/**
|
|
502
|
+
* Front-door service for cross-repo depends_on.
|
|
503
|
+
* When another repo lists this multi-service repo by bare name in its
|
|
504
|
+
* depends_on, den resolves it to "repoName/entrypoint".
|
|
505
|
+
* Single-service repos need no declaration — bare name is always correct.
|
|
506
|
+
*/
|
|
507
|
+
entrypoint?: string;
|
|
508
|
+
smoke?: Record<string, SmokeServiceConfig>;
|
|
509
|
+
performance?: Record<string, PerformanceServiceConfig>;
|
|
510
|
+
synthetics?: SyntheticsConfig;
|
|
511
|
+
journeys?: JourneysConfig;
|
|
512
|
+
security?: Record<string, SecurityServiceConfig>;
|
|
513
|
+
services?: Record<string, ServiceManagementConfig>;
|
|
514
|
+
github?: GitHubManifestConfig;
|
|
515
|
+
release?: ReleaseManifestConfig;
|
|
516
|
+
tests?: Record<string, TestSuiteConfig>;
|
|
517
|
+
/** The application (config/den.yml `applications:`) this repo belongs to. */
|
|
518
|
+
application?: string;
|
|
519
|
+
/**
|
|
520
|
+
* What the repo is. `service` (the default) runs on its own and has a
|
|
521
|
+
* status. `module` is code a host service loads or invokes (a bolt-on);
|
|
522
|
+
* `library` is code other repos import. Neither has a runtime of its own:
|
|
523
|
+
* den never starts or health-checks them and shows what they
|
|
524
|
+
* contribute to instead.
|
|
525
|
+
*/
|
|
526
|
+
kind?: RepoKind;
|
|
527
|
+
/** For a module or library: the repos it contributes to. */
|
|
528
|
+
contributes_to?: string[];
|
|
529
|
+
/**
|
|
530
|
+
* The repo is a Docker Compose project: den runs it with no host ports
|
|
531
|
+
* behind the edge, and supplies up/down/restart/logs/health unless the
|
|
532
|
+
* entrypoint service declares its own.
|
|
533
|
+
*/
|
|
534
|
+
compose?: ManifestComposeConfig;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export type RepoKind = "service" | "module" | "library";
|
|
538
|
+
|
|
539
|
+
export interface ManifestComposeConfig {
|
|
540
|
+
/** Stack name, used in hostnames; defaults to the manifest name. */
|
|
541
|
+
name?: string;
|
|
542
|
+
dir?: string;
|
|
543
|
+
files?: string[];
|
|
544
|
+
routes?: Record<string, string>;
|
|
545
|
+
generate?: string[];
|
|
546
|
+
/** Other stacks (by stack or repo name) this one calls. */
|
|
547
|
+
uses?: string[];
|
|
548
|
+
env?: Record<string, string | number | boolean>;
|
|
549
|
+
profiles?: string[];
|
|
550
|
+
/** service → replacement healthcheck `test` (written to den's override, not the repo). */
|
|
551
|
+
healthchecks?: Record<string, string[]>;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
export interface MigrationResult {
|
|
555
|
+
/** The migrated manifest, ready to write back to disk. */
|
|
556
|
+
manifest: RawManifest;
|
|
557
|
+
/** Schema version of the input manifest (1 when no version field was present). */
|
|
558
|
+
fromVersion: number;
|
|
559
|
+
/** Schema version of the output manifest. */
|
|
560
|
+
toVersion: number;
|
|
561
|
+
/** Human-readable descriptions of each transformation applied. Empty when nothing changed. */
|
|
562
|
+
changes: string[];
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** A repo discovered under .den/<name>/ with its parsed manifest. */
|
|
566
|
+
export interface DiscoveredRepo {
|
|
567
|
+
repoName: string;
|
|
568
|
+
repoPath: string;
|
|
569
|
+
manifest: RawManifest;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// ── Service catalog & workspace types ────────────────────────────────────────
|
|
573
|
+
|
|
574
|
+
export interface ServiceCatalogEntry {
|
|
575
|
+
/** Full GitHub slug: "Globex-Corp/repo-name" — used when cloning managed repos */
|
|
576
|
+
gh: string;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/** Keyed by GH repo name (e.g. "shop", "tasks-runner") */
|
|
580
|
+
export type ServiceCatalog = Record<string, ServiceCatalogEntry>;
|
|
581
|
+
|
|
582
|
+
export interface WorkspaceServiceEntry {
|
|
583
|
+
/**
|
|
584
|
+
* Auto-start toggle: absent (or true) = the system starts with workspace-wide
|
|
585
|
+
* ups (web master ▶ Up, `den up` closure walks). false = skipped by the
|
|
586
|
+
* STARTING half of workspace-wide ops (up/restart) — but workspace down still
|
|
587
|
+
* stops it, and explicit targeting (card ⋮ up, `den up <repo>`) always
|
|
588
|
+
* wins. Toggled per system from the web ⋮ menu.
|
|
589
|
+
*/
|
|
590
|
+
autostart?: boolean;
|
|
591
|
+
/**
|
|
592
|
+
* How this service is managed in this workspace.
|
|
593
|
+
* dev-managed — developer's own checkout; den never modifies it
|
|
594
|
+
* managed — den clones and tracks a branch in .den-services/<repo>/
|
|
595
|
+
*/
|
|
596
|
+
mode: "dev-managed" | "managed";
|
|
597
|
+
/**
|
|
598
|
+
* For linked repos: absolute path to the local checkout in this workspace.
|
|
599
|
+
*/
|
|
600
|
+
path?: string;
|
|
601
|
+
/**
|
|
602
|
+
* For managed repos: branch to track. Defaults to "main".
|
|
603
|
+
*/
|
|
604
|
+
branch?: string;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
export interface WorkspaceConfig {
|
|
608
|
+
/**
|
|
609
|
+
* Service entries keyed by service address.
|
|
610
|
+
* Single-service repos: "tasks-runner"
|
|
611
|
+
* Mono-repo subsystems: "shop/api", "shop/web"
|
|
612
|
+
*/
|
|
613
|
+
services: Record<string, WorkspaceServiceEntry>;
|
|
614
|
+
/**
|
|
615
|
+
* Feature workspace: path to the directory containing managed clones.
|
|
616
|
+
* Relative to den root. Only managed repos are cloned here —
|
|
617
|
+
* linked repos always stay in their own location on disk.
|
|
618
|
+
*/
|
|
619
|
+
directory?: string;
|
|
620
|
+
/**
|
|
621
|
+
* Managed repos to clone into the workspace directory, keyed by
|
|
622
|
+
* GH repo name. Only valid when directory is set.
|
|
623
|
+
*/
|
|
624
|
+
repos?: Record<string, string>; // repoName → branch
|
|
625
|
+
/**
|
|
626
|
+
* Optional editor override for this workspace. When set, opening the workspace
|
|
627
|
+
* directory uses this editor instead of the user's global default.
|
|
628
|
+
* Per-language overrides (from stack.yml) still take precedence at repo level.
|
|
629
|
+
*/
|
|
630
|
+
editor?: string;
|
|
631
|
+
/**
|
|
632
|
+
* Blueprint repo list (`defaults.workspace.repos`) as last applied to this
|
|
633
|
+
* workspace — `default` workspace only. Top-up converges on blueprint
|
|
634
|
+
* DELTAS against this list, so a standard repo the user removed stays
|
|
635
|
+
* removed instead of resurrecting on the next command; only repos that
|
|
636
|
+
* newly JOIN the blueprint are added.
|
|
637
|
+
*/
|
|
638
|
+
seeded_repos?: string[];
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
export interface WorkspacesFile {
|
|
642
|
+
/**
|
|
643
|
+
* Workspaces currently active (may be more than one). Services may run
|
|
644
|
+
* under any active workspace; see daemon ownership / conflict rules.
|
|
645
|
+
*/
|
|
646
|
+
active: string[];
|
|
647
|
+
/**
|
|
648
|
+
* UI/CLI default target workspace. Must be a member of `active` when set.
|
|
649
|
+
* Resolved via DEN_WORKSPACE_OVERRIDE → focus → active[0].
|
|
650
|
+
*/
|
|
651
|
+
focus?: string;
|
|
652
|
+
workspaces: Record<string, WorkspaceConfig>;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/** Runtime-resolved service info — not persisted */
|
|
656
|
+
export interface ResolvedService {
|
|
657
|
+
/** Service address as used in workspace config: "shop/api" or "tasks-runner" */
|
|
658
|
+
address: string;
|
|
659
|
+
/** GH repo name (catalog key): "shop" or "tasks-runner" */
|
|
660
|
+
repoName: string;
|
|
661
|
+
/** Subsystem key from .den.yml services block: "api", "web", or same as repoName */
|
|
662
|
+
subsystem: string;
|
|
663
|
+
/** Absolute path to the repo root for this workspace context */
|
|
664
|
+
repoPath: string;
|
|
665
|
+
/** Branch currently targeted (null for linked repos — den doesn't control their branch) */
|
|
666
|
+
branch: string | null;
|
|
667
|
+
mode: "dev-managed" | "managed";
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
export interface TokenSet {
|
|
671
|
+
access_token: string;
|
|
672
|
+
refresh_token?: string;
|
|
673
|
+
id_token?: string;
|
|
674
|
+
expires_in?: number;
|
|
675
|
+
token_type?: string;
|
|
676
|
+
scope?: string;
|
|
677
|
+
[key: string]: unknown;
|
|
678
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixed marker the web server adds to every HTML page it serves, so the CLI
|
|
3
|
+
* can tell its own UI is up without matching any product or brand text
|
|
4
|
+
* (a brand may differ from the product title, even in case).
|
|
5
|
+
*/
|
|
6
|
+
export const DEN_UI_MARKER = '<meta name="den-ui" content="1">';
|
|
7
|
+
|
|
8
|
+
/** Insert the marker right after <head> (or at the start when there is none). */
|
|
9
|
+
export function addDenUiMarker(html: string): string {
|
|
10
|
+
if (html.includes(DEN_UI_MARKER)) return html;
|
|
11
|
+
const head = /<head(\s[^>]*)?>/i.exec(html);
|
|
12
|
+
if (!head) return DEN_UI_MARKER + html;
|
|
13
|
+
const at = head.index + head[0].length;
|
|
14
|
+
return html.slice(0, at) + DEN_UI_MARKER + html.slice(at);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function hasDenUiMarker(html: string): boolean {
|
|
18
|
+
return html.includes(DEN_UI_MARKER);
|
|
19
|
+
}
|