zapier-platform-core 15.16.0 → 15.17.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapier-platform-core",
3
- "version": "15.16.0",
3
+ "version": "15.17.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/",
@@ -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.16.0"
56
+ "zapier-platform-schema": "15.17.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/node-fetch": "^2.6.11",
@@ -61,7 +61,7 @@
61
61
  "aws-sdk": "^2.1397.0",
62
62
  "dicer": "^0.3.1",
63
63
  "fs-extra": "^11.1.1",
64
- "mock-fs": "^5.2.0",
64
+ "mock-fs": "^5.3.0",
65
65
  "nock": "^13.5.4",
66
66
  "tsd": "^0.31.1"
67
67
  },
package/src/constants.js CHANGED
@@ -14,6 +14,8 @@ const RESPONSE_SIZE_LIMIT = 6291456;
14
14
  const UPLOAD_MAX_SIZE = 1000 * 1000 * 1000 * 1; // 1GB, in zapier backend too
15
15
  const NON_STREAM_UPLOAD_MAX_SIZE = 1000 * 1000 * 150;
16
16
 
17
+ const ENCODED_FILENAME_MAX_LENGTH = 1000; // 1KB - S3 Metadata max is 2048
18
+
17
19
  const HYDRATE_DIRECTIVE_HOIST = '$HOIST$';
18
20
 
