Files
kme_content_adapter/.github/copilot-instructions.md

4.8 KiB

For additional context about technologies to be used, project structure, shell commands, and other important information, read the current plan at specs/001-oidc-proxy-script/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

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 injectionserver.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)
<name> 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:

// 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:

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.