zapier-platform-core 15.8.0 → 15.9.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/app-middlewares/after/large-response-cacher.js +21 -12
- package/src/app-middlewares/before/z-object.js +4 -1
- package/src/tools/cleaner.js +2 -1
- package/src/tools/create-file-stasher.js +5 -65
- package/src/tools/create-response-stasher.js +40 -0
- package/src/tools/uploader.js +69 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-core",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.9.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/",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"node-fetch": "2.6.7",
|
|
53
53
|
"oauth-sign": "0.9.0",
|
|
54
54
|
"semver": "7.5.2",
|
|
55
|
-
"zapier-platform-schema": "15.
|
|
55
|
+
"zapier-platform-schema": "15.9.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/node-fetch": "^2.6.11",
|
|
@@ -2,19 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
const constants = require('../../constants');
|
|
4
4
|
const cleaner = require('../../tools/cleaner');
|
|
5
|
+
const responseStasher = require('../../tools/create-response-stasher');
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const size =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
const largeResponseCachePointer = async (output) => {
|
|
8
|
+
const response = cleaner.maskOutput(output);
|
|
9
|
+
|
|
10
|
+
const autostashLimit = output.input._zapier.event.autostashPayloadOutputLimit;
|
|
11
|
+
|
|
12
|
+
const payload = JSON.stringify(response.results);
|
|
13
|
+
const size = payload.length;
|
|
14
|
+
|
|
15
|
+
// If autostash limit is defined, and is within the range, stash the response
|
|
16
|
+
// If it is -1, stash the response regardless of size
|
|
17
|
+
// If the limit is defined and is out of range, let lambda deal with it
|
|
18
|
+
if (
|
|
19
|
+
(autostashLimit &&
|
|
20
|
+
size >= constants.RESPONSE_SIZE_LIMIT &&
|
|
21
|
+
size <= autostashLimit) ||
|
|
22
|
+
autostashLimit === -1
|
|
23
|
+
) {
|
|
24
|
+
const url = await responseStasher(output.input, payload, size);
|
|
25
|
+
output.resultsUrl = url;
|
|
26
|
+
output.results = Array.isArray(output.results) ? [] : {};
|
|
18
27
|
}
|
|
19
28
|
return output;
|
|
20
29
|
};
|
|
@@ -29,7 +29,10 @@ const injectZObject = (input) => {
|
|
|
29
29
|
generateCallbackUrl: createCallbackHigherOrderFunction(input),
|
|
30
30
|
hash: hashing.hashify,
|
|
31
31
|
JSON: createJSONtool(),
|
|
32
|
-
require: (moduleName) =>
|
|
32
|
+
require: (moduleName) =>
|
|
33
|
+
require(require.resolve(moduleName, {
|
|
34
|
+
paths: module.paths.concat([process.cwd()]),
|
|
35
|
+
})),
|
|
33
36
|
stashFile: createFileStasher(input),
|
|
34
37
|
};
|
|
35
38
|
|
package/src/tools/cleaner.js
CHANGED
|
@@ -130,7 +130,8 @@ const createBundleBank = (appRaw, event = {}, serializeFunc = (x) => x) => {
|
|
|
130
130
|
}, {});
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
-
const maskOutput = (output) =>
|
|
133
|
+
const maskOutput = (output) =>
|
|
134
|
+
_.pick(output, 'results', 'status', 'resultsUrl');
|
|
134
135
|
|
|
135
136
|
// These normalize functions are called after the initial before middleware that
|
|
136
137
|
// cleans the request. The reason is that we need to know why a value is empty
|
|
@@ -9,15 +9,11 @@ const { randomBytes } = require('crypto');
|
|
|
9
9
|
|
|
10
10
|
const _ = require('lodash');
|
|
11
11
|
const contentDisposition = require('content-disposition');
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
const mime = require('mime-types');
|
|
14
14
|
|
|
15
|
-
const request = require('./request-client-internal');
|
|
16
15
|
const { UPLOAD_MAX_SIZE, NON_STREAM_UPLOAD_MAX_SIZE } = require('../constants');
|
|
17
|
-
|
|
18
|
-
const LENGTH_ERR_MESSAGE =
|
|
19
|
-
'We could not calculate the length of your file - please ' +
|
|
20
|
-
'pass a knownLength like z.stashFile(f, knownLength)';
|
|
16
|
+
const uploader = require('./uploader');
|
|
21
17
|
|
|
22
18
|
const DEFAULT_FILE_NAME = 'unnamedfile';
|
|
23
19
|
const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
|
|
@@ -175,64 +171,6 @@ const resolveToBufferStringStream = async (responseOrData) => {
|
|
|
175
171
|
);
|
|
176
172
|
};
|
|
177
173
|
|
|
178
|
-
const uploader = async (
|
|
179
|
-
signedPostData,
|
|
180
|
-
bufferStringStream,
|
|
181
|
-
knownLength,
|
|
182
|
-
filename,
|
|
183
|
-
contentType
|
|
184
|
-
) => {
|
|
185
|
-
filename = path.basename(filename).replace('"', '');
|
|
186
|
-
|
|
187
|
-
const fields = {
|
|
188
|
-
...signedPostData.fields,
|
|
189
|
-
'Content-Disposition': contentDisposition(filename),
|
|
190
|
-
'Content-Type': contentType,
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
const form = new FormData();
|
|
194
|
-
|
|
195
|
-
Object.entries(fields).forEach(([key, value]) => {
|
|
196
|
-
form.append(key, value);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
form.append('file', bufferStringStream, {
|
|
200
|
-
knownLength,
|
|
201
|
-
contentType,
|
|
202
|
-
filename,
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// Try to catch the missing length early, before upload to S3 fails.
|
|
206
|
-
try {
|
|
207
|
-
form.getLengthSync();
|
|
208
|
-
} catch (err) {
|
|
209
|
-
throw new Error(LENGTH_ERR_MESSAGE);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Send to S3 with presigned request.
|
|
213
|
-
const response = await request({
|
|
214
|
-
url: signedPostData.url,
|
|
215
|
-
method: 'POST',
|
|
216
|
-
body: form,
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
if (response.status === 204) {
|
|
220
|
-
return new URL(signedPostData.fields.key, signedPostData.url).href;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (
|
|
224
|
-
response.content &&
|
|
225
|
-
response.content.includes &&
|
|
226
|
-
response.content.includes(
|
|
227
|
-
'You must provide the Content-Length HTTP header.'
|
|
228
|
-
)
|
|
229
|
-
) {
|
|
230
|
-
throw new Error(LENGTH_ERR_MESSAGE);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
throw new Error(`Got ${response.status} - ${response.content}`);
|
|
234
|
-
};
|
|
235
|
-
|
|
236
174
|
const ensureUploadMaxSizeNotExceeded = (streamOrData, length) => {
|
|
237
175
|
let uploadMaxSize = NON_STREAM_UPLOAD_MAX_SIZE;
|
|
238
176
|
let uploadMethod = 'non-streaming';
|
|
@@ -242,7 +180,9 @@ const ensureUploadMaxSizeNotExceeded = (streamOrData, length) => {
|
|
|
242
180
|
}
|
|
243
181
|
|
|
244
182
|
if (length && length > uploadMaxSize) {
|
|
245
|
-
throw new Error(
|
|
183
|
+
throw new Error(
|
|
184
|
+
`${length} bytes is too big, ${uploadMaxSize} is the max for ${uploadMethod} data.`
|
|
185
|
+
);
|
|
246
186
|
}
|
|
247
187
|
};
|
|
248
188
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const uploader = require('./uploader');
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
|
|
7
|
+
const withRetry = async (fn, retries = 3, delay = 100, attempt = 0) => {
|
|
8
|
+
try {
|
|
9
|
+
return await fn();
|
|
10
|
+
} catch (error) {
|
|
11
|
+
if (attempt >= retries) {
|
|
12
|
+
throw error;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
16
|
+
return withRetry(fn, retries, delay, attempt + 1);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// responseStasher uploads the data and returns the URL that points to that data.
|
|
21
|
+
const stashResponse = async (input, response, size) => {
|
|
22
|
+
const rpc = _.get(input, '_zapier.rpc');
|
|
23
|
+
|
|
24
|
+
if (!rpc) {
|
|
25
|
+
throw new Error('rpc is not available');
|
|
26
|
+
}
|
|
27
|
+
const signedPostData = await rpc('get_presigned_upload_post_data');
|
|
28
|
+
return withRetry(
|
|
29
|
+
_.partial(
|
|
30
|
+
uploader,
|
|
31
|
+
signedPostData,
|
|
32
|
+
response.toString(), // accept JSON string to send to uploader.
|
|
33
|
+
size,
|
|
34
|
+
crypto.randomUUID() + '.txt',
|
|
35
|
+
'text/plain'
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
module.exports = stashResponse;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
const FormData = require('form-data');
|
|
4
|
+
const contentDisposition = require('content-disposition');
|
|
5
|
+
|
|
6
|
+
const request = require('./request-client-internal');
|
|
7
|
+
const LENGTH_ERR_MESSAGE =
|
|
8
|
+
'We could not calculate the length of your file - please ' +
|
|
9
|
+
'pass a knownLength like z.stashFile(f, knownLength)';
|
|
10
|
+
|
|
11
|
+
const uploader = async (
|
|
12
|
+
signedPostData,
|
|
13
|
+
bufferStringStream,
|
|
14
|
+
knownLength,
|
|
15
|
+
filename,
|
|
16
|
+
contentType
|
|
17
|
+
) => {
|
|
18
|
+
filename = path.basename(filename).replace('"', '');
|
|
19
|
+
|
|
20
|
+
const fields = {
|
|
21
|
+
...signedPostData.fields,
|
|
22
|
+
'Content-Disposition': contentDisposition(filename),
|
|
23
|
+
'Content-Type': contentType,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const form = new FormData();
|
|
27
|
+
|
|
28
|
+
Object.entries(fields).forEach(([key, value]) => {
|
|
29
|
+
form.append(key, value);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
form.append('file', bufferStringStream, {
|
|
33
|
+
knownLength,
|
|
34
|
+
contentType,
|
|
35
|
+
filename,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Try to catch the missing length early, before upload to S3 fails.
|
|
39
|
+
try {
|
|
40
|
+
form.getLengthSync();
|
|
41
|
+
} catch (err) {
|
|
42
|
+
throw new Error(LENGTH_ERR_MESSAGE);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Send to S3 with presigned request.
|
|
46
|
+
const response = await request({
|
|
47
|
+
url: signedPostData.url,
|
|
48
|
+
method: 'POST',
|
|
49
|
+
body: form,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (response.status === 204) {
|
|
53
|
+
return new URL(signedPostData.fields.key, signedPostData.url).href;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
response.content &&
|
|
58
|
+
response.content.includes &&
|
|
59
|
+
response.content.includes(
|
|
60
|
+
'You must provide the Content-Length HTTP header.'
|
|
61
|
+
)
|
|
62
|
+
) {
|
|
63
|
+
throw new Error(LENGTH_ERR_MESSAGE);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
throw new Error(`Got ${response.status} - ${response.content}`);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
module.exports = uploader;
|