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.0",
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.0"
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
- response.on('data', (chunk) => chunks.push(chunk));
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 (!skipHttpPatch && !event.calledFromCli) {
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,
@@ -4,7 +4,7 @@
4
4
  * files, and/or the schema-to-ts tool and run its CLI to regenerate
5
5
  * these typings.
6
6
  *
7
- * zapier-platform-schema version: 15.17.0
7
+ * zapier-platform-schema version: 15.18.1
8
8
  * schema-to-ts compiler version: 0.1.0
9
9
  */
10
10