← Back to Library

@wip/proxy

lib ·  server app devs
proxyexpressclient-libraryserver-app

@wip/proxy

What it is. @wip/proxy is an Express middleware library for server app devs that proxies calls from a browser-facing app to a WIP instance's REST APIs. It injects a server-held API key into every upstream request (so the key never reaches the browser), streams file-content downloads without exposing internal MinIO URLs to the client, and forwards WIP's own responses — including errors — verbatim. It also ships a small, separate runtime app-config endpoint helper for serving client-visible per-deployment values.

Install & import. Package @wip/proxy, version 0.4.2 (package.json). The package is "private": true — it is not published to a registry; it is consumed as a workspace dependency inside the WIP monorepo (libs/wip-proxy). Primary imports:

import { wipProxy } from '@wip/proxy'
import { appConfigHandler } from '@wip/proxy'

Requires express as a peer dependency (^4.17.0 || ^5.0.0) and Node >=18 (engines.node).

Core API

wipProxy(options: WipProxyOptions): Router

import express from 'express'
import { wipProxy } from '@wip/proxy'

const app = express()
app.use('/wip', wipProxy({
  baseUrl: process.env.WIP_BASE_URL || 'https://localhost:8443',
  apiKey: process.env.WIP_API_KEY,
}))

resolveApiKey(options: WipProxyOptions): string

resolveApiKey({ baseUrl: 'x', apiKeyFile: '/run/secrets/api-key' })
// -> 'live-secret-key'   (trailing newline trimmed)

prefixPattern(prefix: string): RegExp

prefixPattern('/api/def-store').test('/api/def-store/terminologies') // -> true
prefixPattern('/api/def-store').test('/api/def-store-evil')          // -> false

WIP_API_PREFIXES: string[]

import { WIP_API_PREFIXES } from '@wip/proxy'
// e.g. to build an equivalent allowlist for a test outside the proxy itself

appConfigHandler(entries: AppConfigEntries | (() => AppConfigEntries)): (req: Request, res: Response) => void

router.get('/api/app-config', appConfigHandler({
  namespace: process.env.WIP_NAMESPACE || null,
}))
// GET /api/app-config -> 200 {"namespace": "kb"}   (Cache-Control: no-store)

Usage patterns

1. Mount the proxy and forward all API + file traffic.

import express from 'express'
import { wipProxy } from '@wip/proxy'

const app = express()
app.use('/wip', wipProxy({
  baseUrl: process.env.WIP_BASE_URL || 'https://localhost:8443',
  apiKey: process.env.WIP_API_KEY,
}))

This registers GET|POST|PUT|DELETE /wip/api/{service}/* (proxied with the API key injected) and GET /wip/files/:fileId/content (proxied file download, MinIO URLs resolved server-side). A frontend using @wip/client then points at baseUrl: '/wip' with auth: { type: 'none' }, since the proxy handles auth.

2. Scope a multi-namespace admin key.

app.use('/wip', wipProxy({
  baseUrl,
  apiKeyFile: '/path/to/secrets/api-key',
  defaultNamespace: 'dev-my-app',
}))

Any unscoped call to /api/document-store/documents/query gets ?namespace=dev-my-app appended automatically; a caller that already passed namespace= in the query string is left untouched.

3. Serve runtime app-config alongside the proxy.

import { appConfigHandler } from '@wip/proxy'

router.get('/api/app-config', appConfigHandler({
  namespace: process.env.WIP_NAMESPACE || null,
}))

The SPA fetches this once at boot instead of baking VITE_* values into the build; the response is never cached (Cache-Control: no-store) and contains only the entries explicitly passed in.

Gotchas

See also

⚠ GAP: WIP_API_PREFIXES proxies six service prefixes, including /api/ingest-gateway — but the manifest has no ingest-gateway API doc to link here. Five of six proxied services have a sibling REST-API doc in this library; ingest-gateway doesn't yet.

Generated from real source code, not hand-written — see the WIP Technical Library.