zapier-platform-core 15.16.1 → 15.18.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/CHANGELOG.md +1 -3
- package/README.md +9 -3
- package/package.json +3 -3
- package/src/tools/create-cache.js +9 -4
- package/src/tools/create-lambda-handler.js +2 -1
- package/src/tools/create-rpc-client.js +31 -10
- package/src/tools/memory-checker.js +19 -10
- package/types/index.test-d.ts +35 -1
- package/types/zapier.custom.d.ts +25 -15
- package/types/zapier.generated.d.ts +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Zapier Platform Core
|
|
2
2
|
|
|
3
|
-
This is the
|
|
3
|
+
This is the SDK used in Zapier integrations.
|
|
4
4
|
|
|
5
5
|
## Development
|
|
6
6
|
|
|
7
|
+
See [CONTRIBUTING.md](https://github.com/zapier/zapier-platform/blob/main/CONTRIBUTING.md) and [ARCHITECTURE.md](https://github.com/zapier/zapier-platform/blob/main/packages/core/ARCHITECTURE.md) of this package in particular.
|
|
8
|
+
|
|
9
|
+
Useful commands:
|
|
10
|
+
|
|
7
11
|
* `npm install` for getting started
|
|
8
12
|
* `npm test` for running unit tests
|
|
9
13
|
* `npm run local-integration-test` for running integration tests locally
|
|
@@ -16,6 +20,8 @@ Make sure your AWS access key have permission to update and run Lambda functions
|
|
|
16
20
|
* `npm run deploy-integration-test` builds and deploys a zip to a function named `integration-test-cli` on Lambda
|
|
17
21
|
* `npm run lambda-integration-test` runs the integration test using the live Lambda function `integration-test-cli`
|
|
18
22
|
|
|
19
|
-
## Publishing
|
|
23
|
+
## Publishing
|
|
24
|
+
|
|
25
|
+
Only do this after merging your PR to `main`.
|
|
20
26
|
|
|
21
27
|
* `npm version [patch|minor|major]` will pull, test, update schema version in dependencies for this package, update docs, increment version in package.json, and push tags, which then will tell Travis to publish to npm
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-core",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.18.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.
|
|
56
|
+
"zapier-platform-schema": "15.18.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.
|
|
64
|
+
"mock-fs": "^5.3.0",
|
|
65
65
|
"nock": "^13.5.4",
|
|
66
66
|
"tsd": "^0.31.1"
|
|
67
67
|
},
|
|
@@ -12,7 +12,8 @@ const createCache = (input) => {
|
|
|
12
12
|
key,
|
|
13
13
|
value = null,
|
|
14
14
|
ttl = null,
|
|
15
|
-
scope = null
|
|
15
|
+
scope = null,
|
|
16
|
+
nx = null
|
|
16
17
|
) => {
|
|
17
18
|
if (!rpc) {
|
|
18
19
|
throw new Error('rpc is not available');
|
|
@@ -36,6 +37,10 @@ const createCache = (input) => {
|
|
|
36
37
|
);
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
if (nx !== null && !_.isBoolean(nx)) {
|
|
41
|
+
throw new TypeError('nx must be a boolean');
|
|
42
|
+
}
|
|
43
|
+
|
|
39
44
|
ensureJSONEncodable(value);
|
|
40
45
|
};
|
|
41
46
|
|
|
@@ -46,10 +51,10 @@ const createCache = (input) => {
|
|
|
46
51
|
const result = await rpc('zcache_get', key, scope);
|
|
47
52
|
return result ? JSON.parse(result) : null;
|
|
48
53
|
},
|
|
49
|
-
set: async (key, value, ttl = null, scope = null) => {
|
|
50
|
-
runValidationChecks(rpc, key, value, ttl, scope);
|
|
54
|
+
set: async (key, value, ttl = null, scope = null, nx = null) => {
|
|
55
|
+
runValidationChecks(rpc, key, value, ttl, scope, nx);
|
|
51
56
|
|
|
52
|
-
return await rpc('zcache_set', key, JSON.stringify(value), ttl, scope);
|
|
57
|
+
return await rpc('zcache_set', key, JSON.stringify(value), ttl, scope, nx);
|
|
53
58
|
},
|
|
54
59
|
delete: async (key, scope = null) => {
|
|
55
60
|
runValidationChecks(rpc, key, scope);
|
|
@@ -196,7 +196,8 @@ const createLambdaHandler = (appRawOrPath) => {
|
|
|
196
196
|
ZapierPromise.patchGlobal();
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
// If we're running out of memory, exit the process.
|
|
199
|
+
// If we're running out of memory or file descriptors, force exit the process.
|
|
200
|
+
// The backend will try again via @retry(ProcessExitedException).
|
|
200
201
|
checkMemory(event);
|
|
201
202
|
|
|
202
203
|
environmentTools.cleanEnvironment();
|
|
@@ -45,7 +45,7 @@ const rpcCursorMock = (cursorTestObj, method, key, value = null) => {
|
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
const createRpcClient = (event) => {
|
|
48
|
-
return function (method) {
|
|
48
|
+
return async function (method) {
|
|
49
49
|
const params = _.toArray(arguments);
|
|
50
50
|
params.shift();
|
|
51
51
|
|
|
@@ -97,25 +97,46 @@ const createRpcClient = (event) => {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
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
|
+
}
|
|
102
114
|
if (res.content) {
|
|
115
|
+
// check if the ids match
|
|
103
116
|
if (res.content.id !== id) {
|
|
104
117
|
throw new Error(
|
|
105
118
|
`Got id ${res.content.id} but expected ${id} when calling RPC`
|
|
106
119
|
);
|
|
107
120
|
}
|
|
108
|
-
|
|
121
|
+
if (res.content.error) {
|
|
122
|
+
throw new Error(res.content.error);
|
|
123
|
+
}
|
|
124
|
+
return res.content.result;
|
|
109
125
|
} else {
|
|
110
126
|
throw new Error(`Got a ${res.status} when calling RPC`);
|
|
111
127
|
}
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
+
);
|
|
116
135
|
}
|
|
117
|
-
|
|
118
|
-
|
|
136
|
+
// sleep for 100ms before retrying
|
|
137
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
119
140
|
};
|
|
120
141
|
};
|
|
121
142
|
|
|
@@ -8,22 +8,31 @@ let zrun = 0;
|
|
|
8
8
|
const checkMemory = (event) => {
|
|
9
9
|
event = event || {};
|
|
10
10
|
|
|
11
|
+
let memUsage;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
memUsage = process.memoryUsage();
|
|
15
|
+
} catch (err) {
|
|
16
|
+
if (err.code === 'EMFILE') {
|
|
17
|
+
console.error(
|
|
18
|
+
'Force killing process by Zapier for too many open file descriptors'
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
/* eslint no-process-exit: 0 */
|
|
22
|
+
process.exit(1);
|
|
23
|
+
} else {
|
|
24
|
+
throw err;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
11
28
|
zrun += 1;
|
|
12
29
|
if (!constants.IS_TESTING && !event.calledFromCli) {
|
|
13
|
-
console.log(
|
|
14
|
-
'ZID:',
|
|
15
|
-
zid,
|
|
16
|
-
'pid',
|
|
17
|
-
'ZRUN:',
|
|
18
|
-
zrun,
|
|
19
|
-
'RSSMEM:',
|
|
20
|
-
process.memoryUsage()
|
|
21
|
-
);
|
|
30
|
+
console.log('ZID:', zid, 'pid', 'ZRUN:', zrun, 'RSSMEM:', memUsage);
|
|
22
31
|
}
|
|
23
32
|
|
|
24
33
|
if (
|
|
25
34
|
zrun > constants.KILL_MIN_LIMIT &&
|
|
26
|
-
|
|
35
|
+
memUsage.rss > constants.KILL_MAX_LIMIT
|
|
27
36
|
) {
|
|
28
37
|
// should throw "Process exited before completing request"
|
|
29
38
|
// and a @retry in our stack will attempt again - and this
|
package/types/index.test-d.ts
CHANGED
|
@@ -18,7 +18,7 @@ import type {
|
|
|
18
18
|
Trigger,
|
|
19
19
|
} from './zapier.generated';
|
|
20
20
|
|
|
21
|
-
import { expectType } from 'tsd';
|
|
21
|
+
import { expectType, expectDeprecated } from 'tsd';
|
|
22
22
|
|
|
23
23
|
const basicDisplay: BasicDisplay = {
|
|
24
24
|
label: 'some-label',
|
|
@@ -166,3 +166,37 @@ const app: App = {
|
|
|
166
166
|
searches: { [search.key]: search },
|
|
167
167
|
};
|
|
168
168
|
expectType<App>(app);
|
|
169
|
+
|
|
170
|
+
// Return types from z.request
|
|
171
|
+
async (z: ZObject) => {
|
|
172
|
+
const resp = await z.request<{ id: number; name: string }>(
|
|
173
|
+
'https://example.com'
|
|
174
|
+
);
|
|
175
|
+
expectType<{ id: number; name: string }>(resp.data);
|
|
176
|
+
expectDeprecated(resp.json);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
async (z: ZObject) => {
|
|
180
|
+
const resp = await z.request<{ id: number; name: string }>({
|
|
181
|
+
url: 'https://example.com',
|
|
182
|
+
});
|
|
183
|
+
expectType<{ id: number; name: string }>(resp.data);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Return types from z.request (raw)
|
|
187
|
+
async (z: ZObject) => {
|
|
188
|
+
const resp = await z.request<{ id: number; name: string }>(
|
|
189
|
+
'https://example.com',
|
|
190
|
+
{ raw: true }
|
|
191
|
+
);
|
|
192
|
+
const result = await resp.json();
|
|
193
|
+
expectType<{ id: number; name: string }>(result);
|
|
194
|
+
};
|
|
195
|
+
async (z: ZObject) => {
|
|
196
|
+
const resp = await z.request<{ id: number; name: string }>({
|
|
197
|
+
raw: true,
|
|
198
|
+
url: 'https://example.com',
|
|
199
|
+
});
|
|
200
|
+
const result = await resp.json();
|
|
201
|
+
expectType<{ id: number; name: string }>(result);
|
|
202
|
+
};
|
package/types/zapier.custom.d.ts
CHANGED
|
@@ -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 {
|
|
@@ -114,16 +117,17 @@ interface BaseHttpResponse {
|
|
|
114
117
|
request: HttpRequestOptions;
|
|
115
118
|
}
|
|
116
119
|
|
|
117
|
-
export interface HttpResponse extends BaseHttpResponse {
|
|
120
|
+
export interface HttpResponse<T = any> extends BaseHttpResponse {
|
|
118
121
|
content: string;
|
|
119
|
-
data
|
|
120
|
-
|
|
122
|
+
data: T;
|
|
123
|
+
/** @deprecated Since v10.0.0. Use `data` instead. */
|
|
124
|
+
json?: T;
|
|
121
125
|
}
|
|
122
126
|
|
|
123
|
-
export interface RawHttpResponse extends BaseHttpResponse {
|
|
127
|
+
export interface RawHttpResponse<T = any> extends BaseHttpResponse {
|
|
124
128
|
body: NodeJS.ReadableStream;
|
|
125
129
|
buffer(): Promise<Buffer>;
|
|
126
|
-
json(): Promise<
|
|
130
|
+
json(): Promise<T>;
|
|
127
131
|
text(): Promise<string>;
|
|
128
132
|
}
|
|
129
133
|
|
|
@@ -135,15 +139,20 @@ type DehydrateFunc = <T>(
|
|
|
135
139
|
export interface ZObject {
|
|
136
140
|
request: {
|
|
137
141
|
// most specific overloads go first
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
<T = any>(
|
|
143
|
+
url: string,
|
|
144
|
+
options: HttpRequestOptions & { raw: true }
|
|
145
|
+
): Promise<RawHttpResponse<T>>;
|
|
146
|
+
<T = any>(
|
|
147
|
+
options: HttpRequestOptions & { raw: true; url: string }
|
|
148
|
+
): Promise<RawHttpResponse<T>>;
|
|
149
|
+
|
|
150
|
+
<T = any>(url: string, options?: HttpRequestOptions): Promise<
|
|
151
|
+
HttpResponse<T>
|
|
140
152
|
>;
|
|
141
|
-
(options: HttpRequestOptions & {
|
|
142
|
-
|
|
153
|
+
<T = any>(options: HttpRequestOptions & { url: string }): Promise<
|
|
154
|
+
HttpResponse<T>
|
|
143
155
|
>;
|
|
144
|
-
|
|
145
|
-
(url: string, options?: HttpRequestOptions): Promise<HttpResponse>;
|
|
146
|
-
(options: HttpRequestOptions & { url: string }): Promise<HttpResponse>;
|
|
147
156
|
};
|
|
148
157
|
|
|
149
158
|
console: Console;
|
|
@@ -199,6 +208,7 @@ export interface ZObject {
|
|
|
199
208
|
ExpiredAuthError: typeof ExpiredAuthError;
|
|
200
209
|
RefreshAuthError: typeof RefreshAuthError;
|
|
201
210
|
ThrottledError: typeof ThrottledError;
|
|
211
|
+
ResponseError: typeof ResponseError;
|
|
202
212
|
};
|
|
203
213
|
|
|
204
214
|
cache: {
|
|
@@ -221,14 +231,14 @@ export type PerformFunction<BI = Record<string, any>, R = any> = (
|
|
|
221
231
|
|
|
222
232
|
export type BeforeRequestMiddleware = (
|
|
223
233
|
request: HttpRequestOptions,
|
|
224
|
-
z
|
|
225
|
-
bundle
|
|
234
|
+
z: ZObject,
|
|
235
|
+
bundle: Bundle
|
|
226
236
|
) => HttpRequestOptions | Promise<HttpRequestOptions>;
|
|
227
237
|
|
|
228
238
|
export type AfterResponseMiddleware = (
|
|
229
239
|
response: HttpResponse,
|
|
230
240
|
z: ZObject,
|
|
231
|
-
bundle
|
|
241
|
+
bundle: Bundle
|
|
232
242
|
) => HttpResponse | Promise<HttpResponse>;
|
|
233
243
|
|
|
234
244
|
export interface BufferedItem<InputData = { [x: string]: any }> {
|