Fix DECT relay container: install node_modules at /workspace, not under agent
The runtime container failed with ERR_MODULE_NOT_FOUND: axios when integrations/cisco-dect/client.js tried to load. Root cause is Node's ESM resolver: it walks UP from the IMPORTING file looking for node_modules, never sideways into siblings. Container filesystem before: /workspace/dect-relay-agent/node_modules/ <- axios lives here /workspace/dect-relay-agent/index.js <- ok, finds it by walking up /workspace/integrations/cisco-dect/client.js <- walks up to /, never sees axios Node 20.20 has --experimental-detect-module ON by default, so client.js is still treated as ESM (starts with `import`), and the resolver correctly reports "cannot find package 'axios'" rather than syntax-erroring on the import keyword. But it still can't find the package — the location is wrong. Fix: install node_modules at /workspace/ so BOTH the agent AND the shared modules can find it by walking up. /workspace/node_modules/ <- axios here now /workspace/package.json <- also here, "type":"module" for all descendants /workspace/dect-relay-agent/index.js <- walks up to /workspace/node_modules ✓ /workspace/integrations/cisco-dect/client.js <- walks up to /workspace/node_modules ✓ /workspace/utils/httpDigestAuth.js <- same ✓ WORKDIR moves from /workspace/dect-relay-agent to /workspace, and CMD changes accordingly: node --enable-source-maps dect-relay-agent/index.js Rebuild + reship the bundle with `./dect-relay-agent/bundle.sh` and `./install.sh` on the DC host — it's an idempotent upgrade. Verified locally (agent modules import cleanly using the same directory shape as the container).
This commit is contained in:
parent
4f9ebdb5fb
commit
59460b849b
1 changed files with 36 additions and 13 deletions
|
|
@ -28,6 +28,22 @@
|
||||||
# it as a tarball, and ships the tarball. The DC only runs
|
# it as a tarball, and ships the tarball. The DC only runs
|
||||||
# `docker load` + `docker compose up -d` — zero network calls beyond
|
# `docker load` + `docker compose up -d` — zero network calls beyond
|
||||||
# the initial docker load.
|
# the initial docker load.
|
||||||
|
#
|
||||||
|
# WHERE node_modules LIVES (subtle but critical):
|
||||||
|
# /workspace/node_modules ← NOT under dect-relay-agent/
|
||||||
|
#
|
||||||
|
# The agent imports `../integrations/cisco-dect/client.js`, which
|
||||||
|
# in turn does `import axios from 'axios'`. Node's ESM resolver
|
||||||
|
# walks UP from the IMPORTING file (client.js) looking for
|
||||||
|
# node_modules — it does NOT search siblings. So if node_modules
|
||||||
|
# lived at /workspace/dect-relay-agent/node_modules, then
|
||||||
|
# client.js (at /workspace/integrations/cisco-dect/client.js) would
|
||||||
|
# never find axios and blow up with ERR_MODULE_NOT_FOUND at runtime.
|
||||||
|
# Placing node_modules one level higher fixes it: both the agent
|
||||||
|
# AND the shared integrations resolve axios via /workspace/node_modules.
|
||||||
|
# The package.json at /workspace/ also declares "type":"module" so
|
||||||
|
# every .js file under /workspace/ is treated as ESM without needing
|
||||||
|
# its own package.json.
|
||||||
|
|
||||||
# ─── Stage 1: builder ────────────────────────────────────────────────
|
# ─── Stage 1: builder ────────────────────────────────────────────────
|
||||||
# Installs prod deps in a full node image (has python/build-essentials
|
# Installs prod deps in a full node image (has python/build-essentials
|
||||||
|
|
@ -37,10 +53,12 @@
|
||||||
|
|
||||||
FROM node:20-alpine AS builder
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
WORKDIR /workspace/dect-relay-agent
|
WORKDIR /workspace
|
||||||
|
|
||||||
# Copy just the package manifest first so this layer caches across
|
# Copy just the package manifest first so this layer caches across
|
||||||
# code-only changes.
|
# code-only changes. The agent's package.json IS the workspace
|
||||||
|
# package.json — same "type":"module", same deps (ws / axios /
|
||||||
|
# dotenv), just placed one directory higher.
|
||||||
COPY dect-relay-agent/package.json ./package.json
|
COPY dect-relay-agent/package.json ./package.json
|
||||||
|
|
||||||
# Install only production deps. --ignore-scripts because we don't run
|
# Install only production deps. --ignore-scripts because we don't run
|
||||||
|
|
@ -60,21 +78,26 @@ FROM node:20-alpine AS runtime
|
||||||
# baseline hardening we get essentially for free.
|
# baseline hardening we get essentially for free.
|
||||||
USER node
|
USER node
|
||||||
|
|
||||||
# Match the repo layout so relative imports (`../integrations/...`)
|
# WORKDIR is the workspace root so `node dect-relay-agent/index.js`
|
||||||
# resolve exactly as they do in development.
|
# resolves correctly AND node_modules at /workspace/node_modules is
|
||||||
WORKDIR /workspace/dect-relay-agent
|
# discoverable by both the agent and the shared modules.
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
# Ship the node_modules we built in stage 1. Ownership goes to `node`
|
# Shared node_modules (see the header comment for why it's here and
|
||||||
# so the process can read them without needing root.
|
# not under dect-relay-agent/). Ownership goes to `node` so the
|
||||||
COPY --from=builder --chown=node:node /workspace/dect-relay-agent/node_modules ./node_modules
|
# process can read them without needing root.
|
||||||
|
COPY --from=builder --chown=node:node /workspace/node_modules ./node_modules
|
||||||
|
|
||||||
# Agent source + manifest.
|
# Package manifest at workspace root — Node uses this to determine
|
||||||
|
# "type":"module" for every .js file under /workspace/**.
|
||||||
COPY --chown=node:node dect-relay-agent/package.json ./package.json
|
COPY --chown=node:node dect-relay-agent/package.json ./package.json
|
||||||
COPY --chown=node:node dect-relay-agent/index.js ./index.js
|
|
||||||
|
# Agent source.
|
||||||
|
COPY --chown=node:node dect-relay-agent/index.js ./dect-relay-agent/index.js
|
||||||
|
|
||||||
# Shared modules the agent imports from the parent workspace.
|
# Shared modules the agent imports from the parent workspace.
|
||||||
COPY --chown=node:node integrations/cisco-dect /workspace/integrations/cisco-dect
|
COPY --chown=node:node integrations/cisco-dect ./integrations/cisco-dect
|
||||||
COPY --chown=node:node utils/httpDigestAuth.js /workspace/utils/httpDigestAuth.js
|
COPY --chown=node:node utils/httpDigestAuth.js ./utils/httpDigestAuth.js
|
||||||
|
|
||||||
# Optional metadata that shows up in `docker inspect` output — useful
|
# Optional metadata that shows up in `docker inspect` output — useful
|
||||||
# in the DC for "which build am I running?" without needing to poke
|
# in the DC for "which build am I running?" without needing to poke
|
||||||
|
|
@ -92,4 +115,4 @@ LABEL org.opencontainers.image.title="dect-relay-agent" \
|
||||||
# Node handles SIGTERM natively when the process installs handlers
|
# Node handles SIGTERM natively when the process installs handlers
|
||||||
# (which we do in index.js). --enable-source-maps improves stack
|
# (which we do in index.js). --enable-source-maps improves stack
|
||||||
# traces if something crashes at runtime — cheap and always-on.
|
# traces if something crashes at runtime — cheap and always-on.
|
||||||
CMD ["node", "--enable-source-maps", "index.js"]
|
CMD ["node", "--enable-source-maps", "dect-relay-agent/index.js"]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue