Skip to content

Commit db6ed84

Browse files
committed
feat: fix dev env port resolution and improve multi-worktree support
Fix OTel collector endpoint resolution and add multi-worktree improvements: - Fix dotenv-expand infinite recursion from self-referential ${VAR:-default} patterns in .env files that prevented port isolation from working - Fix HDX_COLLECTOR_URL fallback for browser-side OTel telemetry - Set correct HYPERDX_API_KEY in app .env.development - Add slot-specific session cookie names (connect.sid.<slot>) so multiple worktrees on localhost don't overwrite each other's sessions - Share NX build cache across worktrees via NX_CACHE_DIRECTORY - Add worktrunk project config (.config/wt.toml) for worktree lifecycle hooks: symlink node_modules, copy .env.local, clean up Docker on remove
1 parent 53ba1e3 commit db6ed84

7 files changed

Lines changed: 55 additions & 22 deletions

File tree

.config/wt.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# HyperDX worktrunk project config
2+
# See: https://worktrunk.dev
3+
#
4+
# This file is committed and shared with the team. It configures lifecycle
5+
# hooks that run when creating/switching/removing worktrees via `wt`.
6+
7+
# ---------------------------------------------------------------------------
8+
# pre-start: blocking — symlink node_modules from primary worktree for
9+
# instant dependency access. If the branch needs different deps, remove the
10+
# symlink and run `yarn install` manually.
11+
# ---------------------------------------------------------------------------
12+
pre-start = "ln -sf {{ primary_worktree_path }}/node_modules {{ worktree_path }}/node_modules"
13+
14+
# ---------------------------------------------------------------------------
15+
# post-start: background tasks
16+
# ---------------------------------------------------------------------------
17+
[post-start]
18+
env = "cp {{ primary_worktree_path }}/.env.local {{ worktree_path }}/.env.local 2>/dev/null && echo 'Copied .env.local' || true"
19+
20+
# ---------------------------------------------------------------------------
21+
# post-remove: clean up all Docker resources for this worktree's slot
22+
# (dev stack, integration tests, E2E tests)
23+
# ---------------------------------------------------------------------------
24+
[post-remove]
25+
dev-down = "make dev-down 2>/dev/null || true"
26+
int-down = "make dev-int-down 2>/dev/null || true"
27+
e2e-down = "make dev-e2e-down 2>/dev/null || true"

.env

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ HYPERDX_OPAMP_PORT=${HYPERDX_OPAMP_PORT:-4320}
2929
HYPERDX_BASE_PATH=
3030

3131
# Docker service ports (overridden by scripts/dev-env.sh for isolation)
32-
HDX_DEV_MONGO_PORT=${HDX_DEV_MONGO_PORT:-27017}
33-
HDX_DEV_CH_HTTP_PORT=${HDX_DEV_CH_HTTP_PORT:-8123}
34-
HDX_DEV_CH_NATIVE_PORT=${HDX_DEV_CH_NATIVE_PORT:-9000}
35-
HDX_DEV_OTEL_HEALTH_PORT=${HDX_DEV_OTEL_HEALTH_PORT:-13133}
36-
HDX_DEV_OTEL_GRPC_PORT=${HDX_DEV_OTEL_GRPC_PORT:-4317}
37-
HDX_DEV_OTEL_HTTP_PORT=${HDX_DEV_OTEL_HTTP_PORT:-4318}
38-
HDX_DEV_OTEL_METRICS_PORT=${HDX_DEV_OTEL_METRICS_PORT:-8888}
39-
HDX_DEV_OTEL_JSON_HTTP_PORT=${HDX_DEV_OTEL_JSON_HTTP_PORT:-14318}
32+
HDX_DEV_MONGO_PORT=27017
33+
HDX_DEV_CH_HTTP_PORT=8123
34+
HDX_DEV_CH_NATIVE_PORT=9000
35+
HDX_DEV_OTEL_HEALTH_PORT=13133
36+
HDX_DEV_OTEL_GRPC_PORT=4317
37+
HDX_DEV_OTEL_HTTP_PORT=4318
38+
HDX_DEV_OTEL_METRICS_PORT=8888
39+
HDX_DEV_OTEL_JSON_HTTP_PORT=14318
4040

4141
# Otel/Clickhouse config
4242
HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE=default

