For additional context about technologies to be used, project structure, shell commands, and other important information, read the current plan at `specs/002-sitemap-generation/plan.md` ## Project Overview `kme-content-adapter` is an HTTP proxy adapter (Node.js ≥18, ESM) that searches and exports documents from KME via a single proxy script executed in a VM sandbox. ## Commands ```bash npm run dev # Start with --watch (auto-restart on file changes) npm start # Start, piping logs through jq for pretty-printing npm test # Run all tests npm run test:unit # Unit tests only npm run test:integration # Integration tests only npm run test:contract # Contract tests only # Run a single test file node --test tests/unit/my.test.js ``` Tests use the Node.js built-in test runner (`node:test`). No test framework is installed. Environment overrides: `PORT`, `HOST`, `LOG_LEVEL`. ## Architecture The server loads `src/proxyScripts/proxy.js` once at startup using `vm.Script`, then executes it in a **fresh isolated VM context per request** via `vm.createContext`. This mirrors the target deployment environment (IVA Studio proxy script). ``` src/ ├── proxyScripts/ │ └── proxy.js # ALL business logic lives here ├── globalVariables/ │ ├── *.json # Runtime data injected into VM context │ └── adapterHelper.js # Pure utility functions (optional) ├── logger.js # Structured JSON logger └── server.js # HTTP server bootstrap only config/ └── default.json # Infrastructure settings (port, host, log level) ``` **Context injection** — `server.js` injects these globals into every request context: | Variable | Source | |---|---| | `console` | Custom structured logger (`logger.js`) | | `crypto` | Node.js Web Crypto API | | `axios` | HTTP client | | `jwt` | `jsonwebtoken` | | `uuidv4` | UUID v4 generator | | `xmlBuilder` | `xmlbuilder2` `create` function | | `URLSearchParams`, `URL` | Node.js globals | | `adapterHelper` | Loaded from `src/globalVariables/adapterHelper.js` (if present) | | `` | Each JSON/JS file in `src/globalVariables/` (filename → variable name) | | `req`, `res` | Node.js HTTP request/response | Routing metadata (`workspaceId`, `branch`, `route`) is attached by `server.js` to `req.params` before invoking the proxy — `proxy.js` must read these from `req.params`, never from `config`. ## Key Conventions ### `src/proxyScripts/proxy.js` — The Only Place for Business Logic - **ZERO `import`/`export` statements** — the file runs in a VM with no module system access. - **ZERO access to `config`, `global.config`, or `process.env`** — these are server concerns. - All dependencies arrive via the injected VM context (see table above). - Access injected variables directly: `adapter_settings.key`, not `globalThis["adapter_settings"]`. ### `src/globalVariables/adapterHelper.js` — Literal Function Body Pattern This file contains the **literal body of a function**, not valid standalone JavaScript. `server.js` wraps it at load time: ```javascript // server.js wraps the file contents like this: const wrappedCode = `(function() {\n${code}\n})()`; ``` So `adapterHelper.js` must end with a bare `return { ... }` that exports the helpers object. It must have zero imports/exports and contain only pure utilities (validators, formatters, XML helpers, error mappers). Authentication, API calls, and state must stay in `proxy.js`. ### `src/globalVariables/` — Filename Is the Variable Name Every file loaded from this directory is injected into the VM context using its filename (without extension) as the key: - `adapter_settings.json` → available as `adapter_settings` in `proxy.js` - `adapterHelper.js` → available as `adapterHelper` in `proxy.js` - Files matching `*.example.*` are skipped. - JSON files are loaded before JS files (so JS modules can reference JSON data). ### Config vs. Secrets - `config/default.json` — infrastructure only: `server.port`, `server.host`, `logging.level`, `proxy.*` - Credentials, API keys, and behavioral config → JSON files in `src/globalVariables/` ### Logging Use the `logger` from `src/logger.js` in server-side code. It accepts either a string or a structured object: ```javascript logger.info("Simple message"); logger.info({ message: "Structured", requestId: "abc", status: 200 }); ``` In `proxy.js`, use the injected `console` object (same API). ### Challenging New Files Before adding any file to `src/`, verify it belongs to one of the five allowed categories (server.js, logger.js, proxyScripts/proxy.js, globalVariables/*.json, globalVariables/adapterHelper.js). New files require explicit justification against the monolithic architecture constraint.