From 253f630627466872c33ff58907958170b060b112 Mon Sep 17 00:00:00 2001 From: Richard Dzurus Date: Mon, 19 May 2025 12:46:38 +0200 Subject: [PATCH 1/4] adds direct execute and mtls options support --- package-lock.json | 4 +- package.json | 2 +- src/commands/generate/index.ts | 11 +++++ templates/api-index.js.hbs | 80 ++++++++++++++++++++++++++++++++-- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index ee0ac63..fa915ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "polyapi", - "version": "0.23.12", + "version": "0.23.13", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "polyapi", - "version": "0.23.12", + "version": "0.23.13", "license": "MIT", "dependencies": { "@guanghechen/helper-string": "4.7.1", diff --git a/package.json b/package.json index 46cfec9..4428a7e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "polyapi", - "version": "0.23.12", + "version": "0.23.13", "description": "Poly is a CLI tool to help create and manage your Poly definitions.", "license": "MIT", "repository": { diff --git a/src/commands/generate/index.ts b/src/commands/generate/index.ts index 6c037b4..bd3d2e7 100644 --- a/src/commands/generate/index.ts +++ b/src/commands/generate/index.ts @@ -66,6 +66,16 @@ const prepareDir = async (polyPath: string) => { } }; +const getExecutionConfig = () => ({ + directExecute: process.env.API_FUNCTION_DIRECT_EXECUTE === 'true', + mtls: { + certPath: process.env.MTLS_CERT_PATH, + keyPath: process.env.MTLS_KEY_PATH, + caPath: process.env.MTLS_CA_PATH, + rejectUnauthorized: process.env.NODE_ENV !== 'development', + }, +}); + const generateRedirectIndexFiles = async (polyPath: string) => { const defaultPolyLib = getPolyLibPath(DEFAULT_POLY_PATH); @@ -156,6 +166,7 @@ const generateApiFunctionJSFiles = async (libPath: string, specifications: ApiFu `${libPath}/api/index.js`, template({ specifications, + executionConfig: getExecutionConfig(), }), ); }; diff --git a/templates/api-index.js.hbs b/templates/api-index.js.hbs index 7a4a4cc..e4349b9 100644 --- a/templates/api-index.js.hbs +++ b/templates/api-index.js.hbs @@ -1,6 +1,19 @@ const axios = require('../axios'); const set = require('lodash/set'); const merge = require('lodash/merge'); +const https = require('https'); +const fs = require('fs'); + +// Environment variables injected during generation +const env = { + directExecute: {{executionConfig.directExecute}}, + mtls: { + certPath: '{{executionConfig.mtls.certPath}}', + keyPath: '{{executionConfig.mtls.keyPath}}', + caPath: '{{executionConfig.mtls.caPath}}', + rejectUnauthorized: {{executionConfig.mtls.rejectUnauthorized}}, + } +}; const functions = [ {{#each specifications}} @@ -8,6 +21,20 @@ const functions = [ {{/each}} ]; +// Create MTLS agent if paths are provided +const createHttpsAgent = () => { + const { mtls } = env; + if (!mtls.certPath || !mtls.keyPath || !mtls.caPath) { + return undefined; + } + return new https.Agent({ + cert: fs.readFileSync(mtls.certPath), + key: fs.readFileSync(mtls.keyPath), + ca: fs.readFileSync(mtls.caPath), + rejectUnauthorized: mtls.rejectUnauthorized, + }); +}; + module.exports = (clientID, polyCustom) => merge( {}, functions.reduce( @@ -17,11 +44,58 @@ module.exports = (clientID, polyCustom) => merge( (...args) => { const requestStartTime = Date.now(); const requestArgs = argKeys.reduce((acc, key, index) => ({ ...acc, [key]: args[index] }), {}); + + // Check if direct execution is enabled + const { directExecute } = env; + + if (directExecute === true) { + // Make direct API call + const httpsAgent = createHttpsAgent(); + + let polyHeaders; + + return axios.post( + `/functions/api/${id}/direct-execute?clientId=${clientID}`, + requestArgs, + { + headers: { + 'x-poly-execution-id': polyCustom.executionId, + } + } + ).then(({ headers, data }) => { + polyHeaders = headers; + if (data && (data.status < 200 || data.status >= 300)) { + console.error('Error getting direct execution data for api function with id:', id, 'Status code:', data.status, 'Request data:', requestArgs, 'Response data:', data.data); + } + return axios({ + ...data, + headers: { + ...data.headers, + }, + httpsAgent, + }) + }).then(({ headers, data, status, ...args }) => { + if (status && (status < 200 || status >= 300)) { + console.error('Error direct executing api function with id:', id, 'Status code:', status, 'Request data:', requestArgs, 'Response data:', data.data); + } + const serverExecutionTimeMs = Number(polyHeaders['x-poly-execution-duration']); + const roundTripNetworkLatencyMs = Date.now() - requestStartTime - serverExecutionTimeMs; + return { + data: data, + status: status, + headers: { ...headers }, + metrics: { + roundTripNetworkLatencyMs, + serverExecutionTimeMs, + } + }; + }); + } + + // default indirect execution return axios.post( `/functions/api/${id}/execute?clientId=${clientID}`, - { - ...requestArgs, - }, + requestArgs, { headers: { 'x-poly-execution-id': polyCustom.executionId, From a2f22743096f4eef20b0b39a8482e0970c6a7456 Mon Sep 17 00:00:00 2001 From: Richard Dzurus Date: Mon, 19 May 2025 12:48:30 +0200 Subject: [PATCH 2/4] reversed unintended change --- templates/api-index.js.hbs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/api-index.js.hbs b/templates/api-index.js.hbs index e4349b9..22adb34 100644 --- a/templates/api-index.js.hbs +++ b/templates/api-index.js.hbs @@ -95,7 +95,9 @@ module.exports = (clientID, polyCustom) => merge( // default indirect execution return axios.post( `/functions/api/${id}/execute?clientId=${clientID}`, - requestArgs, + { + ...requestArgs, + }, { headers: { 'x-poly-execution-id': polyCustom.executionId, From b3b71b4e3673a3a31925d8f1ab83ca1539d59304 Mon Sep 17 00:00:00 2001 From: Richard Dzurus Date: Mon, 19 May 2025 22:35:27 +0200 Subject: [PATCH 3/4] fixed metric names + http agent to be created only once --- templates/api-index.js.hbs | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/templates/api-index.js.hbs b/templates/api-index.js.hbs index 22adb34..0d2525f 100644 --- a/templates/api-index.js.hbs +++ b/templates/api-index.js.hbs @@ -22,17 +22,25 @@ const functions = [ ]; // Create MTLS agent if paths are provided -const createHttpsAgent = () => { +let httpsAgent = undefined; +const getHttpsAgent = () => { + if (httpsAgent) { + return httpsAgent; + } + const { mtls } = env; if (!mtls.certPath || !mtls.keyPath || !mtls.caPath) { return undefined; } - return new https.Agent({ + + httpsAgent = new https.Agent({ cert: fs.readFileSync(mtls.certPath), key: fs.readFileSync(mtls.keyPath), ca: fs.readFileSync(mtls.caPath), rejectUnauthorized: mtls.rejectUnauthorized, }); + + return httpsAgent; }; module.exports = (clientID, polyCustom) => merge( @@ -42,7 +50,7 @@ module.exports = (clientID, polyCustom) => merge( acc, path, (...args) => { - const requestStartTime = Date.now(); + const requestServerStartTime = Date.now(); const requestArgs = argKeys.reduce((acc, key, index) => ({ ...acc, [key]: args[index] }), {}); // Check if direct execution is enabled @@ -50,9 +58,11 @@ module.exports = (clientID, polyCustom) => merge( if (directExecute === true) { // Make direct API call - const httpsAgent = createHttpsAgent(); let polyHeaders; + let serverPreperationTimeMs; + let roundTripServerNetworkLatencyMs; + let requestApiStartTime; return axios.post( `/functions/api/${id}/direct-execute?clientId=${clientID}`, @@ -67,6 +77,13 @@ module.exports = (clientID, polyCustom) => merge( if (data && (data.status < 200 || data.status >= 300)) { console.error('Error getting direct execution data for api function with id:', id, 'Status code:', data.status, 'Request data:', requestArgs, 'Response data:', data.data); } + + serverPreperationTimeMs = Number(polyHeaders['x-poly-execution-duration']); + roundTripServerNetworkLatencyMs = Date.now() - requestServerStartTime - serverPreperationTimeMs; + + requestApiStartTime = Date.now(); + const httpsAgent = getHttpsAgent(); + return axios({ ...data, headers: { @@ -78,15 +95,15 @@ module.exports = (clientID, polyCustom) => merge( if (status && (status < 200 || status >= 300)) { console.error('Error direct executing api function with id:', id, 'Status code:', status, 'Request data:', requestArgs, 'Response data:', data.data); } - const serverExecutionTimeMs = Number(polyHeaders['x-poly-execution-duration']); - const roundTripNetworkLatencyMs = Date.now() - requestStartTime - serverExecutionTimeMs; + const apiExecutionTimeMs = Date.now() - requestApiStartTime; return { data: data, status: status, headers: { ...headers }, metrics: { - roundTripNetworkLatencyMs, - serverExecutionTimeMs, + roundTripServerNetworkLatencyMs, + serverPreperationTimeMs, + apiExecutionTimeMs, } }; }); @@ -108,7 +125,7 @@ module.exports = (clientID, polyCustom) => merge( console.error('Error executing api function with id:', id, 'Status code:', data.status, 'Request data:', requestArgs, 'Response data:', data.data); } const serverExecutionTimeMs = Number(headers['x-poly-execution-duration']); - const roundTripNetworkLatencyMs = Date.now() - requestStartTime - serverExecutionTimeMs; + const roundTripNetworkLatencyMs = Date.now() - requestServerStartTime - serverExecutionTimeMs; return { ...data, metrics: { From 23d0342506d7401ee8504a918cd674df6c399d6c Mon Sep 17 00:00:00 2001 From: Richard Dzurus Date: Thu, 22 May 2025 16:56:10 +0200 Subject: [PATCH 4/4] version increment --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index fa915ce..08ebe7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "polyapi", - "version": "0.23.13", + "version": "0.23.14", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 4428a7e..4dbd91e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "polyapi", - "version": "0.23.13", + "version": "0.23.14", "description": "Poly is a CLI tool to help create and manage your Poly definitions.", "license": "MIT", "repository": {