zapier-platform-core 11.3.1 → 12.0.0
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 +2 -2
- package/src/http-middlewares/after/prepare-response.js +48 -30
- package/src/http-middlewares/after/throw-for-stale-auth.js +16 -0
- package/src/http-middlewares/after/throw-for-status.js +4 -11
- package/src/http-middlewares/before/add-query-params.js +18 -1
- package/src/http-middlewares/before/prepare-request.js +6 -1
- package/src/tools/create-app-request-client.js +14 -2
- package/src/tools/create-logger.js +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.0.0",
|
|
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/",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"node-fetch": "2.6.7",
|
|
51
51
|
"oauth-sign": "0.9.0",
|
|
52
52
|
"semver": "7.3.5",
|
|
53
|
-
"zapier-platform-schema": "
|
|
53
|
+
"zapier-platform-schema": "12.0.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"adm-zip": "0.5.5",
|
|
@@ -2,9 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const querystring = require('querystring');
|
|
5
|
-
const throwForStatus = require('./throw-for-status');
|
|
6
5
|
const { replaceHeaders } = require('./middleware-utils');
|
|
7
6
|
const { FORM_TYPE } = require('../../tools/http');
|
|
7
|
+
const errors = require('../../errors');
|
|
8
|
+
|
|
9
|
+
const _throwForStatus = (response) => {
|
|
10
|
+
// calling this always throws, regardless of the skipThrowForStatus value
|
|
11
|
+
// eslint-disable-next-line yoda
|
|
12
|
+
if (400 <= response.status && response.status < 600) {
|
|
13
|
+
throw new errors.ResponseError(response);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
8
16
|
|
|
9
17
|
const prepareRawResponse = (resp, request) => {
|
|
10
18
|
// TODO: if !2xx should we go ahead and get response.content for them?
|
|
@@ -14,7 +22,11 @@ const prepareRawResponse = (resp, request) => {
|
|
|
14
22
|
skipThrowForStatus: request.skipThrowForStatus,
|
|
15
23
|
};
|
|
16
24
|
const outResp = _.extend(resp, extendedResp, replaceHeaders(resp));
|
|
17
|
-
|
|
25
|
+
|
|
26
|
+
outResp.throwForStatus = () => {
|
|
27
|
+
_throwForStatus(outResp);
|
|
28
|
+
};
|
|
29
|
+
|
|
18
30
|
Object.defineProperty(outResp, 'content', {
|
|
19
31
|
get: function () {
|
|
20
32
|
throw new Error(
|
|
@@ -27,30 +39,36 @@ const prepareRawResponse = (resp, request) => {
|
|
|
27
39
|
return outResp;
|
|
28
40
|
};
|
|
29
41
|
|
|
30
|
-
const prepareContentResponse = (resp, request) => {
|
|
42
|
+
const prepareContentResponse = async (resp, request) => {
|
|
31
43
|
// TODO: does it make sense to not trim the signature? more equivalence to raw...
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})
|
|
44
|
+
const content = await resp.text();
|
|
45
|
+
|
|
46
|
+
// trim down the response signature a ton for simplicity
|
|
47
|
+
const preppedResp = {
|
|
48
|
+
status: resp.status,
|
|
49
|
+
json: undefined,
|
|
50
|
+
data: undefined,
|
|
51
|
+
content: content,
|
|
52
|
+
request: request,
|
|
53
|
+
// only controls if _we_ call throwForStatus automatically
|
|
54
|
+
skipThrowForStatus: request.skipThrowForStatus,
|
|
55
|
+
};
|
|
56
|
+
const outResp = _.extend(preppedResp, replaceHeaders(resp));
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
if (outResp.headers.get('content-type') === FORM_TYPE) {
|
|
60
|
+
outResp.data = querystring.parse(content);
|
|
61
|
+
} else {
|
|
62
|
+
outResp.data = JSON.parse(content);
|
|
63
|
+
outResp.json = JSON.parse(content); // DEPRECATED (not using reference to isolate)
|
|
64
|
+
}
|
|
65
|
+
} catch (_e) {}
|
|
66
|
+
|
|
67
|
+
outResp.throwForStatus = () => {
|
|
68
|
+
_throwForStatus(outResp);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return outResp;
|
|
54
72
|
};
|
|
55
73
|
|
|
56
74
|
// Provide a standardized plain JS responseObj for common consumption, or raw response for streaming.
|
|
@@ -58,11 +76,11 @@ const prepareResponse = (resp) => {
|
|
|
58
76
|
const request = resp.input;
|
|
59
77
|
delete resp.input;
|
|
60
78
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
79
|
+
const responseFunc = request.raw
|
|
80
|
+
? prepareRawResponse
|
|
81
|
+
: prepareContentResponse;
|
|
82
|
+
|
|
83
|
+
return responseFunc(resp, request);
|
|
66
84
|
};
|
|
67
85
|
|
|
68
86
|
module.exports = prepareResponse;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { RefreshAuthError } = require('../../errors');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Raise a RefreshAuthError _before_ any other error handling happens. Behaves more closely to the 9.x behavior rather than 10.x
|
|
7
|
+
*/
|
|
8
|
+
const throwForStaleAuth = (resp) => {
|
|
9
|
+
if (resp.status === 401) {
|
|
10
|
+
throw new RefreshAuthError();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return resp;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
module.exports = throwForStaleAuth;
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (
|
|
7
|
-
!response.skipThrowForStatus &&
|
|
8
|
-
response.status >= 400 &&
|
|
9
|
-
response.status < 600
|
|
10
|
-
) {
|
|
11
|
-
throw new errors.ResponseError(response);
|
|
3
|
+
const throwForStatusMiddleware = (response) => {
|
|
4
|
+
if (!response.skipThrowForStatus) {
|
|
5
|
+
response.throwForStatus();
|
|
12
6
|
}
|
|
13
|
-
|
|
14
7
|
return response;
|
|
15
8
|
};
|
|
16
9
|
|
|
17
|
-
module.exports =
|
|
10
|
+
module.exports = throwForStatusMiddleware;
|
|
@@ -14,7 +14,24 @@ const addQueryParams = (req) => {
|
|
|
14
14
|
|
|
15
15
|
normalizeEmptyParamFields(req);
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
let stringifiedParams = querystring.stringify(req.params);
|
|
18
|
+
|
|
19
|
+
// it goes against spec, but for compatibility, some APIs want certain
|
|
20
|
+
// characters (mostly $) unencoded
|
|
21
|
+
if (req.skipEncodingChars) {
|
|
22
|
+
for (let i = 0; i < req.skipEncodingChars.length; i++) {
|
|
23
|
+
const char = req.skipEncodingChars.charAt(i);
|
|
24
|
+
const valToReplace = querystring.escape(char);
|
|
25
|
+
if (valToReplace === char) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
// no replaceAll in JS yet, coming in a node version soon!
|
|
29
|
+
stringifiedParams = stringifiedParams.replace(
|
|
30
|
+
new RegExp(valToReplace, 'g'),
|
|
31
|
+
char
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
18
35
|
|
|
19
36
|
if (stringifiedParams) {
|
|
20
37
|
req.url += `${splitter}${stringifiedParams}`;
|
|
@@ -113,7 +113,12 @@ const prepareRequest = function (req) {
|
|
|
113
113
|
body: false,
|
|
114
114
|
},
|
|
115
115
|
replace: true, // always replace curlies
|
|
116
|
-
|
|
116
|
+
// read default from app flags, but always defer to the request object if the value was set
|
|
117
|
+
skipThrowForStatus: _.get(
|
|
118
|
+
input,
|
|
119
|
+
['_zapier', 'app', 'flags', 'skipThrowForStatus'],
|
|
120
|
+
false
|
|
121
|
+
),
|
|
117
122
|
_addContext: () => {},
|
|
118
123
|
});
|
|
119
124
|
|
|
@@ -18,7 +18,8 @@ const prepareRequest = require('../http-middlewares/before/prepare-request');
|
|
|
18
18
|
// after middles
|
|
19
19
|
const logResponse = require('../http-middlewares/after/log-response');
|
|
20
20
|
const prepareResponse = require('../http-middlewares/after/prepare-response');
|
|
21
|
-
const
|
|
21
|
+
const throwForStaleAuth = require('../http-middlewares/after/throw-for-stale-auth');
|
|
22
|
+
const throwForStatusMiddleware = require('../http-middlewares/after/throw-for-status');
|
|
22
23
|
|
|
23
24
|
const createAppRequestClient = (input, options) => {
|
|
24
25
|
input = ensurePath(input, '_zapier.app');
|
|
@@ -51,11 +52,22 @@ const createAppRequestClient = (input, options) => {
|
|
|
51
52
|
httpBefores.push(disableSSLCertCheck);
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
let includeAutoRefresh = false;
|
|
56
|
+
if (
|
|
57
|
+
app.authentication &&
|
|
58
|
+
(app.authentication.type === 'session' ||
|
|
59
|
+
(app.authentication.type === 'oauth2' &&
|
|
60
|
+
_.get(app, 'authentication.oauth2Config.autoRefresh')))
|
|
61
|
+
) {
|
|
62
|
+
includeAutoRefresh = true;
|
|
63
|
+
}
|
|
64
|
+
|
|
54
65
|
const httpAfters = [
|
|
55
66
|
prepareResponse,
|
|
56
67
|
logResponse,
|
|
68
|
+
...(includeAutoRefresh ? [throwForStaleAuth] : []),
|
|
57
69
|
...ensureArray(app.afterResponse),
|
|
58
|
-
|
|
70
|
+
throwForStatusMiddleware,
|
|
59
71
|
];
|
|
60
72
|
|
|
61
73
|
return createRequestClient(httpBefores, httpAfters, options);
|
|
@@ -167,6 +167,7 @@ class LogStream extends Transform {
|
|
|
167
167
|
class LogStreamFactory {
|
|
168
168
|
constructor() {
|
|
169
169
|
this._logStream = null;
|
|
170
|
+
this.ended = false;
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
getOrCreate(url, token) {
|
|
@@ -185,6 +186,10 @@ class LogStreamFactory {
|
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
async end() {
|
|
189
|
+
// Mark the factory as ended. This suggests that any logStream.write() that
|
|
190
|
+
// follows should end() right away.
|
|
191
|
+
this.ended = true;
|
|
192
|
+
|
|
188
193
|
if (this._logStream) {
|
|
189
194
|
this._logStream.end();
|
|
190
195
|
const response = await this._logStream.request;
|
|
@@ -240,6 +245,14 @@ const sendLog = async (logStreamFactory, options, event, message, data) => {
|
|
|
240
245
|
// no line breaks, and after an object it ends with a line break.
|
|
241
246
|
JSON.stringify({ message: safeMessage, data: safeData }) + '\n'
|
|
242
247
|
);
|
|
248
|
+
|
|
249
|
+
if (logStreamFactory.ended) {
|
|
250
|
+
// Lambda handler calls logger.end() at the end. But what if there's a
|
|
251
|
+
// (bad) callback that is still running after the Lambda handler returns?
|
|
252
|
+
// We need to make sure the bad callback ends the logger as well.
|
|
253
|
+
// Otherwise, it will hang!
|
|
254
|
+
logStreamFactory.end();
|
|
255
|
+
}
|
|
243
256
|
}
|
|
244
257
|
};
|
|
245
258
|
|