zapier-platform-core 15.18.0 → 15.18.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-core",
|
|
3
|
-
"version": "15.18.
|
|
3
|
+
"version": "15.18.1",
|
|
4
4
|
"description": "The core SDK for CLI apps in the Zapier Developer Platform.",
|
|
5
5
|
"repository": "zapier/zapier-platform",
|
|
6
6
|
"homepage": "https://platform.zapier.com/",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"node-fetch": "2.6.7",
|
|
54
54
|
"oauth-sign": "0.9.0",
|
|
55
55
|
"semver": "7.5.2",
|
|
56
|
-
"zapier-platform-schema": "15.18.
|
|
56
|
+
"zapier-platform-schema": "15.18.1"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/node-fetch": "^2.6.11",
|
|
@@ -48,7 +48,7 @@ const createHttpPatch = (event) => {
|
|
|
48
48
|
return originalRequest(options, callback);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
// Ignore requests made via the request client
|
|
51
|
+
// Ignore requests made via the request client (z.request)
|
|
52
52
|
if (_.get(options.headers, 'user-agent', []).indexOf('Zapier') !== -1) {
|
|
53
53
|
return originalRequest(options, callback);
|
|
54
54
|
}
|
|
@@ -112,7 +112,14 @@ const createHttpPatch = (event) => {
|
|
|
112
112
|
}
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
const originalEmit = response.emit;
|
|
116
|
+
|
|
117
|
+
response.emit = function (event, ...args) {
|
|
118
|
+
if (event === 'data') {
|
|
119
|
+
chunks.push(args[0]);
|
|
120
|
+
}
|
|
121
|
+
return originalEmit.apply(this, [event, ...args]);
|
|
122
|
+
};
|
|
116
123
|
response.on('end', logResponse);
|
|
117
124
|
response.on('error', logResponse);
|
|
118
125
|
|
|
@@ -17,6 +17,7 @@ const createLogger = require('./create-logger');
|
|
|
17
17
|
const createRpcClient = require('./create-rpc-client');
|
|
18
18
|
const environmentTools = require('./environment');
|
|
19
19
|
const schemaTools = require('./schema');
|
|
20
|
+
const wrapFetchWithLogger = require('./fetch-logger');
|
|
20
21
|
const ZapierPromise = require('./promise');
|
|
21
22
|
|
|
22
23
|
const isDefinedPrimitive = (value) => {
|
|
@@ -189,10 +190,15 @@ const createLambdaHandler = (appRawOrPath) => {
|
|
|
189
190
|
// Wait for all async events to complete before callback returns.
|
|
190
191
|
// This is not strictly necessary since this is the default now when
|
|
191
192
|
// using the callback; just putting it here to be explicit.
|
|
193
|
+
// In some cases, the code hangs and never exits because the event loop is not
|
|
194
|
+
// empty, so we can override the default behavior and exit after the app is done.
|
|
192
195
|
context.callbackWaitsForEmptyEventLoop = true;
|
|
196
|
+
if (event.skipWaitForAsync === true) {
|
|
197
|
+
context.callbackWaitsForEmptyEventLoop = false;
|
|
198
|
+
}
|
|
193
199
|
|
|
194
200
|
// replace native Promise with bluebird (works better with domains)
|
|
195
|
-
if (!event.calledFromCli) {
|
|
201
|
+
if (!event.calledFromCli || event.calledFromCliInvoke) {
|
|
196
202
|
ZapierPromise.patchGlobal();
|
|
197
203
|
}
|
|
198
204
|
|
|
@@ -253,10 +259,16 @@ const createLambdaHandler = (appRawOrPath) => {
|
|
|
253
259
|
|
|
254
260
|
const { skipHttpPatch } = appRaw.flags || {};
|
|
255
261
|
// Adds logging for _all_ kinds of http(s) requests, no matter the library
|
|
256
|
-
if (
|
|
262
|
+
if (
|
|
263
|
+
!skipHttpPatch &&
|
|
264
|
+
(!event.calledFromCli || event.calledFromCliInvoke)
|
|
265
|
+
) {
|
|
257
266
|
const httpPatch = createHttpPatch(event);
|
|
258
267
|
httpPatch(require('http'), logger);
|
|
259
268
|
httpPatch(require('https'), logger); // 'https' needs to be patched separately
|
|
269
|
+
if (global.fetch) {
|
|
270
|
+
global.fetch = wrapFetchWithLogger(global.fetch, logger);
|
|
271
|
+
}
|
|
260
272
|
}
|
|
261
273
|
|
|
262
274
|
// TODO: Avoid calling prepareApp(appRaw) repeatedly here as createApp()
|
|
@@ -264,6 +276,7 @@ const createLambdaHandler = (appRawOrPath) => {
|
|
|
264
276
|
const compiledApp = schemaTools.prepareApp(appRaw);
|
|
265
277
|
|
|
266
278
|
const input = createInput(compiledApp, event, logger, logBuffer, rpc);
|
|
279
|
+
|
|
267
280
|
return app(input);
|
|
268
281
|
})
|
|
269
282
|
.then((output) => {
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
|
|
3
|
+
const { ALLOWED_HTTP_DATA_CONTENT_TYPES } = require('./http');
|
|
4
|
+
|
|
5
|
+
const stringifyRequestData = (data) => {
|
|
6
|
+
// Be careful not to consume the data if it's a stream
|
|
7
|
+
if (typeof data === 'string') {
|
|
8
|
+
return data;
|
|
9
|
+
} else if (data instanceof URLSearchParams) {
|
|
10
|
+
return data.toString();
|
|
11
|
+
} else if (global.FormData && data instanceof global.FormData) {
|
|
12
|
+
return '<FormData>';
|
|
13
|
+
} else {
|
|
14
|
+
// See https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#setting_a_body
|
|
15
|
+
// for other possible body types
|
|
16
|
+
return '<unsupported format>';
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const normalizeRequestInfo = (input, init) => {
|
|
21
|
+
const result = {
|
|
22
|
+
method: 'GET',
|
|
23
|
+
headers: {},
|
|
24
|
+
data: '',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (global.Request && input instanceof global.Request) {
|
|
28
|
+
result.url = input.url;
|
|
29
|
+
result.method = input.method || result.method;
|
|
30
|
+
result.headers =
|
|
31
|
+
Object.fromEntries(input.headers.entries()) || result.headers;
|
|
32
|
+
if (input.body) {
|
|
33
|
+
result.data = stringifyRequestData(input.body);
|
|
34
|
+
}
|
|
35
|
+
} else if (typeof input.toString === 'function') {
|
|
36
|
+
// This condition includes `typeof input === 'string'` as well
|
|
37
|
+
result.url = input.toString();
|
|
38
|
+
} else {
|
|
39
|
+
// Don't log if we don't recognize the input type
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (init) {
|
|
44
|
+
result.method = init.method || result.method;
|
|
45
|
+
result.headers = init.headers || result.headers;
|
|
46
|
+
if (init.body) {
|
|
47
|
+
result.data = stringifyRequestData(init.body);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Is this request made by z.request()?
|
|
55
|
+
const isZapierUserAgent = (headers) =>
|
|
56
|
+
_.get(headers, 'user-agent', []).indexOf('Zapier') !== -1;
|
|
57
|
+
|
|
58
|
+
const shouldIncludeResponseContent = (contentType) => {
|
|
59
|
+
for (const ctype of ALLOWED_HTTP_DATA_CONTENT_TYPES) {
|
|
60
|
+
if (contentType.includes(ctype)) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const stringifyResponseContent = async (response) => {
|
|
68
|
+
// Be careful not to consume the original response body, which is why we clone it
|
|
69
|
+
return response.clone().text();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Usage:
|
|
73
|
+
// global.fetch = wrapFetchWithLogger(global.fetch, logger);
|
|
74
|
+
const wrapFetchWithLogger = (fetchFunc, logger) => {
|
|
75
|
+
if (fetchFunc.patchedByZapier) {
|
|
76
|
+
return fetchFunc;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const newFetch = async function (input, init) {
|
|
80
|
+
const response = await fetchFunc(input, init);
|
|
81
|
+
const requestInfo = normalizeRequestInfo(input, init);
|
|
82
|
+
if (requestInfo && !isZapierUserAgent(requestInfo.headers)) {
|
|
83
|
+
const responseContentType = response.headers.get('content-type');
|
|
84
|
+
|
|
85
|
+
logger(`${response.status} ${requestInfo.method} ${requestInfo.url}`, {
|
|
86
|
+
log_type: 'http',
|
|
87
|
+
request_type: 'patched-devplatform-outbound',
|
|
88
|
+
request_url: requestInfo.url,
|
|
89
|
+
request_method: requestInfo.method,
|
|
90
|
+
request_headers: requestInfo.headers,
|
|
91
|
+
request_data: requestInfo.data,
|
|
92
|
+
request_via_client: false,
|
|
93
|
+
response_status_code: response.status,
|
|
94
|
+
response_headers: Object.fromEntries(response.headers.entries()),
|
|
95
|
+
response_content: shouldIncludeResponseContent(responseContentType)
|
|
96
|
+
? await stringifyResponseContent(response)
|
|
97
|
+
: '<unsupported format>',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return response;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
newFetch.patchedByZapier = true;
|
|
104
|
+
return newFetch;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
module.exports = wrapFetchWithLogger;
|
package/src/tools/http.js
CHANGED
|
@@ -7,6 +7,7 @@ const JSON_TYPE_UTF8 = 'application/json; charset=utf-8';
|
|
|
7
7
|
const BINARY_TYPE = 'application/octet-stream';
|
|
8
8
|
const HTML_TYPE = 'text/html';
|
|
9
9
|
const TEXT_TYPE = 'text/plain';
|
|
10
|
+
const TEXT_TYPE_UTF8 = 'text/plain; charset=utf-8';
|
|
10
11
|
const YAML_TYPE = 'application/yaml';
|
|
11
12
|
const XML_TYPE = 'application/xml';
|
|
12
13
|
const JSONAPI_TYPE = 'application/vnd.api+json';
|
|
@@ -17,6 +18,7 @@ const ALLOWED_HTTP_DATA_CONTENT_TYPES = new Set([
|
|
|
17
18
|
JSON_TYPE_UTF8,
|
|
18
19
|
HTML_TYPE,
|
|
19
20
|
TEXT_TYPE,
|
|
21
|
+
TEXT_TYPE_UTF8,
|
|
20
22
|
YAML_TYPE,
|
|
21
23
|
XML_TYPE,
|
|
22
24
|
JSONAPI_TYPE,
|