packages/api/.env.development

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
11
HYPERDX_API_KEY="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
2-
# Ports are overridden by scripts/dev-env.sh for worktree isolation
3-
HYPERDX_API_PORT=${HYPERDX_API_PORT:-8000}
4-
HYPERDX_OPAMP_PORT=${HYPERDX_OPAMP_PORT:-4320}
5-
HYPERDX_APP_PORT=${HYPERDX_APP_PORT:-8080}
2+
# Ports come from scripts/dev-env.sh (worktree isolation) or root .env (defaults)
63
HYPERDX_LOG_LEVEL=debug
74
EXPRESS_SESSION_SECRET="hyperdx is cool 👋"
85
FRONTEND_URL="http://localhost:${HYPERDX_APP_PORT}"
96
HDX_NODE_ADVANCED_NETWORK_CAPTURE=1
107
HDX_NODE_BETA_MODE=1
118
HDX_NODE_CONSOLE_CAPTURE=1
12-
HYPERDX_API_KEY=${HYPERDX_API_KEY}
13-
HYPERDX_LOG_LEVEL=${HYPERDX_LOG_LEVEL}
149
MINER_API_URL="http://localhost:5123"
15-
MONGO_URI="mongodb://localhost:${HDX_DEV_MONGO_PORT:-27017}/hyperdx"
10+
MONGO_URI="mongodb://localhost:${HDX_DEV_MONGO_PORT}/hyperdx"
1611
NODE_ENV=development
1712
OTEL_SERVICE_NAME="hdx-oss-dev-api"
1813
OTEL_RESOURCE_ATTRIBUTES="service.version=dev"
19-
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:${HDX_DEV_OTEL_HTTP_PORT:-4318}"
14+
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:${HDX_DEV_OTEL_HTTP_PORT}"
2015
PORT=${HYPERDX_API_PORT}
2116
OPAMP_PORT=${HYPERDX_OPAMP_PORT}
2217
REDIS_URL=redis://localhost:6379
2318
USAGE_STATS_ENABLED=false
2419
NODE_OPTIONS="--max-http-header-size=131072"
2520
ENABLE_SWAGGER=true
26-
DEFAULT_CONNECTIONS=[{"name":"Local ClickHouse","host":"http://localhost:${HDX_DEV_CH_HTTP_PORT:-8123}","username":"default","password":""}]
21+
DEFAULT_CONNECTIONS=[{"name":"Local ClickHouse","host":"http://localhost:${HDX_DEV_CH_HTTP_PORT}","username":"default","password":""}]
2722
DEFAULT_SOURCES=[{"from":{"databaseName":"default","tableName":"otel_logs"},"kind":"log","timestampValueExpression":"TimestampTime","name":"Logs","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"Body","serviceNameExpression":"ServiceName","bodyExpression":"Body","eventAttributesExpression":"LogAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,SeverityText,Body","severityTextExpression":"SeverityText","traceIdExpression":"TraceId","spanIdExpression":"SpanId","connection":"Local ClickHouse","traceSourceId":"Traces","sessionSourceId":"Sessions","metricSourceId":"Metrics"},{"from":{"databaseName":"default","tableName":"otel_traces"},"kind":"trace","timestampValueExpression":"Timestamp","name":"Traces","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"SpanName","serviceNameExpression":"ServiceName","eventAttributesExpression":"SpanAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,StatusCode,round(Duration/1e6),SpanName","traceIdExpression":"TraceId","spanIdExpression":"SpanId","durationExpression":"Duration","durationPrecision":9,"parentSpanIdExpression":"ParentSpanId","spanNameExpression":"SpanName","spanKindExpression":"SpanKind","statusCodeExpression":"StatusCode","statusMessageExpression":"StatusMessage","connection":"Local ClickHouse","logSourceId":"Logs","sessionSourceId":"Sessions","metricSourceId":"Metrics"},{"from":{"databaseName":"default","tableName":""},"kind":"metric","timestampValueExpression":"TimeUnix","name":"Metrics","resourceAttributesExpression":"ResourceAttributes","metricTables":{"gauge":"otel_metrics_gauge","histogram":"otel_metrics_histogram","sum":"otel_metrics_sum","_id":"682586a8b1f81924e628e808","id":"682586a8b1f81924e628e808"},"connection":"Local ClickHouse","logSourceId":"Logs","traceSourceId":"Traces","sessionSourceId":"Sessions"},{"from":{"databaseName":"default","tableName":"hyperdx_sessions"},"kind":"session","timestampValueExpression":"TimestampTime","name":"Sessions","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"Body","serviceNameExpression":"ServiceName","bodyExpression":"Body","eventAttributesExpression":"LogAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,SeverityText,Body","severityTextExpression":"SeverityText","traceIdExpression":"TraceId","spanIdExpression":"SpanId","connection":"Local ClickHouse","logSourceId":"Logs","traceSourceId":"Traces","metricSourceId":"Metrics"},{"from":{"databaseName":"otel_json","tableName":"otel_logs"},"kind":"log","timestampValueExpression":"Timestamp","name":"JSON Logs","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"Body","serviceNameExpression":"ServiceName","bodyExpression":"Body","eventAttributesExpression":"LogAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,SeverityText,Body","severityTextExpression":"SeverityText","traceIdExpression":"TraceId","spanIdExpression":"SpanId","connection":"Local ClickHouse","traceSourceId":"JSON Traces","metricSourceId":"JSON Metrics"},{"from":{"databaseName":"otel_json","tableName":"otel_traces"},"kind":"trace","timestampValueExpression":"Timestamp","name":"JSON Traces","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"SpanName","serviceNameExpression":"ServiceName","eventAttributesExpression":"SpanAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,StatusCode,round(Duration/1e6),SpanName","traceIdExpression":"TraceId","spanIdExpression":"SpanId","durationExpression":"Duration","durationPrecision":9,"parentSpanIdExpression":"ParentSpanId","spanNameExpression":"SpanName","spanKindExpression":"SpanKind","statusCodeExpression":"StatusCode","statusMessageExpression":"StatusMessage","connection":"Local ClickHouse","logSourceId":"JSON Logs","metricSourceId":"JSON Metrics"},{"from":{"databaseName":"otel_json","tableName":""},"kind":"metric","timestampValueExpression":"TimeUnix","name":"JSON Metrics","resourceAttributesExpression":"ResourceAttributes","metricTables":{"gauge":"otel_metrics_gauge","histogram":"otel_metrics_histogram","sum":"otel_metrics_sum"},"connection":"Local ClickHouse","logSourceId":"JSON Logs","traceSourceId":"JSON Traces"}]
2823
INGESTION_API_KEY="super-secure-ingestion-api-key"
2924
HYPERDX_API_KEY=$INGESTION_API_KEY

packages/api/src/api-app.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ import passport from './utils/passport';
2222
const app: express.Application = express();
2323

2424
const sess: session.SessionOptions & { cookie: session.CookieOptions } = {
25+
// Use a slot-specific cookie name in dev so multiple worktrees on localhost
26+
// don't overwrite each other's session cookies.
27+
...(config.IS_DEV && process.env.HDX_DEV_SLOT
28+
? { name: `connect.sid.${process.env.HDX_DEV_SLOT}` }
29+
: {}),
2530
resave: false,
2631
saveUninitialized: false,
2732
secret: config.EXPRESS_SESSION_SECRET,

packages/app/.env.development

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
HYPERDX_API_KEY="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
2-
# Ports are overridden by scripts/dev-env.sh for worktree isolation
3-
HYPERDX_API_PORT=${HYPERDX_API_PORT:-8000}
4-
HYPERDX_APP_PORT=${HYPERDX_APP_PORT:-8080}
1+
HYPERDX_API_KEY="super-secure-ingestion-api-key"
2+
# Ports come from scripts/dev-env.sh (worktree isolation) or root .env (defaults)
53
SERVER_URL="http://localhost:${HYPERDX_API_PORT}"
64
NODE_ENV=development
7-
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:${HDX_DEV_OTEL_HTTP_PORT:-4318}"
5+
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:${HDX_DEV_OTEL_HTTP_PORT}"
86
OTEL_SERVICE_NAME="hdx-oss-dev-app"
97
PORT=${HYPERDX_APP_PORT}
108
NODE_OPTIONS="--max-http-header-size=131072"

packages/app/src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const HDX_EXPORTER_ENABLED =
1616
(process.env.HDX_EXPORTER_ENABLED ?? 'true') === 'true';
1717
export const HDX_COLLECTOR_URL =
1818
process.env.NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT ??
19+
process.env.OTEL_EXPORTER_OTLP_ENDPOINT ??
1920
'http://localhost:4318';
2021
export const IS_DEV = NODE_ENV === 'development';
2122

scripts/dev-env.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ HDX_DEV_OTEL_JSON_HTTP_PORT=$((31100 + HDX_DEV_SLOT))
5959
# --- Docker Compose project name (unique per slot) ---
6060
HDX_DEV_PROJECT="hdx-dev-${HDX_DEV_SLOT}"
6161

62+
# --- Shared NX build cache across all worktrees ---
63+
# NX cache is content-hash based so changed files get cache misses (correct
64+
# behavior). Unchanged packages reuse cached output regardless of worktree.
65+
NX_CACHE_DIRECTORY="${HOME}/.config/hyperdx/nx-cache"
66+
mkdir -p "$NX_CACHE_DIRECTORY"
67+
6268
# Export everything
6369
export HDX_DEV_SLOT
6470
export HDX_DEV_BRANCH
@@ -75,6 +81,7 @@ export HDX_DEV_OTEL_HTTP_PORT
7581
export HDX_DEV_OTEL_METRICS_PORT
7682
export HDX_DEV_OTEL_JSON_HTTP_PORT
7783
export HDX_DEV_PROJECT
84+
export NX_CACHE_DIRECTORY
7885

7986
# --- Clean up stale Next.js state from previous sessions ---
8087
# Nuke the entire .next directory to avoid stale webpack bundles, lock files,

0 commit comments

Comments
 (0)