19
21
  const RENDER_ONLY_METHODS = [
@@ -58,6 +60,7 @@ const PACKAGE_VERSION = packageJson.version;
58
60
  module.exports = {
59
61
  DEFAULT_LOGGING_HTTP_API_KEY,
60
62
  DEFAULT_LOGGING_HTTP_ENDPOINT,
63
+ ENCODED_FILENAME_MAX_LENGTH,
61
64
  HYDRATE_DIRECTIVE_HOIST,
62
65
  IS_TESTING,
63
66
  KILL_MAX_LIMIT,
@@ -12,7 +12,11 @@ const contentDisposition = require('content-disposition');
12
12
 
13
13
  const mime = require('mime-types');
14
14
 
15
- const { UPLOAD_MAX_SIZE, NON_STREAM_UPLOAD_MAX_SIZE } = require('../constants');
15
+ const {
16
+ ENCODED_FILENAME_MAX_LENGTH,
17
+ UPLOAD_MAX_SIZE,
18
+ NON_STREAM_UPLOAD_MAX_SIZE,
19
+ } = require('../constants');
16
20
  const uploader = require('./uploader');
17
21
 
18
22
  const DEFAULT_FILE_NAME = 'unnamedfile';
@@ -186,6 +190,24 @@ const ensureUploadMaxSizeNotExceeded = (streamOrData, length) => {
186
190
  }
187
191
  };
188
192
 
193
+ // S3's max metadata size is 2KB
194
+ // If the filename needs to be encoded, both the filename
195
+ // and encoded filename are included in the Content-Disposition header
196
+ const ensureMetadataMaxSizeNotExceeded = (filename) => {
197
+ const filenameMaxSize = ENCODED_FILENAME_MAX_LENGTH;
198
+ if (filename) {
199
+ const encodedFilename = encodeURIComponent(filename);
200
+ if (
201
+ encodedFilename !== filename &&
202
+ encodedFilename.length > filenameMaxSize
203
+ ) {
204
+ throw new Error(
205
+ `URI-Encoded Filename is too long at ${encodedFilename.length}, ${ENCODED_FILENAME_MAX_LENGTH} is the max.`
206
+ );
207
+ }
208
+ }
209
+ };
210
+
189
211
  // Designed to be some user provided function/api.
190
212
  const createFileStasher = (input) => {
191
213
  const rpc = _.get(input, '_zapier.rpc');
@@ -247,6 +269,8 @@ const createFileStasher = (input) => {
247
269
  const finalLength = knownLength || length;
248
270
  ensureUploadMaxSizeNotExceeded(streamOrData, finalLength);
249
271
 
272
+ ensureMetadataMaxSizeNotExceeded(filename || _filename);
273
+
250
274
  return uploader(
251
275
  signedPostData,
252
276
  streamOrData,
@@ -330,6 +330,11 @@ const sendLog = async (logStreamFactory, options, event, message, data) => {
330
330
  toStdout(event, message, safeData);
331
331
  }
332
332
 
333
+ if (event.customLogger && typeof event.customLogger === 'function') {
334
+ // For `zapier invoke` command
335
+ event.customLogger(safeMessage, safeData);
336
+ }
337
+
333
338
  if (options.logBuffer && data.log_type === 'console') {
334
339
  // Cap size of messages in log buffer, in case devs log humongous things.
335
340
  options.logBuffer.push({ type: safeData.log_type, message: safeMessage });
@@ -31,17 +31,42 @@ const rpcCacheMock = (zcacheTestObj, method, key, value = null, ttl = null) => {
31
31
  throw new Error(`Unexpected method '${method}'`);
32
32
  };
33
33
 
34
+ const rpcCursorMock = (cursorTestObj, method, key, value = null) => {
35
+ if (method === 'get_cursor') {
36
+ return cursorTestObj[key] || null;
37
+ }
38
+
39
+ if (method === 'set_cursor') {
40
+ cursorTestObj[key] = value;
41
+ return null;
42
+ }
43
+
44
+ throw new Error(`Unexpected method '${method}'`);
45
+ };
46
+
34
47
  const createRpcClient = (event) => {
35
- return function (method) {
48
+ return async function (method) {
36
49
  const params = _.toArray(arguments);
37
50
  params.shift();
38
51
 
39
52
  const zcacheMethods = ['zcache_get', 'zcache_set', 'zcache_delete'];
40
- if (zcacheMethods.includes(method) && _.isPlainObject(event.zcacheTestObj)) {
53
+ if (
54
+ zcacheMethods.includes(method) &&
55
+ _.isPlainObject(event.zcacheTestObj)
56
+ ) {
41
57
  const [key, value = null] = params;
42
58
  return rpcCacheMock(event.zcacheTestObj, method, key, value);
43
59
  }
44
60
 
61
+ const cursorMethods = ['get_cursor', 'set_cursor'];
62
+ if (
63
+ cursorMethods.includes(method) &&
64
+ _.isPlainObject(event.cursorTestObj)
65
+ ) {
66
+ const [key, value = null] = params;
67
+ return rpcCursorMock(event.cursorTestObj, method, key, value);
68
+ }
69
+
45
70
  const id = genId();
46
71
  const body = JSON.stringify({
47
72
  id,
@@ -72,25 +97,46 @@ const createRpcClient = (event) => {
72
97
  }
73
98
  }
74
99
 
75
- return request(req)
76
- .then((res) => {
100
+ // RPC can fail, so let's retry.
101
+ // Be careful what we throw here as this will be forwarded to the user.
102
+ const maxRetries = 3;
103
+ let attempt = 0;
104
+ let res;
105
+
106
+ while (attempt < maxRetries) {
107
+ // We will throw here, which will be caught by catch logic to either retry or bubble up.
108
+ try {
109
+ res = await request(req);
110
+
111
+ if (res.status > 500) {
112
+ throw new Error('Unable to reach the RPC server');
113
+ }
77
114
  if (res.content) {
115
+ // check if the ids match
78
116
  if (res.content.id !== id) {
79
117
  throw new Error(
80
118
  `Got id ${res.content.id} but expected ${id} when calling RPC`
81
119
  );
82
120
  }
83
- return res.content;
121
+ if (res.content.error) {
122
+ throw new Error(res.content.error);
123
+ }
124
+ return res.content.result;
84
125
  } else {
85
126
  throw new Error(`Got a ${res.status} when calling RPC`);
86
127
  }
87
- })
88
- .then((content) => {
89
- if (content.error) {
90
- throw new Error(content.error);
128
+ } catch (err) {
129
+ attempt++;
130
+
131
+ if (attempt === maxRetries || (res && res.status < 500)) {
132
+ throw new Error(
133
+ `RPC request failed after ${attempt} attempts: ${err.message}`
134
+ );
91
135
  }
92
- return content.result;
93
- });
136
+ // sleep for 100ms before retrying
137
+ await new Promise((resolve) => setTimeout(resolve, 100));
138
+ }
139
+ }
94
140
  };
95
141
  };
96
142
 
@@ -73,6 +73,9 @@ declare class RefreshAuthError extends Error {}
73
73
  declare class ThrottledError extends Error {
74
74
  constructor(message: string, delay?: number);
75
75
  }
76
+ declare class ResponseError extends Error {
77
+ constructor(response: HttpResponse);
78
+ }
76
79
 
77
80
  // copied http stuff from external typings
78
81
  export interface HttpRequestOptions {
@@ -135,12 +138,13 @@ type DehydrateFunc = <T>(
135
138
  export interface ZObject {
136
139
  request: {
137
140
  // most specific overloads go first
138
- (url: string, options: HttpRequestOptions & { raw: true }): Promise<
139
- RawHttpResponse
140
- >;
141
- (options: HttpRequestOptions & { raw: true; url: string }): Promise<
142
- RawHttpResponse
143
- >;
141
+ (
142
+ url: string,
143
+ options: HttpRequestOptions & { raw: true }
144
+ ): Promise<RawHttpResponse>;
145
+ (
146
+ options: HttpRequestOptions & { raw: true; url: string }
147
+ ): Promise<RawHttpResponse>;
144
148
 
145
149
  (url: string, options?: HttpRequestOptions): Promise<HttpResponse>;
146
150
  (options: HttpRequestOptions & { url: string }): Promise<HttpResponse>;
@@ -199,6 +203,7 @@ export interface ZObject {
199
203
  ExpiredAuthError: typeof ExpiredAuthError;
200
204
  RefreshAuthError: typeof RefreshAuthError;
201
205
  ThrottledError: typeof ThrottledError;
206
+ ResponseError: typeof ResponseError;
202
207
  };
203
208
 
204
209
  cache: {
@@ -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.16.0
7
+ * zapier-platform-schema version: 15.17.0
8
8
  * schema-to-ts compiler version: 0.1.0
9
9
  */
10
10