zapier-platform-core 12.0.3 → 12.2.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 +4 -3
- package/src/tools/create-logger.js +46 -12
- package/src/tools/schema.js +34 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-core",
|
|
3
|
-
"version": "12.0
|
|
3
|
+
"version": "12.2.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/",
|
|
@@ -40,17 +40,18 @@
|
|
|
40
40
|
},
|
|
41
41
|
"engineStrict": true,
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@zapier/secret-scrubber": "^1.0.
|
|
43
|
+
"@zapier/secret-scrubber": "^1.0.7",
|
|
44
44
|
"bluebird": "3.7.2",
|
|
45
45
|
"content-disposition": "0.5.3",
|
|
46
46
|
"dotenv": "9.0.2",
|
|
47
47
|
"form-data": "4.0.0",
|
|
48
48
|
"lodash": "4.17.21",
|
|
49
49
|
"mime-types": "2.1.34",
|
|
50
|
+
"node-abort-controller": "3.0.1",
|
|
50
51
|
"node-fetch": "2.6.7",
|
|
51
52
|
"oauth-sign": "0.9.0",
|
|
52
53
|
"semver": "7.3.5",
|
|
53
|
-
"zapier-platform-schema": "12.0
|
|
54
|
+
"zapier-platform-schema": "12.2.0"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"adm-zip": "0.5.5",
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { promisify } = require('util');
|
|
3
4
|
const { Transform } = require('stream');
|
|
4
5
|
const { parse: querystringParse } = require('querystring');
|
|
5
6
|
|
|
6
7
|
const _ = require('lodash');
|
|
8
|
+
const { AbortController } = require('node-abort-controller');
|
|
7
9
|
|
|
8
10
|
const request = require('./request-client-internal');
|
|
9
11
|
const { simpleTruncate, recurseReplace, truncateData } = require('./data');
|
|
@@ -28,6 +30,10 @@ const {
|
|
|
28
30
|
// than the limit (16 MB) on the server side.
|
|
29
31
|
const LOG_STREAM_BYTES_LIMIT = 15 * 1024 * 1024;
|
|
30
32
|
|
|
33
|
+
const DEFAULT_LOGGER_TIMEOUT = 200;
|
|
34
|
+
|
|
35
|
+
const sleep = promisify(setTimeout);
|
|
36
|
+
|
|
31
37
|
const isUrl = (url) => {
|
|
32
38
|
try {
|
|
33
39
|
// eslint-disable-next-line no-new
|
|
@@ -167,6 +173,7 @@ class LogStream extends Transform {
|
|
|
167
173
|
constructor(options) {
|
|
168
174
|
super(options);
|
|
169
175
|
this.bytesWritten = 0;
|
|
176
|
+
this.controller = new AbortController();
|
|
170
177
|
this.request = this._newRequest(options.url, options.token);
|
|
171
178
|
}
|
|
172
179
|
|
|
@@ -179,15 +186,20 @@ class LogStream extends Transform {
|
|
|
179
186
|
'X-Token': token,
|
|
180
187
|
},
|
|
181
188
|
body: this,
|
|
189
|
+
signal: this.controller.signal,
|
|
182
190
|
};
|
|
183
191
|
return request(httpOptions).catch((err) => {
|
|
192
|
+
if (err.name === 'AbortError') {
|
|
193
|
+
return {
|
|
194
|
+
status: 200,
|
|
195
|
+
content: 'aborted',
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
184
199
|
// Swallow logging errors. This will show up in AWS logs at least.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
'http options:',
|
|
189
|
-
httpOptions
|
|
190
|
-
);
|
|
200
|
+
// Don't need to log for AbortError because that happens when we abort
|
|
201
|
+
// on purpose.
|
|
202
|
+
console.error('Error making log request:', err);
|
|
191
203
|
});
|
|
192
204
|
}
|
|
193
205
|
|
|
@@ -196,6 +208,10 @@ class LogStream extends Transform {
|
|
|
196
208
|
this.bytesWritten += Buffer.byteLength(chunk, encoding);
|
|
197
209
|
callback();
|
|
198
210
|
}
|
|
211
|
+
|
|
212
|
+
abort() {
|
|
213
|
+
this.controller.abort();
|
|
214
|
+
}
|
|
199
215
|
}
|
|
200
216
|
|
|
201
217
|
// Implements singleton for LogStream. The goal is for every sendLog() call we
|
|
@@ -222,17 +238,35 @@ class LogStreamFactory {
|
|
|
222
238
|
return this._logStream;
|
|
223
239
|
}
|
|
224
240
|
|
|
225
|
-
|
|
241
|
+
// Ends the logger and gets a response from the log server. Optionally takes
|
|
242
|
+
// timeoutToAbort to specify how many milliseconds we want to wait before
|
|
243
|
+
// force aborting the connection to the log server.
|
|
244
|
+
async end(timeoutToAbort = DEFAULT_LOGGER_TIMEOUT) {
|
|
226
245
|
// Mark the factory as ended. This suggests that any logStream.write() that
|
|
227
246
|
// follows should end() right away.
|
|
228
247
|
this.ended = true;
|
|
248
|
+
let response;
|
|
229
249
|
|
|
230
250
|
if (this._logStream) {
|
|
231
251
|
this._logStream.end();
|
|
232
|
-
|
|
252
|
+
|
|
253
|
+
const clock =
|
|
254
|
+
timeoutToAbort > 0 ? sleep(timeoutToAbort) : Promise.resolve(undefined);
|
|
255
|
+
const responsePromise = this._logStream.request;
|
|
256
|
+
|
|
257
|
+
const result = await Promise.race([clock, responsePromise]);
|
|
258
|
+
const isTimeout = !result;
|
|
259
|
+
if (isTimeout) {
|
|
260
|
+
this._logStream.abort();
|
|
261
|
+
// Expect to get a `{content: 'aborted'}` response
|
|
262
|
+
response = await responsePromise;
|
|
263
|
+
} else {
|
|
264
|
+
response = result;
|
|
265
|
+
}
|
|
266
|
+
|
|
233
267
|
this._logStream = null;
|
|
234
|
-
return response;
|
|
235
268
|
}
|
|
269
|
+
return response;
|
|
236
270
|
}
|
|
237
271
|
}
|
|
238
272
|
|
|
@@ -294,7 +328,7 @@ const sendLog = async (logStreamFactory, options, event, message, data) => {
|
|
|
294
328
|
// (bad) callback that is still running after the Lambda handler returns?
|
|
295
329
|
// We need to make sure the bad callback ends the logger as well.
|
|
296
330
|
// Otherwise, it will hang!
|
|
297
|
-
logStreamFactory.end();
|
|
331
|
+
logStreamFactory.end(DEFAULT_LOGGER_TIMEOUT);
|
|
298
332
|
}
|
|
299
333
|
}
|
|
300
334
|
};
|
|
@@ -331,8 +365,8 @@ const createLogger = (event, options) => {
|
|
|
331
365
|
const logStreamFactory = new LogStreamFactory();
|
|
332
366
|
const logger = sendLog.bind(undefined, logStreamFactory, options, event);
|
|
333
367
|
|
|
334
|
-
logger.end = async () => {
|
|
335
|
-
return logStreamFactory.end();
|
|
368
|
+
logger.end = async (timeoutToAbort = DEFAULT_LOGGER_TIMEOUT) => {
|
|
369
|
+
return logStreamFactory.end(timeoutToAbort);
|
|
336
370
|
};
|
|
337
371
|
return logger;
|
|
338
372
|
};
|
package/src/tools/schema.js
CHANGED
|
@@ -14,7 +14,7 @@ const convertResourceDos = (appRaw) => {
|
|
|
14
14
|
const triggers = {};
|
|
15
15
|
const searches = {};
|
|
16
16
|
const creates = {};
|
|
17
|
-
const
|
|
17
|
+
const searchCreates = {};
|
|
18
18
|
|
|
19
19
|
_.each(appRaw.resources, (resource) => {
|
|
20
20
|
let search, create, trigger;
|
|
@@ -54,8 +54,7 @@ const convertResourceDos = (appRaw) => {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
if (search && create && isVisible(search) && isVisible(create)) {
|
|
57
|
-
|
|
58
|
-
// key: `${resource.key}SearchOrCreate`,
|
|
57
|
+
searchCreates[search.key] = {
|
|
59
58
|
key: `${search.key}`, // For now this is a Zapier editor limitation (has to match search)
|
|
60
59
|
display: {
|
|
61
60
|
label: `Find or Create ${resource.noun}`,
|
|
@@ -64,11 +63,19 @@ const convertResourceDos = (appRaw) => {
|
|
|
64
63
|
search: search.key,
|
|
65
64
|
create: create.key,
|
|
66
65
|
};
|
|
67
|
-
searchOrCreates[searchOrCreate.key] = searchOrCreate;
|
|
68
66
|
}
|
|
69
67
|
});
|
|
70
68
|
|
|
71
|
-
|
|
69
|
+
const extras = { triggers, searches, creates };
|
|
70
|
+
|
|
71
|
+
// searchAndCreates is an alias for searchOrCreates. Schema validation makes sure only one of them is defined.
|
|
72
|
+
if (appRaw.searchAndCreates) {
|
|
73
|
+
extras.searchAndCreates = searchCreates;
|
|
74
|
+
} else {
|
|
75
|
+
extras.searchOrCreates = searchCreates;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return extras;
|
|
72
79
|
};
|
|
73
80
|
|
|
74
81
|
/* When a trigger/search/create (action) links to a resource, we walk up to
|
|
@@ -106,7 +113,13 @@ const compileApp = (appRaw) => {
|
|
|
106
113
|
appRaw = schemaTools.findSourceRequireFunctions(appRaw);
|
|
107
114
|
const extras = convertResourceDos(appRaw);
|
|
108
115
|
|
|
109
|
-
const actions = [
|
|
116
|
+
const actions = [
|
|
117
|
+
'triggers',
|
|
118
|
+
'searches',
|
|
119
|
+
'creates',
|
|
120
|
+
'searchOrCreates',
|
|
121
|
+
'searchAndCreates',
|
|
122
|
+
];
|
|
110
123
|
let problemKeys = [];
|
|
111
124
|
|
|
112
125
|
actions.forEach((a) => {
|
|
@@ -132,11 +145,21 @@ const compileApp = (appRaw) => {
|
|
|
132
145
|
appRaw.triggers = _.extend({}, extras.triggers, appRaw.triggers || {});
|
|
133
146
|
appRaw.searches = _.extend({}, extras.searches, appRaw.searches || {});
|
|
134
147
|
appRaw.creates = _.extend({}, extras.creates, appRaw.creates || {});
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
)
|
|
148
|
+
|
|
149
|
+
// searchAndCreates is an alias for searchOrCreates. Schema validation makes sure only one of them is defined.
|
|
150
|
+
// If the searchAndCreates key exists, we use it and avoid adding a searchOrCreates key to the appRaw object.
|
|
151
|
+
// Otherwise, we add a searchOrCreates object to the appRaw object, which defaults to an empty object.
|
|
152
|
+
if (appRaw.searchAndCreates) {
|
|
153
|
+
appRaw.searchAndCreates = {
|
|
154
|
+
...extras.searchAndCreates,
|
|
155
|
+
...appRaw.searchAndCreates,
|
|
156
|
+
};
|
|
157
|
+
} else {
|
|
158
|
+
appRaw.searchOrCreates = {
|
|
159
|
+
...extras.searchOrCreates,
|
|
160
|
+
...appRaw.searchOrCreates,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
140
163
|
|
|
141
164
|
_.each(appRaw.triggers, (trigger) => {
|
|
142
165
|
appRaw.triggers[trigger.key] = copyPropertiesFromResource(
|