Skip to content

Commit c1589f1

Browse files
P2) (MS) npm client: add direct execute option and MTLS option (#3)
* adds direct execute and mtls options support * reversed unintended change * fixed metric names + http agent to be created only once * version increment
1 parent 4178e72 commit c1589f1

File tree

4 files changed

+108
-4
lines changed

4 files changed

+108
-4
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "polyapi",
3-
"version": "0.23.13",
3+
"version": "0.23.14",
44
"description": "Poly is a CLI tool to help create and manage your Poly definitions.",
55
"license": "MIT",
66
"repository": {

src/commands/generate/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,16 @@ const prepareDir = async (polyPath: string) => {
6666
}
6767
};
6868

69+
const getExecutionConfig = () => ({
70+
directExecute: process.env.API_FUNCTION_DIRECT_EXECUTE === 'true',
71+
mtls: {
72+
certPath: process.env.MTLS_CERT_PATH,
73+
keyPath: process.env.MTLS_KEY_PATH,
74+
caPath: process.env.MTLS_CA_PATH,
75+
rejectUnauthorized: process.env.NODE_ENV !== 'development',
76+
},
77+
});
78+
6979
const generateRedirectIndexFiles = async (polyPath: string) => {
7080
const defaultPolyLib = getPolyLibPath(DEFAULT_POLY_PATH);
7181

@@ -156,6 +166,7 @@ const generateApiFunctionJSFiles = async (libPath: string, specifications: ApiFu
156166
`${libPath}/api/index.js`,
157167
template({
158168
specifications,
169+
executionConfig: getExecutionConfig(),
159170
}),
160171
);
161172
};

templates/api-index.js.hbs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,115 @@
11
const axios = require('../axios');
22
const set = require('lodash/set');
33
const merge = require('lodash/merge');
4+
const https = require('https');
5+
const fs = require('fs');
6+
7+
// Environment variables injected during generation
8+
const env = {
9+
directExecute: {{executionConfig.directExecute}},
10+
mtls: {
11+
certPath: '{{executionConfig.mtls.certPath}}',
12+
keyPath: '{{executionConfig.mtls.keyPath}}',
13+
caPath: '{{executionConfig.mtls.caPath}}',
14+
rejectUnauthorized: {{executionConfig.mtls.rejectUnauthorized}},
15+
}
16+
};
417

518
const functions = [
619
{{#each specifications}}
720
['{{#if context}}{{context}}.{{/if}}{{name}}', '{{id}}',{{#each function.arguments}}'{{name}}',{{/each}}],
821
{{/each}}
922
];
1023

24+
// Create MTLS agent if paths are provided
25+
let httpsAgent = undefined;
26+
const getHttpsAgent = () => {
27+
if (httpsAgent) {
28+
return httpsAgent;
29+
}
30+
31+
const { mtls } = env;
32+
if (!mtls.certPath || !mtls.keyPath || !mtls.caPath) {
33+
return undefined;
34+
}
35+
36+
httpsAgent = new https.Agent({
37+
cert: fs.readFileSync(mtls.certPath),
38+
key: fs.readFileSync(mtls.keyPath),
39+
ca: fs.readFileSync(mtls.caPath),
40+
rejectUnauthorized: mtls.rejectUnauthorized,
41+
});
42+
43+
return httpsAgent;
44+
};
45+
1146
module.exports = (clientID, polyCustom) => merge(
1247
{},
1348
functions.reduce(
1449
(acc, [path, id, ...argKeys]) => set(
1550
acc,
1651
path,
1752
(...args) => {
18-
const requestStartTime = Date.now();
53+
const requestServerStartTime = Date.now();
1954
const requestArgs = argKeys.reduce((acc, key, index) => ({ ...acc, [key]: args[index] }), {});
55+
56+
// Check if direct execution is enabled
57+
const { directExecute } = env;
58+
59+
if (directExecute === true) {
60+
// Make direct API call
61+
62+
let polyHeaders;
63+
let serverPreperationTimeMs;
64+
let roundTripServerNetworkLatencyMs;
65+
let requestApiStartTime;
66+
67+
return axios.post(
68+
`/functions/api/${id}/direct-execute?clientId=${clientID}`,
69+
requestArgs,
70+
{
71+
headers: {
72+
'x-poly-execution-id': polyCustom.executionId,
73+
}
74+
}
75+
).then(({ headers, data }) => {
76+
polyHeaders = headers;
77+
if (data && (data.status < 200 || data.status >= 300)) {
78+
console.error('Error getting direct execution data for api function with id:', id, 'Status code:', data.status, 'Request data:', requestArgs, 'Response data:', data.data);
79+
}
80+
81+
serverPreperationTimeMs = Number(polyHeaders['x-poly-execution-duration']);
82+
roundTripServerNetworkLatencyMs = Date.now() - requestServerStartTime - serverPreperationTimeMs;
83+
84+
requestApiStartTime = Date.now();
85+
const httpsAgent = getHttpsAgent();
86+
87+
return axios({
88+
...data,
89+
headers: {
90+
...data.headers,
91+
},
92+
httpsAgent,
93+
})
94+
}).then(({ headers, data, status, ...args }) => {
95+
if (status && (status < 200 || status >= 300)) {
96+
console.error('Error direct executing api function with id:', id, 'Status code:', status, 'Request data:', requestArgs, 'Response data:', data.data);
97+
}
98+
const apiExecutionTimeMs = Date.now() - requestApiStartTime;
99+
return {
100+
data: data,
101+
status: status,
102+
headers: { ...headers },
103+
metrics: {
104+
roundTripServerNetworkLatencyMs,
105+
serverPreperationTimeMs,
106+
apiExecutionTimeMs,
107+
}
108+
};
109+
});
110+
}
111+
112+
// default indirect execution
20113
return axios.post(
21114
`/functions/api/${id}/execute?clientId=${clientID}`,
22115
{
@@ -36,7 +129,7 @@ module.exports = (clientID, polyCustom) => merge(
36129
console.error('Error executing api function with id:', id, 'Status code:', data.status, 'Request data:', requestArgs, 'Response data:', responseData);
37130
}
38131
const serverExecutionTimeMs = Number(headers['x-poly-execution-duration']);
39-
const roundTripNetworkLatencyMs = Date.now() - requestStartTime - serverExecutionTimeMs;
132+
const roundTripNetworkLatencyMs = Date.now() - requestServerStartTime - serverExecutionTimeMs;
40133
return {
41134
...data,
42135
metrics: {

0 commit comments

Comments
 (0)