@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
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Den are documented here. Each release lists the
|
|
4
|
+
config and manifest changes a distribution must make to move to it under
|
|
5
|
+
**Migrations**.
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-11-04
|
|
8
|
+
|
|
9
|
+
The first Den release: one engine for local development, tests and releases
|
|
10
|
+
across an organisation's repos, shipped as `@monster-orange/den` and used
|
|
11
|
+
through thin distributions that pin an exact version.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`den create <name> [dir]`** (also `npx @monster-orange/den create`)
|
|
16
|
+
scaffolds a distribution: `den.yml`, a `package.json` pinning this exact
|
|
17
|
+
Den, a `bin/<cli>` shim, a Makefile including `make/den.mk`, an org config
|
|
18
|
+
with a brand, and empty `manifests/` and `tests/pillars/`.
|
|
19
|
+
`examples/distribution/` is its output for `acme`. See
|
|
20
|
+
`docs/distributions.md`.
|
|
21
|
+
- **Den runs as an installed package.** Den's own files resolve from the
|
|
22
|
+
engine root (`node_modules/@monster-orange/den`), the distribution's from
|
|
23
|
+
its root; scripts run with Den's tsx, never through `npx` or the current
|
|
24
|
+
directory. The package ships `src/` and runs it with tsx (a dependency
|
|
25
|
+
now); CI proves it with `scripts/dist-smoke.sh`.
|
|
26
|
+
- **Org > Application > Repo > Services.** Declared applications (config
|
|
27
|
+
`applications:` or a manifest's `application:`) group repos; the Local Dev
|
|
28
|
+
graph boxes each one inside its org's frame, next to the connected groups of
|
|
29
|
+
repos that are their own application.
|
|
30
|
+
- **Security scans keep a latest record.** Every run writes
|
|
31
|
+
`reports/security/<env>/latest-<mode>.json`; the Tests page shows it, with
|
|
32
|
+
findings marked new since the previous run.
|
|
33
|
+
- **Repo suites** (`tests:` in a manifest) run from the Tests page and CLI.
|
|
34
|
+
- **Edge opt-ins**: a project CA and route certificates are opt-in; with none
|
|
35
|
+
set, the rendered edge is unchanged.
|
|
36
|
+
|
|
37
|
+
- **launchd service from a distribution.** `service/install.sh` ships in the
|
|
38
|
+
package and runs from `DEN_ROOT`; `DEN_SERVICE_LABEL` and `DEN_SERVICE_LOGS`
|
|
39
|
+
keep an existing label and log folder; `print` shows the plist.
|
|
40
|
+
|
|
41
|
+
### Migrations
|
|
42
|
+
|
|
43
|
+
From the engine this release was generalised from:
|
|
44
|
+
|
|
45
|
+
- Run Den from the package: a `bin/<cli>` shim that sets `DEN_ROOT` to the
|
|
46
|
+
distribution and execs `node_modules/@monster-orange/den/bin/den`, and a
|
|
47
|
+
Makefile that does `include node_modules/@monster-orange/den/make/den.mk`
|
|
48
|
+
(`den create` writes both; `docs/distributions.md` shows them).
|
|
49
|
+
- Add `den.yml` at the distribution root with `product: { name: <your name> }`.
|
|
50
|
+
Env vars, the config and manifest file names, the state, managed-clone and
|
|
51
|
+
workspace directories all derive from that name, so an existing install
|
|
52
|
+
keeps every on-disk and env name by naming itself as before.
|
|
53
|
+
- Workspace mode `<name>-managed` is now `managed`. Old values are still
|
|
54
|
+
read, and rewritten on the next save.
|
|
55
|
+
- The CLI command `use-<name>` is now `use-managed`.
|
|
56
|
+
- `github_org` has no default: set it in the org config.
|
|
57
|
+
- The shared local-infra repo is configuration: `graph.infra: { repo,
|
|
58
|
+
signals }`. Without it no infra edges are derived. The default-workspace
|
|
59
|
+
entry repo is `defaults.workspace.entry`.
|
|
60
|
+
- Perf suites come from the distribution (`tests/pillars/perf/<module>/test.js`)
|
|
61
|
+
or from repo manifests; Den ships none.
|
|
62
|
+
- Service and setup make targets are `<prefix>-up`, `-status`, … where the
|
|
63
|
+
prefix is `DEN_TARGET_PREFIX` (set before including `make/den.mk`; `den
|
|
64
|
+
create` sets it to the CLI name, so `make <name>-up` keeps working).
|
|
65
|
+
- `service_env` has no built-in entries: a shared-infra secrets file is
|
|
66
|
+
configured as `service_env: { <KEY>: "{repo:<infra repo>}/<path>" }`.
|
|
67
|
+
- The smoke and browser make targets have no default repo: pass `repo=<repo>`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Monster Orange
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,167 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Den
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Den is a config-driven local development appliance. It starts the repos you
|
|
4
|
+
work on in dependency order, puts them behind a local HTTPS edge, gives you a
|
|
5
|
+
web UI and a CLI over all of it, and runs smoke, browser, API, journey,
|
|
6
|
+
security and performance suites against the environments you declare.
|
|
7
|
+
|
|
8
|
+
Den knows nothing about any particular organisation. Everything specific to
|
|
9
|
+
yours — product name, repos, environments, hosts, secrets backend, test
|
|
10
|
+
accounts — lives in **your distribution**, not in Den.
|
|
11
|
+
|
|
12
|
+
> **Status: 0.1.0**, the first release: `npm install @monster-orange/den`. Den is pre-1.0; each release lists the changes a distribution makes under **Migrations** in [CHANGELOG.md](CHANGELOG.md).
|
|
13
|
+
|
|
14
|
+
## Make it your own
|
|
15
|
+
|
|
16
|
+
1. **Create** a distribution named after your product:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npx @monster-orange/den create acme # → ./acme
|
|
20
|
+
cd acme && npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
2. **Name** it: `den.yml` holds `product: { name: acme }`, so the CLI is
|
|
24
|
+
`./bin/acme`, env vars are `ACME_*`, state lives in `~/.acme`. Pass
|
|
25
|
+
`--cli`, `--env-prefix` or `--title` to `create`, or edit `den.yml`.
|
|
26
|
+
3. **Brand** it: `brand:` in `config/acme.yml` sets the name, tagline and
|
|
27
|
+
banner people see in the CLI and web UI.
|
|
28
|
+
4. **Point it at your repos**: set `github_org` in `config/acme.yml`, then
|
|
29
|
+
`./bin/acme register ../shop-api` (or add a manifest per repo under
|
|
30
|
+
`manifests/`).
|
|
31
|
+
5. **Run** it: `./bin/acme up`, `./bin/acme web`, `make test`.
|
|
32
|
+
|
|
33
|
+
Every field, the bin shim, the make fragment and upgrading are in
|
|
34
|
+
[docs/distributions.md](docs/distributions.md);
|
|
35
|
+
[examples/distribution/](examples/distribution) is what `create acme` writes.
|
|
36
|
+
|
|
37
|
+
## Distributions
|
|
38
|
+
|
|
39
|
+
You run Den through a small repo of your own (a _distribution_):
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
my-dev/
|
|
43
|
+
├── den.yml # who this distribution is (below)
|
|
44
|
+
├── package.json # pins an exact @monster-orange/den version
|
|
45
|
+
├── config/<name>.yml # your org config
|
|
46
|
+
├── config/environments/ # one <env>.json per environment
|
|
47
|
+
├── manifests/ # manifests for repos that don't carry their own
|
|
48
|
+
├── tests/pillars/<pillar>/ # your own suites (e.g. tests/pillars/perf/<module>/test.js)
|
|
49
|
+
├── bin/<cli> # shim: DEN_ROOT=<this dir> exec node_modules/@monster-orange/den/bin/den
|
|
50
|
+
└── Makefile # include node_modules/@monster-orange/den/make/den.mk
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`den.yml` names the product. Every runtime name derives from it:
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
product:
|
|
57
|
+
name:
|
|
58
|
+
acme # CLI "acme", env vars ACME_*, config/acme.yml,
|
|
59
|
+
# manifests .acme.yml, state ~/.acme,
|
|
60
|
+
# managed clones .acme-services/, workspaces acme-workspaces/
|
|
61
|
+
# Override any of them: cli, env_prefix, config, manifest, state_dir,
|
|
62
|
+
# services_dir, workspaces_dir
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Den's own checkout is a distribution named `den`, so in this repo the CLI is
|
|
66
|
+
`./bin/den`, the config is `config/den.yml`, and env vars are `DEN_*`.
|
|
67
|
+
|
|
68
|
+
## Repos opt in with a manifest
|
|
69
|
+
|
|
70
|
+
A repo joins by carrying a manifest at its root (`.<name>.yml`, e.g.
|
|
71
|
+
`.den.yml`) whose commands delegate to the repo's own targets. Den never
|
|
72
|
+
reaches inside a repo beyond that. When a repo has no manifest, the
|
|
73
|
+
distribution can hold one for it in `manifests/<repo>.<name>.yml`; the repo's
|
|
74
|
+
own manifest always wins.
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
# demo-api: a self-contained service. Nothing it calls, so it starts alone.
|
|
78
|
+
version: 1
|
|
79
|
+
name: demo-api
|
|
80
|
+
application: shop # the application this repo belongs to (den apps)
|
|
81
|
+
compose:
|
|
82
|
+
files: [docker-compose.yml]
|
|
83
|
+
routes:
|
|
84
|
+
api: api:8080 # https://api.demo-api.<edge domain>
|
|
85
|
+
services:
|
|
86
|
+
demo-api:
|
|
87
|
+
commands:
|
|
88
|
+
local:
|
|
89
|
+
setup: make setup
|
|
90
|
+
preflight: make test
|
|
91
|
+
# OWASP ZAP target for the security pillar (`make test-sec-api env=local`).
|
|
92
|
+
security:
|
|
93
|
+
api:
|
|
94
|
+
hosts:
|
|
95
|
+
local: ["https://api.demo-api.globex.localhost"]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
That is `examples/demo/demo-api/.den.yml`; the other demo repos are in
|
|
99
|
+
[`examples/demo/`](examples/demo/).
|
|
100
|
+
|
|
101
|
+
## What it does
|
|
102
|
+
|
|
103
|
+
- **Workspaces.** A workspace is a set of repos. Each is either
|
|
104
|
+
_dev-managed_ (your checkout, your branch) or _managed_ (cloned by Den and
|
|
105
|
+
kept on a tracking branch).
|
|
106
|
+
- **Derived dependency graph.** Start and stop order comes from real signals in
|
|
107
|
+
each repo — SDK imports, `*_URL` env vars, IaC references, event rules,
|
|
108
|
+
readiness probes — tuned in config with `graph.aliases`, `graph.edges` and
|
|
109
|
+
an optional shared local-infra repo (`graph.infra`).
|
|
110
|
+
- **Local HTTPS edge.** One local proxy routes `https://<route>.<domain>` to
|
|
111
|
+
each service, with an optional project CA.
|
|
112
|
+
- **Test pillars.** `smoke`, `browser` (synthetic Playwright), `api`,
|
|
113
|
+
`journeys` (agent-driven), `perf` (k6), `security` (OWASP ZAP against hosts
|
|
114
|
+
you own) and `suites` (a repo's own commands).
|
|
115
|
+
- **Releases.** A release view over the repos and deploy workflows your config
|
|
116
|
+
lists.
|
|
117
|
+
- **Web UI and CLI** over the same state.
|
|
118
|
+
|
|
119
|
+
## Strategies
|
|
120
|
+
|
|
121
|
+
Concerns that vary by org are strategies selected in config, never hard-wired:
|
|
122
|
+
|
|
123
|
+
| Concern | Built-in choices | Chosen in |
|
|
124
|
+
| ---------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
125
|
+
| Secrets backend | `env`, `doppler`, `1password` | `secrets.provider` in the org config; per engineer in `config/local/user.yml`; per shell `<PREFIX>_SECRETS_PROVIDER` |
|
|
126
|
+
| Test-user tokens | `local-jwt`, `cognito`, `auth0`, `none` | `auth.provider` in `config/environments/<env>.json` |
|
|
127
|
+
|
|
128
|
+
A new secrets backend implements `SecretsProvider`
|
|
129
|
+
(`src/shared/secrets/types.ts`); a new identity provider implements a token
|
|
130
|
+
provider in `src/shared/auth/token-providers/`.
|
|
131
|
+
|
|
132
|
+
## CLI
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
den up [repo] # start the repo's derived dependency closure (-x deps only, -n dry run)
|
|
136
|
+
den down [repo] # stop it cleanly
|
|
137
|
+
den status # service health for the active workspace
|
|
138
|
+
den apps # Org > Application > Repo > Services
|
|
139
|
+
den graph [repo] # the derived dependency graph
|
|
140
|
+
den logs [repo] # tail a repo's local logs
|
|
141
|
+
den use-local [repo] # use your checkout · use-managed [repo] to switch back
|
|
142
|
+
den workspace list # workspaces (activate · deactivate · use · create · delete)
|
|
143
|
+
den run # run test suites (interactive, or with options)
|
|
144
|
+
den web # the web UI
|
|
145
|
+
den --help # everything else
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
In a distribution the command is that distribution's `cli` name.
|
|
149
|
+
|
|
150
|
+
## Developing Den
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npm ci
|
|
154
|
+
npm run typecheck
|
|
155
|
+
npm run lint
|
|
156
|
+
npm test
|
|
157
|
+
DEN_ORG_NAMES_FILE=<patterns file> node scripts/org-name-gate.mjs
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
CI runs the same gates. The org-name gate fails the build when any file names
|
|
161
|
+
an organisation, product, host or account; its patterns are kept out of this
|
|
162
|
+
repo (a CI secret) so the list itself is never published. See
|
|
163
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
[MIT](LICENSE)
|
package/bin/den
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Two roots (see src/shared/paths.ts):
|
|
5
|
+
# DEN_ENGINE_ROOT Den's own package: this script's parent directory, which
|
|
6
|
+
# in a distribution is node_modules/@monster-orange/den.
|
|
7
|
+
# DEN_ROOT the distribution: the directory holding den.yml. A
|
|
8
|
+
# distribution's bin/<cli> shim sets it; in Den's own
|
|
9
|
+
# checkout (where the engine dir holds den.yml) it is set
|
|
10
|
+
# here. Otherwise it is left unset and Den walks up from
|
|
11
|
+
# the entry script to find den.yml.
|
|
12
|
+
DEN_ENGINE_ROOT="$(cd "$(dirname "$(realpath "$0")")/.." && pwd)"
|
|
13
|
+
export DEN_ENGINE_ROOT
|
|
14
|
+
if [ -z "${DEN_ROOT:-}" ] && [ -f "$DEN_ENGINE_ROOT/den.yml" ]; then
|
|
15
|
+
DEN_ROOT="$DEN_ENGINE_ROOT"
|
|
16
|
+
export DEN_ROOT
|
|
17
|
+
fi
|
|
18
|
+
export DEN_INVOKE_CWD="$PWD"
|
|
19
|
+
export OP_ACCOUNT="${OP_ACCOUNT:-example.1password.com}"
|
|
20
|
+
|
|
21
|
+
# tsx: Den's own (a checkout) or hoisted into the distribution's node_modules.
|
|
22
|
+
find_tsx() {
|
|
23
|
+
local dir="$DEN_ENGINE_ROOT"
|
|
24
|
+
while :; do
|
|
25
|
+
if [ -x "$dir/node_modules/.bin/tsx" ]; then
|
|
26
|
+
printf '%s\n' "$dir/node_modules/.bin/tsx"
|
|
27
|
+
return 0
|
|
28
|
+
fi
|
|
29
|
+
[ "$dir" = "/" ] && return 1
|
|
30
|
+
dir="$(dirname "$dir")"
|
|
31
|
+
done
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# `create` scaffolds a new distribution: it needs no den.yml, so it runs on
|
|
35
|
+
# its own entry point rather than the full CLI.
|
|
36
|
+
entry="src/ui/cli/index.ts"
|
|
37
|
+
built="dist/src/ui/cli/index.js"
|
|
38
|
+
if [ "${1:-}" = "create" ]; then
|
|
39
|
+
shift
|
|
40
|
+
entry="src/ui/cli/create-main.ts"
|
|
41
|
+
built="dist/src/ui/cli/create-main.js"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Escape hatch: force the compiled build (e.g. to test the prod artifact).
|
|
45
|
+
if [ "${DEN_USE_DIST:-}" = "1" ] && [ -f "$DEN_ENGINE_ROOT/$built" ]; then
|
|
46
|
+
exec node "$DEN_ENGINE_ROOT/$built" "$@"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Prefer live TypeScript source (the package ships src/ and runs it with tsx).
|
|
50
|
+
# A built dist/ is gitignored and only refreshed by `npm run build`, so
|
|
51
|
+
# preferring it would silently shadow local source edits with a stale build.
|
|
52
|
+
if tsx="$(find_tsx)"; then
|
|
53
|
+
exec "$tsx" "$DEN_ENGINE_ROOT/$entry" "$@"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
if [ -f "$DEN_ENGINE_ROOT/$built" ]; then
|
|
57
|
+
exec node "$DEN_ENGINE_ROOT/$built" "$@"
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
echo "den: no runnable entrypoint: run 'npm install'" >&2
|
|
61
|
+
exit 1
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# Distributions
|
|
2
|
+
|
|
3
|
+
Den is one engine, `@monster-orange/den`. You run it through a small repo of
|
|
4
|
+
your own, a **distribution**, that installs Den as a package and holds
|
|
5
|
+
everything that makes it yours: its name, brand, config, manifests and tests.
|
|
6
|
+
Den's own checkout is itself a distribution, named `den`.
|
|
7
|
+
|
|
8
|
+
- [Create one](#create-one)
|
|
9
|
+
- [Layout](#layout)
|
|
10
|
+
- [den.yml: the product profile](#denyml-the-product-profile)
|
|
11
|
+
- [Brand](#brand)
|
|
12
|
+
- [The bin shim](#the-bin-shim)
|
|
13
|
+
- [make: den.mk](#make-denmk)
|
|
14
|
+
- [Two roots](#two-roots)
|
|
15
|
+
- [Pinning and upgrading](#pinning-and-upgrading)
|
|
16
|
+
- [Developing Den against a distribution](#developing-den-against-a-distribution)
|
|
17
|
+
|
|
18
|
+
## Create one
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npx @monster-orange/den create acme # writes ./acme
|
|
22
|
+
npx @monster-orange/den create acme ~/src/acme-dev --title "Acme Dev"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
From a Den checkout, `./bin/den create acme ../acme` does the same.
|
|
26
|
+
|
|
27
|
+
| Option | Default | What |
|
|
28
|
+
| ----------------------- | ------------------- | ------------------------------------- |
|
|
29
|
+
| `<name>` | (required) | Product name: `[a-z][a-z0-9-]*` |
|
|
30
|
+
| `[dir]` | `./<name>` | A new or empty directory |
|
|
31
|
+
| `--title <title>` | `<Name>` Title Case | Brand name shown to people |
|
|
32
|
+
| `--cli <cli>` | `<name>` | The command people type |
|
|
33
|
+
| `--env-prefix <PREFIX>` | `<NAME>` | Env-var prefix (`ACME` → `ACME_HOME`) |
|
|
34
|
+
|
|
35
|
+
`create` refuses a directory that is not empty and never overwrites a file.
|
|
36
|
+
[`examples/distribution/`](../examples/distribution) is exactly the output of
|
|
37
|
+
`den create acme`; a unit test regenerates it, so the two never drift
|
|
38
|
+
(`npm run example:regen` after changing the scaffolder).
|
|
39
|
+
|
|
40
|
+
Then:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
cd acme
|
|
44
|
+
npm install
|
|
45
|
+
./bin/acme --help
|
|
46
|
+
./bin/acme web # the web UI, branded "Acme"
|
|
47
|
+
make help
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Layout
|
|
51
|
+
|
|
52
|
+
| Path | What |
|
|
53
|
+
| ------------------------- | ------------------------------------------------------------ |
|
|
54
|
+
| `den.yml` | The product profile ([below](#denyml-the-product-profile)) |
|
|
55
|
+
| `package.json` | Pins an exact `@monster-orange/den` version |
|
|
56
|
+
| `bin/<cli>` | The shim people run ([below](#the-bin-shim)) |
|
|
57
|
+
| `Makefile` | Includes Den's targets ([below](#make-denmk)) |
|
|
58
|
+
| `config/<name>.yml` | Org config: brand, `github_org`, `secrets`, `edge`, … |
|
|
59
|
+
| `config/environments/` | One `<env>.json` per environment (base URLs, auth, timeouts) |
|
|
60
|
+
| `config/local/` | Per-engineer overrides (`user.yml`); gitignored |
|
|
61
|
+
| `manifests/` | Manifests for repos that do not carry their own |
|
|
62
|
+
| `tests/pillars/<pillar>/` | Your own suites, e.g. `tests/pillars/perf/<module>/test.js` |
|
|
63
|
+
| `reports/`, `results/` | Test output; gitignored |
|
|
64
|
+
|
|
65
|
+
## den.yml: the product profile
|
|
66
|
+
|
|
67
|
+
Every runtime name derives from `product.name`. Set only what you want to
|
|
68
|
+
differ.
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
product:
|
|
72
|
+
name: acme
|
|
73
|
+
# cli: acme
|
|
74
|
+
# env_prefix: ACME
|
|
75
|
+
# config: config/acme.yml
|
|
76
|
+
# manifest: .acme.yml
|
|
77
|
+
# state_dir: ~/.acme
|
|
78
|
+
# services_dir: .acme-services
|
|
79
|
+
# workspaces_dir: acme-workspaces
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
| Field | Default | What it names |
|
|
83
|
+
| ---------------- | -------------------- | ----------------------------------------------------------------- |
|
|
84
|
+
| `name` | `den` | The product; `[a-z][a-z0-9-]*`. Everything below derives from it |
|
|
85
|
+
| `cli` | `<name>` | The command shown in help, hints and the web UI |
|
|
86
|
+
| `env_prefix` | `<NAME>` (`-` → `_`) | Env vars: `<PREFIX>_ROOT`, `<PREFIX>_HOME`, `<PREFIX>_INVOKE_CWD` |
|
|
87
|
+
| `config` | `config/<name>.yml` | The org config, relative to the distribution root |
|
|
88
|
+
| `manifest` | `.<name>.yml` | The manifest file a repo carries; the `.json` twin is also read |
|
|
89
|
+
| `state_dir` | `~/.<name>` | Per-user state: web server, daemons, logs, history |
|
|
90
|
+
| `services_dir` | `.<name>-services` | Managed clones, relative to the distribution root |
|
|
91
|
+
| `workspaces_dir` | `<name>-workspaces` | Workspace checkouts, relative to the distribution root |
|
|
92
|
+
|
|
93
|
+
Env vars, with `ACME` as the prefix:
|
|
94
|
+
|
|
95
|
+
| Variable | What |
|
|
96
|
+
| ----------------- | ------------------------------------------------------------------ |
|
|
97
|
+
| `ACME_ROOT` | The distribution root, if Den cannot find it from the entry script |
|
|
98
|
+
| `ACME_HOME` | Overrides `state_dir` (two instances on one machine stay apart) |
|
|
99
|
+
| `DEN_ROOT` | The same as `<PREFIX>_ROOT`; the shim sets it |
|
|
100
|
+
| `DEN_ENGINE_ROOT` | Den's package directory; `bin/den` sets it |
|
|
101
|
+
| `DEN_PROFILE` | Read another profile file instead of `<root>/den.yml` (tests) |
|
|
102
|
+
|
|
103
|
+
## Brand
|
|
104
|
+
|
|
105
|
+
What people see: the CLI banner and help header, web page titles and the
|
|
106
|
+
edge's web route. Read from `brand:` in the org config; every field is
|
|
107
|
+
optional.
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
brand:
|
|
111
|
+
name: Acme # default: the product name, first letter upper-cased
|
|
112
|
+
tagline: Acme local dev and E2E harness # default: "Local dev and E2E harness"
|
|
113
|
+
banner: # optional ASCII-art lines; default: the name spelled out
|
|
114
|
+
- " ┌───────────┐"
|
|
115
|
+
- " │ A C M E │"
|
|
116
|
+
- " └───────────┘"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Field | Used for |
|
|
120
|
+
| --------- | ---------------------------------------------------------------------------- |
|
|
121
|
+
| `name` | Web page `<title>`s, the banner fallback, the web route on the edge (`acme`) |
|
|
122
|
+
| `tagline` | The line under the banner |
|
|
123
|
+
| `banner` | The CLI and web server startup banner |
|
|
124
|
+
|
|
125
|
+
Runtime names (env vars, files, directories) always come from `den.yml`,
|
|
126
|
+
never from the brand.
|
|
127
|
+
|
|
128
|
+
## The bin shim
|
|
129
|
+
|
|
130
|
+
`bin/<cli>` is three lines of sh: it names the distribution root and runs
|
|
131
|
+
Den from `node_modules`.
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
#!/bin/sh
|
|
135
|
+
DEN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
136
|
+
export DEN_ROOT; exec "$DEN_ROOT/node_modules/@monster-orange/den/bin/den" "$@"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`package.json` also lists it under `bin`, so `npm link` (or a global
|
|
140
|
+
install of the distribution) puts `acme` on your PATH.
|
|
141
|
+
|
|
142
|
+
Den's own `bin/den` sets `DEN_ENGINE_ROOT` to its own package directory and
|
|
143
|
+
sets `DEN_ROOT` only when it is unset and the engine directory holds a
|
|
144
|
+
`den.yml` (Den's own checkout). An installed Den ships no `den.yml`, so the
|
|
145
|
+
engine directory is never taken for a distribution. `DEN_USE_DIST=1` still
|
|
146
|
+
runs a compiled `dist/` build when one exists.
|
|
147
|
+
|
|
148
|
+
## make: den.mk
|
|
149
|
+
|
|
150
|
+
A distribution's `Makefile` includes Den's targets from the package:
|
|
151
|
+
|
|
152
|
+
```make
|
|
153
|
+
DEN_TARGET_PREFIX := acme
|
|
154
|
+
include node_modules/@monster-orange/den/make/den.mk
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`DEN_TARGET_PREFIX` names the service and setup targets: `make acme-up`,
|
|
158
|
+
`acme-down`, `acme-status`, `acme-logs`, `acme-graph`, `acme-workspace`,
|
|
159
|
+
`acme-setup` and the rest (default `den`). `den create` sets it to the CLI
|
|
160
|
+
name.
|
|
161
|
+
|
|
162
|
+
`den.mk` defines:
|
|
163
|
+
|
|
164
|
+
| Variable | What |
|
|
165
|
+
| ---------------- | --------------------------------------------------------------------- |
|
|
166
|
+
| `DEN_ENGINE` | Den's package directory (the directory above `den.mk`) |
|
|
167
|
+
| `DEN_TSX` | The tsx binary: Den's own, or the one npm hoisted into `node_modules` |
|
|
168
|
+
| `DEN_PLAYWRIGHT` | The playwright binary, found the same way |
|
|
169
|
+
| `DEN_BIN` | `$(DEN_ENGINE)/bin/den` |
|
|
170
|
+
| `DEN_ROOT` | Exported: the directory make runs in (`$(CURDIR)`) |
|
|
171
|
+
|
|
172
|
+
and includes `make/test.mk`, `local_dev.mk`, `journeys.mk`, `security.mk` and
|
|
173
|
+
`demo.mk`: `make test`, `make web`, `make <prefix>-up`, `make test-syn-all
|
|
174
|
+
repo=<repo>`, `make test-smk-all repo=<repo>`, `make test-perf
|
|
175
|
+
module=<module>`, `make test-jrn-all`, `make test-sec-all` and the rest.
|
|
176
|
+
Recipes run from the distribution root (reports and staged tests land there)
|
|
177
|
+
and reach Den's files through `$(DEN_ENGINE)`. `make help` lists the main
|
|
178
|
+
targets; define your own `help` by setting `DEN_OWN_HELP := 1` before the
|
|
179
|
+
include. Add your own targets below it.
|
|
180
|
+
|
|
181
|
+
## Two roots
|
|
182
|
+
|
|
183
|
+
Den resolves two directories (`src/shared/paths.ts`, `src/shared/engine.ts`):
|
|
184
|
+
|
|
185
|
+
- the **engine root** (`getEngineRoot()`, `enginePath()`): Den's own files,
|
|
186
|
+
`src/`, `make/`, `scripts/`; `node_modules/@monster-orange/den` in a
|
|
187
|
+
distribution;
|
|
188
|
+
- the **distribution root** (`getDistRoot()`, `distPath()`): `den.yml`,
|
|
189
|
+
config, manifests, `tests/pillars/`, reports, results, staged tests.
|
|
190
|
+
|
|
191
|
+
Den's scripts run with the engine's tsx (`tsxCommand()`), never through `npx`
|
|
192
|
+
or a path relative to the current directory. In Den's own checkout both roots
|
|
193
|
+
are the same directory.
|
|
194
|
+
|
|
195
|
+
## Running the web UI as a service (macOS)
|
|
196
|
+
|
|
197
|
+
Den ships a launchd installer that runs the web UI at login and restarts it if
|
|
198
|
+
it exits. From the distribution root:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
DEN_ROOT="$PWD" DEN_SERVICE_LABEL=local.acme.web \
|
|
202
|
+
node_modules/@monster-orange/den/service/install.sh # install or refresh
|
|
203
|
+
node_modules/@monster-orange/den/service/install.sh status # with the same env
|
|
204
|
+
node_modules/@monster-orange/den/service/install.sh uninstall
|
|
205
|
+
node_modules/@monster-orange/den/service/install.sh print # the plist only
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
| Variable | Default |
|
|
209
|
+
| ------------------- | ---------------------------------------- |
|
|
210
|
+
| `DEN_ROOT` | required in a distribution |
|
|
211
|
+
| `DEN_SERVICE_LABEL` | `local.<distribution dir name>.web` |
|
|
212
|
+
| `DEN_SERVICE_LOGS` | `~/Library/Logs/<distribution dir name>` |
|
|
213
|
+
|
|
214
|
+
The service runs the engine's server with the `node` on your `PATH` at install
|
|
215
|
+
time, from the distribution root; re-run `install` after changing node versions
|
|
216
|
+
or upgrading Den. Keep the label stable: it is how launchd knows the service.
|
|
217
|
+
|
|
218
|
+
## Pinning and upgrading
|
|
219
|
+
|
|
220
|
+
`package.json` pins an exact Den version (`create` writes the version that
|
|
221
|
+
ran it). Den is pre-1.0: read the **Migrations** section of
|
|
222
|
+
[CHANGELOG.md](../CHANGELOG.md) for every version between yours and the
|
|
223
|
+
target, make the config and manifest changes it lists, then:
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
npm install @monster-orange/den@<version> --save-exact
|
|
227
|
+
./bin/acme --version
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Installing from a tarball (`npm pack` of a Den checkout, before a version is
|
|
231
|
+
on npm): every tarball Den hands out has its own prerelease number
|
|
232
|
+
(`0.1.0-dev.1`, `-dev.2`, …). npm caches a tarball by version and
|
|
233
|
+
integrity, so a repacked tarball with an unchanged version reinstalls the
|
|
234
|
+
old copy; if you ever repack one yourself without bumping, remove
|
|
235
|
+
`node_modules/@monster-orange/den` and its `package-lock.json` entry first.
|
|
236
|
+
|
|
237
|
+
## Developing Den against a distribution
|
|
238
|
+
|
|
239
|
+
To try a Den change in a distribution, install your checkout instead of the
|
|
240
|
+
published package:
|
|
241
|
+
|
|
242
|
+
```sh
|
|
243
|
+
cd acme
|
|
244
|
+
npm install ../den # node_modules/@monster-orange/den → your checkout
|
|
245
|
+
./bin/acme status
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
npm links the directory, so edits to Den's `src/` take effect on the next
|
|
249
|
+
run (Den runs its TypeScript with tsx; there is no build step). Den's
|
|
250
|
+
checkout has its own `den.yml`, but the shim's `DEN_ROOT` wins, so the CLI
|
|
251
|
+
still runs as the distribution. Put the pinned version back with `npm
|
|
252
|
+
install @monster-orange/den@<version> --save-exact` before committing.
|
|
253
|
+
|
|
254
|
+
To check a change the way CI does, run `scripts/dist-smoke.sh` in Den's
|
|
255
|
+
checkout: it packs Den, scaffolds `acme` from the tarball, installs the
|
|
256
|
+
tarball into it, and checks the CLI, make targets and web server.
|
package/make/demo.mk
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# make/demo.mk — end-to-end proof of the repo flow on three demo repos
|
|
2
|
+
#
|
|
3
|
+
# examples/demo/demo-api standalone API
|
|
4
|
+
# examples/demo/demo-web calls demo-api (.den.yml compose.uses)
|
|
5
|
+
# examples/demo/demo-notes unrelated, standalone
|
|
6
|
+
#
|
|
7
|
+
# Each repo carries its own Makefile (run it alone) and .den.yml (how
|
|
8
|
+
# den runs it: compose behind the HTTPS edge, no host ports).
|
|
9
|
+
#
|
|
10
|
+
# make demo register + up + check + restart + down, then clean up
|
|
11
|
+
# make demo-register workspace "demo" with the three repos
|
|
12
|
+
# make demo-apps den apps: "shop" (declared by the repos) + demo-notes (its own)
|
|
13
|
+
# make demo-up den up -A shop (demo-api first), then demo-notes
|
|
14
|
+
# make demo-check HTTPS through the edge (retries ~10s while the edge
|
|
15
|
+
# picks up new routes); demo-web shows demo-api's answer
|
|
16
|
+
# make demo-status den status
|
|
17
|
+
# make demo-restart den restart -A shop
|
|
18
|
+
# make demo-down den down, every demo repo
|
|
19
|
+
# make demo-clean down, drop the demo workspace + catalog entries, refocus
|
|
20
|
+
|
|
21
|
+
.PHONY: demo demo-apps demo-register demo-up demo-check demo-status demo-graph demo-restart demo-down demo-clean
|
|
22
|
+
|
|
23
|
+
DEMO_WS := demo
|
|
24
|
+
DEMO_REPOS := demo-api demo-web demo-notes
|
|
25
|
+
DEMO_DIR := $(DEN_ENGINE)/examples/demo
|
|
26
|
+
DEMO_PREV := $(HOME)/.den/demo-prev-focus
|
|
27
|
+
DEMO_DOMAIN = $(shell $(DEN_TSX) -e 'import("$(DEN_ENGINE)/src/shared/edge/config.ts").then(m=>console.log(m.readEdgeConfig().domain))' 2>/dev/null)
|
|
28
|
+
DEN_CLI := $(DEN_BIN)
|
|
29
|
+
|
|
30
|
+
# Steps run in sequence (a prerequisite list would run demo-check only once).
|
|
31
|
+
demo:
|
|
32
|
+
@for t in demo-register demo-apps demo-graph demo-up demo-check demo-restart demo-check demo-status demo-clean; do \
|
|
33
|
+
echo "\n── make $$t"; $(MAKE) --no-print-directory $$t || { $(MAKE) --no-print-directory demo-clean; exit 1; }; \
|
|
34
|
+
done
|
|
35
|
+
@echo "\n✓ demo passed"
|
|
36
|
+
|
|
37
|
+
demo-register:
|
|
38
|
+
@mkdir -p $(dir $(DEMO_PREV))
|
|
39
|
+
@[ -f $(DEMO_PREV) ] || $(DEN_TSX) -e 'import("$(DEN_ENGINE)/src/shared/environment-manager/workspaces.ts").then(m=>console.log(m.getFocusedWorkspaceName()??"default"))' > $(DEMO_PREV)
|
|
40
|
+
@$(DEN_CLI) workspace create $(DEMO_WS) >/dev/null
|
|
41
|
+
@$(DEN_CLI) workspace use $(DEMO_WS) >/dev/null
|
|
42
|
+
@for r in $(DEMO_REPOS); do $(DEN_CLI) register $(DEMO_DIR)/$$r; done
|
|
43
|
+
@$(DEN_CLI) workspace list
|
|
44
|
+
|
|
45
|
+
demo-apps:
|
|
46
|
+
@$(DEN_CLI) apps
|
|
47
|
+
|
|
48
|
+
demo-graph:
|
|
49
|
+
@$(DEN_CLI) up -A shop --dry-run
|
|
50
|
+
|
|
51
|
+
demo-up:
|
|
52
|
+
@$(DEN_CLI) up -A shop
|
|
53
|
+
@$(DEN_CLI) up demo-notes
|
|
54
|
+
|
|
55
|
+
demo-check:
|
|
56
|
+
@set -e; for u in api.demo-api app.demo-web app.demo-notes; do \
|
|
57
|
+
for i in 1 2 3 4 5 6 7 8 9 10; do \
|
|
58
|
+
code=$$(curl -sk -o /dev/null -w '%{http_code}' https://$$u.$(DEMO_DOMAIN)/healthz); \
|
|
59
|
+
[ "$$code" = 200 ] && break; sleep 1; \
|
|
60
|
+
done; \
|
|
61
|
+
echo "$$code https://$$u.$(DEMO_DOMAIN)/healthz"; [ "$$code" = 200 ] || exit 1; \
|
|
62
|
+
done
|
|
63
|
+
@curl -sk https://app.demo-web.$(DEMO_DOMAIN)/ | grep -q '"service": "demo-api"' \
|
|
64
|
+
&& echo "✓ demo-web reached demo-api over the link network" \
|
|
65
|
+
|| { echo "✗ demo-web did not reach demo-api"; exit 1; }
|
|
66
|
+
|
|
67
|
+
demo-status:
|
|
68
|
+
@$(DEN_CLI) status
|
|
69
|
+
|
|
70
|
+
demo-restart:
|
|
71
|
+
@$(DEN_CLI) restart -A shop
|
|
72
|
+
|
|
73
|
+
demo-down:
|
|
74
|
+
@$(DEN_CLI) down -A shop
|
|
75
|
+
@$(DEN_CLI) down demo-notes
|
|
76
|
+
|
|
77
|
+
demo-clean: demo-down
|
|
78
|
+
@$(DEN_CLI) workspace use $$(cat $(DEMO_PREV) 2>/dev/null || echo default) >/dev/null
|
|
79
|
+
@$(DEN_CLI) workspace delete $(DEMO_WS) --yes >/dev/null
|
|
80
|
+
@$(DEN_TSX) -e 'import("$(DEN_ENGINE)/src/shared/environment-manager/catalog.ts").then(m=>{for(const r of process.argv.slice(1))m.removeCatalogEntry(r)})' $(DEMO_REPOS)
|
|
81
|
+
@echo "✓ demo workspace removed; focus back on $$(cat $(DEMO_PREV) 2>/dev/null || echo default)"
|
|
82
|
+
@rm -f $(DEMO_PREV)
|