@abapify/adt-proxy 0.4.17 → 0.4.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +0 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { RouteDefinition, Serializable } from "@abapify/speci/rest";
|
|
2
|
-
//#region src/types.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* Configuration for the ADT proxy server
|
|
5
4
|
*/
|
|
@@ -52,8 +51,6 @@ interface ProxyResult {
|
|
|
52
51
|
/** Whether the response was converted from XML to JSON */
|
|
53
52
|
converted: boolean;
|
|
54
53
|
}
|
|
55
|
-
//#endregion
|
|
56
|
-
//#region src/converter.d.ts
|
|
57
54
|
/**
|
|
58
55
|
* Convert a JSON string to XML using a schema's build method.
|
|
59
56
|
*/
|
|
@@ -74,8 +71,6 @@ declare function isJsonContentType(contentType: string): boolean;
|
|
|
74
71
|
* Check if a content type indicates XML (case-insensitive).
|
|
75
72
|
*/
|
|
76
73
|
declare function isXmlContentType(contentType: string): boolean;
|
|
77
|
-
//#endregion
|
|
78
|
-
//#region src/proxy.d.ts
|
|
79
74
|
declare function createAdtProxy(config: AdtProxyConfig): {
|
|
80
75
|
readonly routes: RouteDefinition[];
|
|
81
76
|
match: (method: string, url: string, basePath?: string) => {
|
|
@@ -87,6 +82,5 @@ declare function createAdtProxy(config: AdtProxyConfig): {
|
|
|
87
82
|
}>;
|
|
88
83
|
stop(): Promise<void>;
|
|
89
84
|
};
|
|
90
|
-
//#endregion
|
|
91
85
|
export { type AdtProxyConfig, type Logger, type ProxyResult, createAdtProxy, detectContentType, isJsonContentType, isXmlContentType, jsonToXml, xmlToJson };
|
|
92
86
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/converter.ts","../src/proxy.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/converter.ts","../src/proxy.ts"],"mappings":";;;;UASiB;;EAEf;;EAGA;;EAGA;;EAGA;IACE;IACA;;IAEA;;;EAIF;;EAGA;;EAGA;;EAGA,iBAAiB;;EAGjB;;EAGA,SAAS;;;;;UAMM;EACf,MAAM,aAAa;EACnB,KAAK,aAAa;EAClB,KAAK,aAAa;EAClB,MAAM,aAAa;;;;;UA0BJ;;EAEf;;EAGA,SAAS;;EAGT;;EAGA;;;;;iBC9Ec,UAAU,cAAc,QAAQ;;;;iBAehC,UAAU,aAAa,QAAQ;;;;iBAY/B,kBACd,iBACA;;;;iBAmBc,kBAAkB;;;;iBAQlB,iBAAiB;iBCuGjB,eAAe,QAAQ;;;;;;EAuQpB,SAAA;IAAU;;EAgCX,QAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { createServer } from "node:http";
|
|
|
2
2
|
import { createServer as createServer$1 } from "@abapify/speci/rest";
|
|
3
3
|
import { adtContract } from "@abapify/adt-contracts";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// src/converter.ts
|
|
6
6
|
/**
|
|
7
7
|
* Convert a JSON string to XML using a schema's build method.
|
|
8
8
|
*/
|
|
@@ -57,8 +57,7 @@ function isXmlContentType(contentType) {
|
|
|
57
57
|
return ct.includes("xml") || ct.endsWith("+xml");
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
//#region src/proxy.ts
|
|
60
|
+
// src/proxy.ts
|
|
62
61
|
/**
|
|
63
62
|
* ADT Proxy Server
|
|
64
63
|
*
|
|
@@ -320,6 +319,5 @@ function createAdtProxy(config) {
|
|
|
320
319
|
};
|
|
321
320
|
}
|
|
322
321
|
|
|
323
|
-
//#endregion
|
|
324
322
|
export { createAdtProxy, detectContentType, isJsonContentType, isXmlContentType, jsonToXml, xmlToJson };
|
|
325
323
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["createServer","httpCreateServer"],"sources":["../src/converter.ts","../src/proxy.ts"],"sourcesContent":["/**\n * ADT Proxy Server - Content Conversion\n *\n * Handles JSON↔XML conversion using schema parse/build methods.\n * This is the core of the proxy's content negotiation.\n */\n\nimport type { Serializable } from '@abapify/speci/rest';\n\n/**\n * Convert a JSON string to XML using a schema's build method.\n */\nexport function jsonToXml(json: string, schema: Serializable): string {\n try {\n const data = JSON.parse(json);\n if (typeof schema.build === 'function') {\n return schema.build(data);\n }\n return json;\n } catch {\n return json;\n }\n}\n\n/**\n * Convert an XML string to JSON using a schema's parse method.\n */\nexport function xmlToJson(xml: string, schema: Serializable): string {\n try {\n const data = schema.parse(xml);\n return JSON.stringify(data);\n } catch {\n return xml;\n }\n}\n\n/**\n * Detect content type from a string or content-type header.\n */\nexport function detectContentType(\n content: string,\n contentType?: string,\n): 'json' | 'xml' | 'text' | 'binary' {\n if (contentType) {\n const ct = contentType.toLowerCase();\n if (ct.includes('json')) return 'json';\n if (ct.includes('xml')) return 'xml';\n if (ct.includes('text')) return 'text';\n return 'binary';\n }\n\n const trimmed = content.trimStart();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) return 'json';\n if (trimmed.startsWith('<?xml') || trimmed.startsWith('<')) return 'xml';\n return 'text';\n}\n\n/**\n * Check if a content type indicates JSON (case-insensitive).\n */\nexport function isJsonContentType(contentType: string): boolean {\n const ct = contentType.toLowerCase();\n return ct.includes('json') || ct.endsWith('+json');\n}\n\n/**\n * Check if a content type indicates XML (case-insensitive).\n */\nexport function isXmlContentType(contentType: string): boolean {\n const ct = contentType.toLowerCase();\n return ct.includes('xml') || ct.endsWith('+xml');\n}\n","/**\n * ADT Proxy Server\n *\n * Proxies ADT endpoint requests to a downstream SAP system with\n * automatic JSON↔XML conversion using contract schemas.\n *\n * Architecture:\n * Client (JSON) → Proxy → Downstream SAP (XML)\n * Client (JSON) ← Proxy ← Downstream SAP (XML)\n *\n * The proxy uses speci's createServer to extract route definitions\n * from ADT contracts, enabling schema-aware content conversion.\n *\n * @example\n * ```typescript\n * import { createAdtProxy } from '@abapify/adt-proxy';\n *\n * const proxy = createAdtProxy({\n * targetUrl: 'https://my-sap-system.com:8000',\n * auth: { username: 'user', password: 'pass', client: '100' },\n * });\n *\n * const { port } = await proxy.start();\n * console.log(`Proxy running on http://localhost:${port}`);\n * ```\n */\n\nimport { createServer as httpCreateServer, type Server } from 'node:http';\nimport { createServer } from '@abapify/speci/rest';\nimport { adtContract, type AdtContract } from '@abapify/adt-contracts';\nimport type { RouteDefinition } from '@abapify/speci/rest';\nimport {\n jsonToXml,\n xmlToJson,\n isJsonContentType,\n isXmlContentType,\n} from './converter';\nimport type { AdtProxyConfig, ProxyResult, Logger } from './types';\n\nconst DEFAULT_LOGGER: Logger = {\n debug: (_msg: string) => {\n /* noop */\n },\n info: (_msg: string) => {\n /* noop */\n },\n warn: console.warn,\n error: console.error,\n};\n\nconst FORWARDABLE_REQUEST_HEADERS = [\n 'accept',\n 'content-type',\n 'x-csrf-token',\n 'x-sap-security-session',\n 'x-sap-adt-sessiontype',\n 'cookie',\n];\n\nconst FORWARDABLE_RESPONSE_HEADERS = [\n 'content-type',\n 'x-csrf-token',\n 'x-sap-security-session',\n 'set-cookie',\n 'etag',\n 'location',\n];\n\nfunction forwardHeaders(\n source: Record<string, string | string[] | undefined>,\n target: Record<string, string | string[]>,\n keys: string[],\n): void {\n for (const h of keys) {\n const value = source[h];\n if (value && !target[h]) {\n target[h] = value;\n }\n }\n}\n\nfunction addAuthHeaders(\n headers: Record<string, string>,\n auth?: AdtProxyConfig['auth'],\n): void {\n if (!auth) return;\n if (!headers.authorization) {\n const creds = Buffer.from(`${auth.username}:${auth.password}`).toString(\n 'base64',\n );\n headers.authorization = `Basic ${creds}`;\n }\n if (auth.client && !headers['sap-client']) {\n headers['sap-client'] = auth.client;\n }\n}\n\nfunction convertRequestBody(\n body: string,\n contentType: string | undefined,\n bodySchema?: RouteDefinition['bodySchema'],\n): { body: string; converted: boolean } {\n if (!body || !bodySchema || !contentType) {\n return { body, converted: false };\n }\n if (!isJsonContentType(contentType)) {\n return { body, converted: false };\n }\n return { body: jsonToXml(body, bodySchema), converted: true };\n}\n\nfunction convertResponseBody(\n body: string,\n contentType: string,\n status: number,\n responseSchemas: RouteDefinition['responseSchemas'],\n): { body: string; converted: boolean } {\n if (!body || !isXmlContentType(contentType) || !responseSchemas[status]) {\n return { body, converted: false };\n }\n const converted = xmlToJson(body, responseSchemas[status]);\n const wasConverted = converted !== body;\n return { body: converted, converted: wasConverted };\n}\n\nasync function forwardRequest(\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: string,\n timeoutMs = 30_000,\n): Promise<{\n status: number;\n headers: Record<string, string | string[]>;\n body: string;\n}> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: body || undefined,\n signal: controller.signal,\n });\n\n const responseBody = await response.text();\n const responseHeaders: Record<string, string | string[]> = {};\n response.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'set-cookie') return;\n responseHeaders[key] = value;\n });\n\n if (typeof response.headers.getSetCookie === 'function') {\n const setCookies = response.headers.getSetCookie();\n if (setCookies.length > 0) {\n responseHeaders['set-cookie'] = setCookies;\n }\n }\n\n return {\n status: response.status,\n headers: responseHeaders,\n body: responseBody,\n };\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport function createAdtProxy(config: AdtProxyConfig) {\n const {\n targetUrl,\n auth,\n basePath = '',\n forwardUnknown = true,\n convertContent = true,\n defaultHeaders = {},\n logger = DEFAULT_LOGGER,\n } = config;\n\n const contractRoutes = createServer(adtContract as AdtContract);\n let server: Server | undefined;\n\n function buildDownstreamHeaders(\n incomingHeaders: Record<string, string | string[] | undefined>,\n contractHeaders?: Record<string, string>,\n ): Record<string, string> {\n const headers: Record<string, string> = {\n ...defaultHeaders,\n ...contractHeaders,\n };\n forwardHeaders(incomingHeaders, headers, FORWARDABLE_REQUEST_HEADERS);\n addAuthHeaders(headers, auth);\n if (convertContent && !headers.accept) {\n headers.accept = 'application/json';\n }\n return headers;\n }\n\n function buildDownstreamUrl(url: string): string {\n const relativePath =\n basePath && url.startsWith(basePath)\n ? url.slice(basePath.length) || '/'\n : url;\n return `${targetUrl}${relativePath}`;\n }\n\n function getContentType(\n headers: Record<string, string | string[] | undefined>,\n ): string | undefined {\n const ct = headers['content-type'];\n return Array.isArray(ct) ? ct[0] : ct;\n }\n\n async function handleMatchedRoute(\n method: string,\n url: string,\n requestBody: string,\n incomingHeaders: Record<string, string | string[] | undefined>,\n route: RouteDefinition,\n ): Promise<ProxyResult> {\n logger.info(`Matched route: ${route.method} ${route.pathTemplate}`);\n\n const reqContentType = getContentType(incomingHeaders);\n const { body: downstreamBody, converted: reqConverted } =\n convertRequestBody(requestBody, reqContentType, route.bodySchema);\n\n const downstreamHeaders = buildDownstreamHeaders(\n incomingHeaders,\n route.requestHeaders,\n );\n if (reqConverted) {\n downstreamHeaders['content-type'] = 'application/xml';\n }\n\n const response = await forwardRequest(\n method,\n buildDownstreamUrl(url),\n downstreamHeaders,\n downstreamBody,\n );\n\n const respContentType = Array.isArray(response.headers['content-type'])\n ? response.headers['content-type'][0]\n : response.headers['content-type'] || '';\n const { body: responseBody, converted: respConverted } =\n convertResponseBody(\n response.body,\n respContentType,\n response.status,\n route.responseSchemas,\n );\n\n return {\n status: response.status,\n headers: response.headers,\n body: responseBody,\n converted: respConverted,\n };\n }\n\n async function handleForwardedRequest(\n method: string,\n url: string,\n requestBody: string,\n incomingHeaders: Record<string, string | string[] | undefined>,\n ): Promise<ProxyResult> {\n logger.debug(`No route match for ${method} ${url} - forwarding as-is`);\n\n const downstreamHeaders = buildDownstreamHeaders(incomingHeaders);\n const response = await forwardRequest(\n method,\n buildDownstreamUrl(url),\n downstreamHeaders,\n requestBody,\n );\n\n return {\n status: response.status,\n headers: response.headers,\n body: response.body,\n converted: false,\n };\n }\n\n function sendNotFound(\n res: {\n writeHead: (\n status: number,\n headers: Record<string, string | string[]>,\n ) => void;\n end: (body?: string) => void;\n },\n method: string,\n url: string,\n ): void {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'Not Found',\n message: `No contract route matched for ${method} ${url}`,\n availableRoutes: contractRoutes.routes.map((r) => ({\n method: r.method,\n path: r.pathTemplate,\n })),\n }),\n );\n }\n\n function sendResponse(\n res: {\n writeHead: (\n status: number,\n headers: Record<string, string | string[]>,\n ) => void;\n end: (body?: string) => void;\n },\n result: ProxyResult,\n ): void {\n const responseHeaders: Record<string, string | string[]> = {\n 'x-proxy': 'adt-proxy',\n };\n forwardHeaders(\n result.headers,\n responseHeaders,\n FORWARDABLE_RESPONSE_HEADERS,\n );\n\n if (result.converted) {\n responseHeaders['content-type'] = 'application/json';\n }\n\n res.writeHead(result.status, responseHeaders);\n res.end(result.body);\n }\n\n async function readBody(\n req: {\n on: (event: string, cb: (...args: any[]) => void) => void;\n },\n maxSize = 10 * 1024 * 1024,\n ): Promise<string> {\n return new Promise((resolve, reject) => {\n let size = 0;\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => {\n size += chunk.length;\n if (size > maxSize) {\n reject(new Error(`Request body exceeds ${maxSize} byte limit`));\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => resolve(Buffer.concat(chunks).toString()));\n req.on('error', (err: Error) => reject(err));\n });\n }\n\n async function handleRequest(\n req: {\n method?: string;\n url?: string;\n headers: Record<string, string | string[] | undefined>;\n on: (event: string, cb: (chunk: any) => void) => void;\n },\n res: {\n writeHead: (\n status: number,\n headers: Record<string, string | string[]>,\n ) => void;\n end: (body?: string) => void;\n },\n ): Promise<void> {\n const method = req.method || 'GET';\n const url = req.url || '/';\n logger.info(`${method} ${url}`);\n\n const requestBody = await readBody(req);\n const match = contractRoutes.match(method, url, basePath);\n\n if (match && convertContent) {\n const result = await handleMatchedRoute(\n method,\n url,\n requestBody,\n req.headers,\n match.route,\n );\n sendResponse(res, result);\n return;\n }\n\n if (match) {\n const downstreamHeaders = buildDownstreamHeaders(\n req.headers,\n match.route.requestHeaders,\n );\n const response = await forwardRequest(\n method,\n buildDownstreamUrl(url),\n downstreamHeaders,\n requestBody,\n );\n sendResponse(res, {\n status: response.status,\n headers: response.headers,\n body: response.body,\n converted: false,\n });\n return;\n }\n\n if (forwardUnknown) {\n const result = await handleForwardedRequest(\n method,\n url,\n requestBody,\n req.headers,\n );\n sendResponse(res, result);\n return;\n }\n\n sendNotFound(res, method, url);\n }\n\n return {\n get routes() {\n return contractRoutes.routes;\n },\n match: contractRoutes.match,\n\n async start(): Promise<{ port: number }> {\n return new Promise((resolve, reject) => {\n server = httpCreateServer((req, res) => {\n handleRequest(req, res).catch((err) => {\n logger.error('Request handling error', { error: err.message });\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'Internal Server Error',\n message: err.message,\n }),\n );\n });\n });\n\n server.on('error', reject);\n\n server.listen(config.port || 0, config.host || '127.0.0.1', () => {\n const addr = server?.address();\n if (!addr || typeof addr !== 'object') {\n reject(new Error('Failed to get server address'));\n return;\n }\n logger.info(\n `ADT proxy listening on http://${config.host || '127.0.0.1'}:${addr.port}`,\n );\n logger.info(`Proxying to ${targetUrl}`);\n resolve({ port: addr.port });\n });\n });\n },\n\n async stop(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!server) return resolve();\n server.close((err) => (err ? reject(err) : resolve()));\n });\n },\n };\n}\n\nexport { createServer } from '@abapify/speci/rest';\nexport type { AdtProxyConfig, ProxyResult, Logger } from './types';\nexport {\n jsonToXml,\n xmlToJson,\n detectContentType,\n isJsonContentType,\n isXmlContentType,\n} from './converter';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["createServer","httpCreateServer"],"sources":["../src/converter.ts","../src/proxy.ts"],"sourcesContent":["/**\n * ADT Proxy Server - Content Conversion\n *\n * Handles JSON↔XML conversion using schema parse/build methods.\n * This is the core of the proxy's content negotiation.\n */\n\nimport type { Serializable } from '@abapify/speci/rest';\n\n/**\n * Convert a JSON string to XML using a schema's build method.\n */\nexport function jsonToXml(json: string, schema: Serializable): string {\n try {\n const data = JSON.parse(json);\n if (typeof schema.build === 'function') {\n return schema.build(data);\n }\n return json;\n } catch {\n return json;\n }\n}\n\n/**\n * Convert an XML string to JSON using a schema's parse method.\n */\nexport function xmlToJson(xml: string, schema: Serializable): string {\n try {\n const data = schema.parse(xml);\n return JSON.stringify(data);\n } catch {\n return xml;\n }\n}\n\n/**\n * Detect content type from a string or content-type header.\n */\nexport function detectContentType(\n content: string,\n contentType?: string,\n): 'json' | 'xml' | 'text' | 'binary' {\n if (contentType) {\n const ct = contentType.toLowerCase();\n if (ct.includes('json')) return 'json';\n if (ct.includes('xml')) return 'xml';\n if (ct.includes('text')) return 'text';\n return 'binary';\n }\n\n const trimmed = content.trimStart();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) return 'json';\n if (trimmed.startsWith('<?xml') || trimmed.startsWith('<')) return 'xml';\n return 'text';\n}\n\n/**\n * Check if a content type indicates JSON (case-insensitive).\n */\nexport function isJsonContentType(contentType: string): boolean {\n const ct = contentType.toLowerCase();\n return ct.includes('json') || ct.endsWith('+json');\n}\n\n/**\n * Check if a content type indicates XML (case-insensitive).\n */\nexport function isXmlContentType(contentType: string): boolean {\n const ct = contentType.toLowerCase();\n return ct.includes('xml') || ct.endsWith('+xml');\n}\n","/**\n * ADT Proxy Server\n *\n * Proxies ADT endpoint requests to a downstream SAP system with\n * automatic JSON↔XML conversion using contract schemas.\n *\n * Architecture:\n * Client (JSON) → Proxy → Downstream SAP (XML)\n * Client (JSON) ← Proxy ← Downstream SAP (XML)\n *\n * The proxy uses speci's createServer to extract route definitions\n * from ADT contracts, enabling schema-aware content conversion.\n *\n * @example\n * ```typescript\n * import { createAdtProxy } from '@abapify/adt-proxy';\n *\n * const proxy = createAdtProxy({\n * targetUrl: 'https://my-sap-system.com:8000',\n * auth: { username: 'user', password: 'pass', client: '100' },\n * });\n *\n * const { port } = await proxy.start();\n * console.log(`Proxy running on http://localhost:${port}`);\n * ```\n */\n\nimport { createServer as httpCreateServer, type Server } from 'node:http';\nimport { createServer } from '@abapify/speci/rest';\nimport { adtContract, type AdtContract } from '@abapify/adt-contracts';\nimport type { RouteDefinition } from '@abapify/speci/rest';\nimport {\n jsonToXml,\n xmlToJson,\n isJsonContentType,\n isXmlContentType,\n} from './converter';\nimport type { AdtProxyConfig, ProxyResult, Logger } from './types';\n\nconst DEFAULT_LOGGER: Logger = {\n debug: (_msg: string) => {\n /* noop */\n },\n info: (_msg: string) => {\n /* noop */\n },\n warn: console.warn,\n error: console.error,\n};\n\nconst FORWARDABLE_REQUEST_HEADERS = [\n 'accept',\n 'content-type',\n 'x-csrf-token',\n 'x-sap-security-session',\n 'x-sap-adt-sessiontype',\n 'cookie',\n];\n\nconst FORWARDABLE_RESPONSE_HEADERS = [\n 'content-type',\n 'x-csrf-token',\n 'x-sap-security-session',\n 'set-cookie',\n 'etag',\n 'location',\n];\n\nfunction forwardHeaders(\n source: Record<string, string | string[] | undefined>,\n target: Record<string, string | string[]>,\n keys: string[],\n): void {\n for (const h of keys) {\n const value = source[h];\n if (value && !target[h]) {\n target[h] = value;\n }\n }\n}\n\nfunction addAuthHeaders(\n headers: Record<string, string>,\n auth?: AdtProxyConfig['auth'],\n): void {\n if (!auth) return;\n if (!headers.authorization) {\n const creds = Buffer.from(`${auth.username}:${auth.password}`).toString(\n 'base64',\n );\n headers.authorization = `Basic ${creds}`;\n }\n if (auth.client && !headers['sap-client']) {\n headers['sap-client'] = auth.client;\n }\n}\n\nfunction convertRequestBody(\n body: string,\n contentType: string | undefined,\n bodySchema?: RouteDefinition['bodySchema'],\n): { body: string; converted: boolean } {\n if (!body || !bodySchema || !contentType) {\n return { body, converted: false };\n }\n if (!isJsonContentType(contentType)) {\n return { body, converted: false };\n }\n return { body: jsonToXml(body, bodySchema), converted: true };\n}\n\nfunction convertResponseBody(\n body: string,\n contentType: string,\n status: number,\n responseSchemas: RouteDefinition['responseSchemas'],\n): { body: string; converted: boolean } {\n if (!body || !isXmlContentType(contentType) || !responseSchemas[status]) {\n return { body, converted: false };\n }\n const converted = xmlToJson(body, responseSchemas[status]);\n const wasConverted = converted !== body;\n return { body: converted, converted: wasConverted };\n}\n\nasync function forwardRequest(\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: string,\n timeoutMs = 30_000,\n): Promise<{\n status: number;\n headers: Record<string, string | string[]>;\n body: string;\n}> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: body || undefined,\n signal: controller.signal,\n });\n\n const responseBody = await response.text();\n const responseHeaders: Record<string, string | string[]> = {};\n response.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'set-cookie') return;\n responseHeaders[key] = value;\n });\n\n if (typeof response.headers.getSetCookie === 'function') {\n const setCookies = response.headers.getSetCookie();\n if (setCookies.length > 0) {\n responseHeaders['set-cookie'] = setCookies;\n }\n }\n\n return {\n status: response.status,\n headers: responseHeaders,\n body: responseBody,\n };\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport function createAdtProxy(config: AdtProxyConfig) {\n const {\n targetUrl,\n auth,\n basePath = '',\n forwardUnknown = true,\n convertContent = true,\n defaultHeaders = {},\n logger = DEFAULT_LOGGER,\n } = config;\n\n const contractRoutes = createServer(adtContract as AdtContract);\n let server: Server | undefined;\n\n function buildDownstreamHeaders(\n incomingHeaders: Record<string, string | string[] | undefined>,\n contractHeaders?: Record<string, string>,\n ): Record<string, string> {\n const headers: Record<string, string> = {\n ...defaultHeaders,\n ...contractHeaders,\n };\n forwardHeaders(incomingHeaders, headers, FORWARDABLE_REQUEST_HEADERS);\n addAuthHeaders(headers, auth);\n if (convertContent && !headers.accept) {\n headers.accept = 'application/json';\n }\n return headers;\n }\n\n function buildDownstreamUrl(url: string): string {\n const relativePath =\n basePath && url.startsWith(basePath)\n ? url.slice(basePath.length) || '/'\n : url;\n return `${targetUrl}${relativePath}`;\n }\n\n function getContentType(\n headers: Record<string, string | string[] | undefined>,\n ): string | undefined {\n const ct = headers['content-type'];\n return Array.isArray(ct) ? ct[0] : ct;\n }\n\n async function handleMatchedRoute(\n method: string,\n url: string,\n requestBody: string,\n incomingHeaders: Record<string, string | string[] | undefined>,\n route: RouteDefinition,\n ): Promise<ProxyResult> {\n logger.info(`Matched route: ${route.method} ${route.pathTemplate}`);\n\n const reqContentType = getContentType(incomingHeaders);\n const { body: downstreamBody, converted: reqConverted } =\n convertRequestBody(requestBody, reqContentType, route.bodySchema);\n\n const downstreamHeaders = buildDownstreamHeaders(\n incomingHeaders,\n route.requestHeaders,\n );\n if (reqConverted) {\n downstreamHeaders['content-type'] = 'application/xml';\n }\n\n const response = await forwardRequest(\n method,\n buildDownstreamUrl(url),\n downstreamHeaders,\n downstreamBody,\n );\n\n const respContentType = Array.isArray(response.headers['content-type'])\n ? response.headers['content-type'][0]\n : response.headers['content-type'] || '';\n const { body: responseBody, converted: respConverted } =\n convertResponseBody(\n response.body,\n respContentType,\n response.status,\n route.responseSchemas,\n );\n\n return {\n status: response.status,\n headers: response.headers,\n body: responseBody,\n converted: respConverted,\n };\n }\n\n async function handleForwardedRequest(\n method: string,\n url: string,\n requestBody: string,\n incomingHeaders: Record<string, string | string[] | undefined>,\n ): Promise<ProxyResult> {\n logger.debug(`No route match for ${method} ${url} - forwarding as-is`);\n\n const downstreamHeaders = buildDownstreamHeaders(incomingHeaders);\n const response = await forwardRequest(\n method,\n buildDownstreamUrl(url),\n downstreamHeaders,\n requestBody,\n );\n\n return {\n status: response.status,\n headers: response.headers,\n body: response.body,\n converted: false,\n };\n }\n\n function sendNotFound(\n res: {\n writeHead: (\n status: number,\n headers: Record<string, string | string[]>,\n ) => void;\n end: (body?: string) => void;\n },\n method: string,\n url: string,\n ): void {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'Not Found',\n message: `No contract route matched for ${method} ${url}`,\n availableRoutes: contractRoutes.routes.map((r) => ({\n method: r.method,\n path: r.pathTemplate,\n })),\n }),\n );\n }\n\n function sendResponse(\n res: {\n writeHead: (\n status: number,\n headers: Record<string, string | string[]>,\n ) => void;\n end: (body?: string) => void;\n },\n result: ProxyResult,\n ): void {\n const responseHeaders: Record<string, string | string[]> = {\n 'x-proxy': 'adt-proxy',\n };\n forwardHeaders(\n result.headers,\n responseHeaders,\n FORWARDABLE_RESPONSE_HEADERS,\n );\n\n if (result.converted) {\n responseHeaders['content-type'] = 'application/json';\n }\n\n res.writeHead(result.status, responseHeaders);\n res.end(result.body);\n }\n\n async function readBody(\n req: {\n on: (event: string, cb: (...args: any[]) => void) => void;\n },\n maxSize = 10 * 1024 * 1024,\n ): Promise<string> {\n return new Promise((resolve, reject) => {\n let size = 0;\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => {\n size += chunk.length;\n if (size > maxSize) {\n reject(new Error(`Request body exceeds ${maxSize} byte limit`));\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => resolve(Buffer.concat(chunks).toString()));\n req.on('error', (err: Error) => reject(err));\n });\n }\n\n async function handleRequest(\n req: {\n method?: string;\n url?: string;\n headers: Record<string, string | string[] | undefined>;\n on: (event: string, cb: (chunk: any) => void) => void;\n },\n res: {\n writeHead: (\n status: number,\n headers: Record<string, string | string[]>,\n ) => void;\n end: (body?: string) => void;\n },\n ): Promise<void> {\n const method = req.method || 'GET';\n const url = req.url || '/';\n logger.info(`${method} ${url}`);\n\n const requestBody = await readBody(req);\n const match = contractRoutes.match(method, url, basePath);\n\n if (match && convertContent) {\n const result = await handleMatchedRoute(\n method,\n url,\n requestBody,\n req.headers,\n match.route,\n );\n sendResponse(res, result);\n return;\n }\n\n if (match) {\n const downstreamHeaders = buildDownstreamHeaders(\n req.headers,\n match.route.requestHeaders,\n );\n const response = await forwardRequest(\n method,\n buildDownstreamUrl(url),\n downstreamHeaders,\n requestBody,\n );\n sendResponse(res, {\n status: response.status,\n headers: response.headers,\n body: response.body,\n converted: false,\n });\n return;\n }\n\n if (forwardUnknown) {\n const result = await handleForwardedRequest(\n method,\n url,\n requestBody,\n req.headers,\n );\n sendResponse(res, result);\n return;\n }\n\n sendNotFound(res, method, url);\n }\n\n return {\n get routes() {\n return contractRoutes.routes;\n },\n match: contractRoutes.match,\n\n async start(): Promise<{ port: number }> {\n return new Promise((resolve, reject) => {\n server = httpCreateServer((req, res) => {\n handleRequest(req, res).catch((err) => {\n logger.error('Request handling error', { error: err.message });\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'Internal Server Error',\n message: err.message,\n }),\n );\n });\n });\n\n server.on('error', reject);\n\n server.listen(config.port || 0, config.host || '127.0.0.1', () => {\n const addr = server?.address();\n if (!addr || typeof addr !== 'object') {\n reject(new Error('Failed to get server address'));\n return;\n }\n logger.info(\n `ADT proxy listening on http://${config.host || '127.0.0.1'}:${addr.port}`,\n );\n logger.info(`Proxying to ${targetUrl}`);\n resolve({ port: addr.port });\n });\n });\n },\n\n async stop(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!server) return resolve();\n server.close((err) => (err ? reject(err) : resolve()));\n });\n },\n };\n}\n\nexport { createServer } from '@abapify/speci/rest';\nexport type { AdtProxyConfig, ProxyResult, Logger } from './types';\nexport {\n jsonToXml,\n xmlToJson,\n detectContentType,\n isJsonContentType,\n isXmlContentType,\n} from './converter';\n"],"mappings":";;;;;;;;AAYA,SAAgB,UAAU,MAAc,QAA8B;CACpE,IAAI;EACF,MAAM,OAAO,KAAK,MAAM,IAAI;EAC5B,IAAI,OAAO,OAAO,UAAU,YAC1B,OAAO,OAAO,MAAM,IAAI;EAE1B,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,SAAgB,UAAU,KAAa,QAA8B;CACnE,IAAI;EACF,MAAM,OAAO,OAAO,MAAM,GAAG;EAC7B,OAAO,KAAK,UAAU,IAAI;CAC5B,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,SAAgB,kBACd,SACA,aACoC;CACpC,IAAI,aAAa;EACf,MAAM,KAAK,YAAY,YAAY;EACnC,IAAI,GAAG,SAAS,MAAM,GAAG,OAAO;EAChC,IAAI,GAAG,SAAS,KAAK,GAAG,OAAO;EAC/B,IAAI,GAAG,SAAS,MAAM,GAAG,OAAO;EAChC,OAAO;CACT;CAEA,MAAM,UAAU,QAAQ,UAAU;CAClC,IAAI,QAAQ,WAAW,GAAG,KAAK,QAAQ,WAAW,GAAG,GAAG,OAAO;CAC/D,IAAI,QAAQ,WAAW,OAAO,KAAK,QAAQ,WAAW,GAAG,GAAG,OAAO;CACnE,OAAO;AACT;;;;AAKA,SAAgB,kBAAkB,aAA8B;CAC9D,MAAM,KAAK,YAAY,YAAY;CACnC,OAAO,GAAG,SAAS,MAAM,KAAK,GAAG,SAAS,OAAO;AACnD;;;;AAKA,SAAgB,iBAAiB,aAA8B;CAC7D,MAAM,KAAK,YAAY,YAAY;CACnC,OAAO,GAAG,SAAS,KAAK,KAAK,GAAG,SAAS,MAAM;AACjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChCA,MAAM,iBAAyB;CAC7B,QAAQ,SAAiB,CAEzB;CACA,OAAO,SAAiB,CAExB;CACA,MAAM,QAAQ;CACd,OAAO,QAAQ;AACjB;AAEA,MAAM,8BAA8B;CAClC;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,+BAA+B;CACnC;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,SAAS,eACP,QACA,QACA,MACM;CACN,KAAK,MAAM,KAAK,MAAM;EACpB,MAAM,QAAQ,OAAO;EACrB,IAAI,SAAS,CAAC,OAAO,IACnB,OAAO,KAAK;CAEhB;AACF;AAEA,SAAS,eACP,SACA,MACM;CACN,IAAI,CAAC,MAAM;CACX,IAAI,CAAC,QAAQ,eAIX,QAAQ,gBAAgB,SAHV,OAAO,KAAK,GAAG,KAAK,SAAS,GAAG,KAAK,UAAU,CAAC,CAAC,SAC7D,QAEmC;CAEvC,IAAI,KAAK,UAAU,CAAC,QAAQ,eAC1B,QAAQ,gBAAgB,KAAK;AAEjC;AAEA,SAAS,mBACP,MACA,aACA,YACsC;CACtC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,aAC3B,OAAO;EAAE;EAAM,WAAW;CAAM;CAElC,IAAI,CAAC,kBAAkB,WAAW,GAChC,OAAO;EAAE;EAAM,WAAW;CAAM;CAElC,OAAO;EAAE,MAAM,UAAU,MAAM,UAAU;EAAG,WAAW;CAAK;AAC9D;AAEA,SAAS,oBACP,MACA,aACA,QACA,iBACsC;CACtC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,WAAW,KAAK,CAAC,gBAAgB,SAC9D,OAAO;EAAE;EAAM,WAAW;CAAM;CAElC,MAAM,YAAY,UAAU,MAAM,gBAAgB,OAAO;CAEzD,OAAO;EAAE,MAAM;EAAW,WADL,cAAc;CACe;AACpD;AAEA,eAAe,eACb,QACA,KACA,SACA,MACA,YAAY,KAKX;CACD,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,QAAQ,iBAAiB,WAAW,MAAM,GAAG,SAAS;CAE5D,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC;GACA;GACA,MAAM,QAAQ;GACd,QAAQ,WAAW;EACrB,CAAC;EAED,MAAM,eAAe,MAAM,SAAS,KAAK;EACzC,MAAM,kBAAqD,CAAC;EAC5D,SAAS,QAAQ,SAAS,OAAO,QAAQ;GACvC,IAAI,IAAI,YAAY,MAAM,cAAc;GACxC,gBAAgB,OAAO;EACzB,CAAC;EAED,IAAI,OAAO,SAAS,QAAQ,iBAAiB,YAAY;GACvD,MAAM,aAAa,SAAS,QAAQ,aAAa;GACjD,IAAI,WAAW,SAAS,GACtB,gBAAgB,gBAAgB;EAEpC;EAEA,OAAO;GACL,QAAQ,SAAS;GACjB,SAAS;GACT,MAAM;EACR;CACF,UAAU;EACR,aAAa,KAAK;CACpB;AACF;AAEA,SAAgB,eAAe,QAAwB;CACrD,MAAM,EACJ,WACA,MACA,WAAW,IACX,iBAAiB,MACjB,iBAAiB,MACjB,iBAAiB,CAAC,GAClB,SAAS,mBACP;CAEJ,MAAM,iBAAiBA,eAAa,WAA0B;CAC9D,IAAI;CAEJ,SAAS,uBACP,iBACA,iBACwB;EACxB,MAAM,UAAkC;GACtC,GAAG;GACH,GAAG;EACL;EACA,eAAe,iBAAiB,SAAS,2BAA2B;EACpE,eAAe,SAAS,IAAI;EAC5B,IAAI,kBAAkB,CAAC,QAAQ,QAC7B,QAAQ,SAAS;EAEnB,OAAO;CACT;CAEA,SAAS,mBAAmB,KAAqB;EAC/C,MAAM,eACJ,YAAY,IAAI,WAAW,QAAQ,IAC/B,IAAI,MAAM,SAAS,MAAM,KAAK,MAC9B;EACN,OAAO,GAAG,YAAY;CACxB;CAEA,SAAS,eACP,SACoB;EACpB,MAAM,KAAK,QAAQ;EACnB,OAAO,MAAM,QAAQ,EAAE,IAAI,GAAG,KAAK;CACrC;CAEA,eAAe,mBACb,QACA,KACA,aACA,iBACA,OACsB;EACtB,OAAO,KAAK,kBAAkB,MAAM,OAAO,GAAG,MAAM,cAAc;EAGlE,MAAM,EAAE,MAAM,gBAAgB,WAAW,iBACvC,mBAAmB,aAFE,eAAe,eAES,GAAG,MAAM,UAAU;EAElE,MAAM,oBAAoB,uBACxB,iBACA,MAAM,cACR;EACA,IAAI,cACF,kBAAkB,kBAAkB;EAGtC,MAAM,WAAW,MAAM,eACrB,QACA,mBAAmB,GAAG,GACtB,mBACA,cACF;EAEA,MAAM,kBAAkB,MAAM,QAAQ,SAAS,QAAQ,eAAe,IAClE,SAAS,QAAQ,eAAe,CAAC,KACjC,SAAS,QAAQ,mBAAmB;EACxC,MAAM,EAAE,MAAM,cAAc,WAAW,kBACrC,oBACE,SAAS,MACT,iBACA,SAAS,QACT,MAAM,eACR;EAEF,OAAO;GACL,QAAQ,SAAS;GACjB,SAAS,SAAS;GAClB,MAAM;GACN,WAAW;EACb;CACF;CAEA,eAAe,uBACb,QACA,KACA,aACA,iBACsB;EACtB,OAAO,MAAM,sBAAsB,OAAO,GAAG,IAAI,oBAAoB;EAErE,MAAM,oBAAoB,uBAAuB,eAAe;EAChE,MAAM,WAAW,MAAM,eACrB,QACA,mBAAmB,GAAG,GACtB,mBACA,WACF;EAEA,OAAO;GACL,QAAQ,SAAS;GACjB,SAAS,SAAS;GAClB,MAAM,SAAS;GACf,WAAW;EACb;CACF;CAEA,SAAS,aACP,KAOA,QACA,KACM;EACN,IAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;EACzD,IAAI,IACF,KAAK,UAAU;GACb,OAAO;GACP,SAAS,iCAAiC,OAAO,GAAG;GACpD,iBAAiB,eAAe,OAAO,KAAK,OAAO;IACjD,QAAQ,EAAE;IACV,MAAM,EAAE;GACV,EAAE;EACJ,CAAC,CACH;CACF;CAEA,SAAS,aACP,KAOA,QACM;EACN,MAAM,kBAAqD,EACzD,WAAW,YACb;EACA,eACE,OAAO,SACP,iBACA,4BACF;EAEA,IAAI,OAAO,WACT,gBAAgB,kBAAkB;EAGpC,IAAI,UAAU,OAAO,QAAQ,eAAe;EAC5C,IAAI,IAAI,OAAO,IAAI;CACrB;CAEA,eAAe,SACb,KAGA,UAAU,UACO;EACjB,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,IAAI,OAAO;GACX,MAAM,SAAmB,CAAC;GAC1B,IAAI,GAAG,SAAS,UAAkB;IAChC,QAAQ,MAAM;IACd,IAAI,OAAO,SAAS;KAClB,uBAAO,IAAI,MAAM,wBAAwB,QAAQ,YAAY,CAAC;KAC9D;IACF;IACA,OAAO,KAAK,KAAK;GACnB,CAAC;GACD,IAAI,GAAG,aAAa,QAAQ,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC;GAC7D,IAAI,GAAG,UAAU,QAAe,OAAO,GAAG,CAAC;EAC7C,CAAC;CACH;CAEA,eAAe,cACb,KAMA,KAOe;EACf,MAAM,SAAS,IAAI,UAAU;EAC7B,MAAM,MAAM,IAAI,OAAO;EACvB,OAAO,KAAK,GAAG,OAAO,GAAG,KAAK;EAE9B,MAAM,cAAc,MAAM,SAAS,GAAG;EACtC,MAAM,QAAQ,eAAe,MAAM,QAAQ,KAAK,QAAQ;EAExD,IAAI,SAAS,gBAAgB;GAQ3B,aAAa,KAAK,MAPG,mBACnB,QACA,KACA,aACA,IAAI,SACJ,MAAM,KACR,CACwB;GACxB;EACF;EAEA,IAAI,OAAO;GACT,MAAM,oBAAoB,uBACxB,IAAI,SACJ,MAAM,MAAM,cACd;GACA,MAAM,WAAW,MAAM,eACrB,QACA,mBAAmB,GAAG,GACtB,mBACA,WACF;GACA,aAAa,KAAK;IAChB,QAAQ,SAAS;IACjB,SAAS,SAAS;IAClB,MAAM,SAAS;IACf,WAAW;GACb,CAAC;GACD;EACF;EAEA,IAAI,gBAAgB;GAOlB,aAAa,KAAK,MANG,uBACnB,QACA,KACA,aACA,IAAI,OACN,CACwB;GACxB;EACF;EAEA,aAAa,KAAK,QAAQ,GAAG;CAC/B;CAEA,OAAO;EACL,IAAI,SAAS;GACX,OAAO,eAAe;EACxB;EACA,OAAO,eAAe;EAEtB,MAAM,QAAmC;GACvC,OAAO,IAAI,SAAS,SAAS,WAAW;IACtC,SAASC,cAAkB,KAAK,QAAQ;KACtC,cAAc,KAAK,GAAG,CAAC,CAAC,OAAO,QAAQ;MACrC,OAAO,MAAM,0BAA0B,EAAE,OAAO,IAAI,QAAQ,CAAC;MAC7D,IAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;MACzD,IAAI,IACF,KAAK,UAAU;OACb,OAAO;OACP,SAAS,IAAI;MACf,CAAC,CACH;KACF,CAAC;IACH,CAAC;IAED,OAAO,GAAG,SAAS,MAAM;IAEzB,OAAO,OAAO,OAAO,QAAQ,GAAG,OAAO,QAAQ,mBAAmB;KAChE,MAAM,OAAO,QAAQ,QAAQ;KAC7B,IAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;MACrC,uBAAO,IAAI,MAAM,8BAA8B,CAAC;MAChD;KACF;KACA,OAAO,KACL,iCAAiC,OAAO,QAAQ,YAAY,GAAG,KAAK,MACtE;KACA,OAAO,KAAK,eAAe,WAAW;KACtC,QAAQ,EAAE,MAAM,KAAK,KAAK,CAAC;IAC7B,CAAC;GACH,CAAC;EACH;EAEA,MAAM,OAAsB;GAC1B,OAAO,IAAI,SAAS,SAAS,WAAW;IACtC,IAAI,CAAC,QAAQ,OAAO,QAAQ;IAC5B,OAAO,OAAO,QAAS,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAE;GACvD,CAAC;EACH;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abapify/adt-proxy",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.19",
|
|
4
4
|
"description": "ADT proxy server with JSON↔XML conversion",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@abapify/adt-contracts": "0.4.
|
|
21
|
-
"@abapify/speci": "0.4.
|
|
20
|
+
"@abapify/adt-contracts": "0.4.19",
|
|
21
|
+
"@abapify/speci": "0.4.19"
|
|
22
22
|
},
|
|
23
23
|
"repository": {
|
|
24
24
|
"type": "git",
|