zapier-platform-core 17.5.0 → 17.7.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/index.js +1 -0
- package/index.mjs +3 -0
- package/package.json +2 -2
- package/src/app-middlewares/before/z-object.js +3 -2
- package/src/checks/index.js +1 -1
- package/src/checks/search-is-array-or-envelope.js +60 -0
- package/src/index.js +2 -0
- package/src/tools/console-singleton.js +49 -0
- package/src/tools/create-logger.js +68 -7
- package/types/console.test-d.ts +24 -0
- package/types/custom.d.ts +2 -5
- package/types/functions.d.ts +11 -3
- package/types/schemas.generated.d.ts +4 -1
- package/src/checks/search-is-array.js +0 -23
package/index.js
CHANGED
|
@@ -2,4 +2,5 @@ const zapier = require('./src');
|
|
|
2
2
|
zapier.version = require('./package.json').version;
|
|
3
3
|
zapier.tools = require('./src/tools/exported');
|
|
4
4
|
zapier.errors = require('./src/errors');
|
|
5
|
+
zapier.console = require('./src/tools/console-singleton').consoleProxy;
|
|
5
6
|
module.exports = zapier;
|
package/index.mjs
CHANGED
|
@@ -2,9 +2,11 @@ import zapier from './src/index.js';
|
|
|
2
2
|
import packageJson from './package.json' with { type: 'json' };
|
|
3
3
|
import _tools from './src/tools/exported.js';
|
|
4
4
|
import _errors from './src/errors.js';
|
|
5
|
+
import { consoleProxy } from './src/tools/console-singleton.js';
|
|
5
6
|
zapier.version = packageJson.version;
|
|
6
7
|
zapier.tools = _tools;
|
|
7
8
|
zapier.errors = _errors;
|
|
9
|
+
zapier.console = consoleProxy;
|
|
8
10
|
// Allows `import { ... } from 'zapier-platform-core'`
|
|
9
11
|
export const {
|
|
10
12
|
createAppHandler,
|
|
@@ -16,6 +18,7 @@ export const {
|
|
|
16
18
|
defineSearch,
|
|
17
19
|
defineTrigger,
|
|
18
20
|
integrationTestHandler,
|
|
21
|
+
console,
|
|
19
22
|
tools,
|
|
20
23
|
version,
|
|
21
24
|
errors,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-core",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.7.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/",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"node-fetch": "2.7.0",
|
|
64
64
|
"oauth-sign": "0.9.0",
|
|
65
65
|
"semver": "7.7.1",
|
|
66
|
-
"zapier-platform-schema": "17.
|
|
66
|
+
"zapier-platform-schema": "17.7.0"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@types/node-fetch": "^2.6.11",
|
|
@@ -10,7 +10,7 @@ const createJSONtool = require('../../tools/create-json-tool');
|
|
|
10
10
|
const createStoreKeyTool = require('../../tools/create-storekey-tool');
|
|
11
11
|
const createCallbackHigherOrderFunction = require('../../tools/create-callback-wrapper');
|
|
12
12
|
const createLegacyScriptingRunner = require('../../tools/create-legacy-scripting-runner');
|
|
13
|
-
const
|
|
13
|
+
const { initialize } = require('../../tools/console-singleton');
|
|
14
14
|
const errors = require('../../errors');
|
|
15
15
|
const hashing = require('../../tools/hashing');
|
|
16
16
|
|
|
@@ -19,9 +19,10 @@ const hashing = require('../../tools/hashing');
|
|
|
19
19
|
*/
|
|
20
20
|
const injectZObject = (input) => {
|
|
21
21
|
const bundle = _.get(input, '_zapier.event.bundle', {});
|
|
22
|
+
|
|
22
23
|
const zRoot = {
|
|
23
24
|
cache: createCache(input),
|
|
24
|
-
console:
|
|
25
|
+
console: initialize(input),
|
|
25
26
|
cursor: createStoreKeyTool(input),
|
|
26
27
|
dehydrate: createDehydrator(input, 'method'),
|
|
27
28
|
dehydrateFile: createDehydrator(input, 'file'),
|
package/src/checks/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
createIsObject: require('./create-is-object'),
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
searchIsArrayOrEnvelope: require('./search-is-array-or-envelope'),
|
|
5
5
|
|
|
6
6
|
triggerIsArray: require('./trigger-is-array'),
|
|
7
7
|
triggerIsObject: require('./trigger-is-object'),
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { simpleTruncate } = require('../tools/data');
|
|
5
|
+
|
|
6
|
+
const isSearch = require('./is-search');
|
|
7
|
+
|
|
8
|
+
const hasCanPaginate = (searchKey, compiledApp) => {
|
|
9
|
+
const canPaginate =
|
|
10
|
+
compiledApp?.searches?.[searchKey]?.operation?.canPaginate;
|
|
11
|
+
return canPaginate;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
Searches should return an array of objects,
|
|
16
|
+
or a response envelope like { results: [...], paging_token: '...' }
|
|
17
|
+
when canPaginate is true.
|
|
18
|
+
*/
|
|
19
|
+
const searchIsArrayOrEnvelope = {
|
|
20
|
+
name: 'searchIsArrayOrEnvelope',
|
|
21
|
+
shouldRun: isSearch,
|
|
22
|
+
run: (method, results, compiledApp) => {
|
|
23
|
+
const searchKey = method.split('.', 2)[1];
|
|
24
|
+
const truncatedResults = simpleTruncate(JSON.stringify(results), 50);
|
|
25
|
+
|
|
26
|
+
if (hasCanPaginate(searchKey, compiledApp)) {
|
|
27
|
+
// if paging is supported and results is an object (indicating pagination), it must have results and paging_token
|
|
28
|
+
if (_.isPlainObject(results)) {
|
|
29
|
+
if (!_.has(results, 'results') || !_.has(results, 'paging_token')) {
|
|
30
|
+
return [
|
|
31
|
+
`Paginated search results must be an object containing results and paging_token, got: ${truncatedResults}`,
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
if (
|
|
35
|
+
!_.isString(results.paging_token) &&
|
|
36
|
+
!_.isNull(results.paging_token)
|
|
37
|
+
) {
|
|
38
|
+
return [
|
|
39
|
+
`"paging_token" must be a string or null, got: ${typeof results.paging_token}`,
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
// pass to array check below
|
|
43
|
+
results = results.results;
|
|
44
|
+
} else {
|
|
45
|
+
return [
|
|
46
|
+
`Paginated search results must be an object, got: ${typeof results}, (${truncatedResults})`,
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!_.isArray(results)) {
|
|
52
|
+
return [
|
|
53
|
+
`Search results must be an array, got: ${typeof results}, (${truncatedResults})`,
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
module.exports = searchIsArrayOrEnvelope;
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const createLambdaHandler = require('./tools/create-lambda-handler');
|
|
4
4
|
const createAppTester = require('./tools/create-app-tester');
|
|
5
|
+
const { consoleProxy } = require('./tools/console-singleton');
|
|
5
6
|
|
|
6
7
|
let _integrationTestHandler;
|
|
7
8
|
const integrationTestHandler = (event, context, callback) => {
|
|
@@ -15,5 +16,6 @@ module.exports = {
|
|
|
15
16
|
createAppHandler: createLambdaHandler,
|
|
16
17
|
createAppTester,
|
|
17
18
|
integrationTestHandler,
|
|
19
|
+
console: consoleProxy,
|
|
18
20
|
...require('./typeHelpers'),
|
|
19
21
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const createLoggerConsole = require('./create-logger-console');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shared console instance that can be used standalone or as z.console.
|
|
7
|
+
* Uses createLoggerConsole to create the single instance shared between both.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Shared console instance - will be initialized by middleware
|
|
11
|
+
let loggerConsole = null;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Initialize the console with the input context from middleware.
|
|
15
|
+
* This is called by the z-object middleware and uses createLoggerConsole.
|
|
16
|
+
* Creates a new logger console for each Lambda invocation to ensure proper isolation.
|
|
17
|
+
* Returns the shared console instance for z.console to use.
|
|
18
|
+
*/
|
|
19
|
+
const initialize = (input) => {
|
|
20
|
+
// Always create a new logger console for each invocation to ensure
|
|
21
|
+
// log context isolation between Lambda invocations
|
|
22
|
+
loggerConsole = createLoggerConsole(input);
|
|
23
|
+
return loggerConsole;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Reset the singleton for testing purposes
|
|
28
|
+
*/
|
|
29
|
+
const reset = () => {
|
|
30
|
+
loggerConsole = null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Proxy that behaves like a console object.
|
|
35
|
+
* Forwards calls to loggerConsole if initialized, otherwise to global console.
|
|
36
|
+
*/
|
|
37
|
+
const consoleProxy = new Proxy(console, {
|
|
38
|
+
get(target, prop, receiver) {
|
|
39
|
+
// Use loggerConsole if initialized, otherwise fall back to global console
|
|
40
|
+
const actualConsole = loggerConsole || target;
|
|
41
|
+
return Reflect.get(actualConsole, prop, actualConsole);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
consoleProxy,
|
|
47
|
+
initialize,
|
|
48
|
+
reset,
|
|
49
|
+
};
|
|
@@ -32,16 +32,68 @@ const LOG_STREAM_BYTES_LIMIT = 15 * 1024 * 1024;
|
|
|
32
32
|
|
|
33
33
|
const DEFAULT_LOGGER_TIMEOUT = 200;
|
|
34
34
|
|
|
35
|
+
// Will be initialized lazily
|
|
36
|
+
const SAFE_AUTH_DATA_KEYS = new Set();
|
|
37
|
+
|
|
35
38
|
const sleep = promisify(setTimeout);
|
|
36
39
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
const initSafeAuthDataKeys = () => {
|
|
41
|
+
// An authData key in (safePrefixes x safeSuffixes) is considered safe to log
|
|
42
|
+
// uncensored
|
|
43
|
+
const safePrefixes = [
|
|
44
|
+
'account',
|
|
45
|
+
'bot_user',
|
|
46
|
+
'cloud',
|
|
47
|
+
'cloud_site',
|
|
48
|
+
'company',
|
|
49
|
+
'domain',
|
|
50
|
+
'email',
|
|
51
|
+
'environment',
|
|
52
|
+
'location',
|
|
53
|
+
'org',
|
|
54
|
+
'organization',
|
|
55
|
+
'project',
|
|
56
|
+
'region',
|
|
57
|
+
'scope',
|
|
58
|
+
'scopes',
|
|
59
|
+
'site',
|
|
60
|
+
'subdomain',
|
|
61
|
+
'team',
|
|
62
|
+
'token_type',
|
|
63
|
+
'user',
|
|
64
|
+
'workspace',
|
|
65
|
+
];
|
|
66
|
+
const safeSuffixes = ['', '_id', '_name', 'id', 'name'];
|
|
67
|
+
for (const prefix of safePrefixes) {
|
|
68
|
+
for (const suffix of safeSuffixes) {
|
|
69
|
+
SAFE_AUTH_DATA_KEYS.add(prefix + suffix);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const isUrl = (value) => {
|
|
75
|
+
if (!value || typeof value !== 'string') {
|
|
43
76
|
return false;
|
|
44
77
|
}
|
|
78
|
+
const commonProtocols = [
|
|
79
|
+
'https://',
|
|
80
|
+
'http://',
|
|
81
|
+
'ftp://',
|
|
82
|
+
'ftps://',
|
|
83
|
+
'file://',
|
|
84
|
+
];
|
|
85
|
+
for (const protocol of commonProtocols) {
|
|
86
|
+
if (value.startsWith(protocol)) {
|
|
87
|
+
try {
|
|
88
|
+
// eslint-disable-next-line no-new
|
|
89
|
+
new URL(value);
|
|
90
|
+
return true;
|
|
91
|
+
} catch (e) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
45
97
|
};
|
|
46
98
|
|
|
47
99
|
const MAX_LENGTH = 3500;
|
|
@@ -136,6 +188,13 @@ const attemptFindSecretsInStr = (s, isGettingNewSecret) => {
|
|
|
136
188
|
return findSensitiveValues(parsedRespContent);
|
|
137
189
|
};
|
|
138
190
|
|
|
191
|
+
const isSafeAuthDataKey = (key) => {
|
|
192
|
+
if (SAFE_AUTH_DATA_KEYS.size === 0) {
|
|
193
|
+
initSafeAuthDataKeys();
|
|
194
|
+
}
|
|
195
|
+
return SAFE_AUTH_DATA_KEYS.has(key.toLowerCase());
|
|
196
|
+
};
|
|
197
|
+
|
|
139
198
|
const buildSensitiveValues = (event, data) => {
|
|
140
199
|
const bundle = event.bundle || {};
|
|
141
200
|
const authData = bundle.authData || {};
|
|
@@ -147,7 +206,9 @@ const buildSensitiveValues = (event, data) => {
|
|
|
147
206
|
if (isSensitiveKey(key)) {
|
|
148
207
|
return true;
|
|
149
208
|
}
|
|
150
|
-
|
|
209
|
+
if (isSafeAuthDataKey(key)) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
151
212
|
if (isUrl(value) && !isUrlWithSecrets(value)) {
|
|
152
213
|
return false;
|
|
153
214
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { expectType } from 'tsd';
|
|
2
|
+
import { console } from '..';
|
|
3
|
+
|
|
4
|
+
// Test that console is exported and has the right type
|
|
5
|
+
expectType<Console>(console);
|
|
6
|
+
|
|
7
|
+
// Test that console has expected methods with proper signatures
|
|
8
|
+
expectType<{
|
|
9
|
+
(...data: any[]): void;
|
|
10
|
+
(message?: any, ...optionalParams: any[]): void;
|
|
11
|
+
}>(console.log);
|
|
12
|
+
expectType<{
|
|
13
|
+
(...data: any[]): void;
|
|
14
|
+
(message?: any, ...optionalParams: any[]): void;
|
|
15
|
+
}>(console.error);
|
|
16
|
+
expectType<{
|
|
17
|
+
(...data: any[]): void;
|
|
18
|
+
(message?: any, ...optionalParams: any[]): void;
|
|
19
|
+
}>(console.warn);
|
|
20
|
+
|
|
21
|
+
// Test that console can be used for logging
|
|
22
|
+
console.log('test message');
|
|
23
|
+
console.error('test error');
|
|
24
|
+
console.warn('test warning');
|
package/types/custom.d.ts
CHANGED
|
@@ -10,13 +10,10 @@ import { Headers } from 'node-fetch';
|
|
|
10
10
|
|
|
11
11
|
// The EXPORTED OBJECT
|
|
12
12
|
export const version: string;
|
|
13
|
-
export const tools: {
|
|
14
|
-
|
|
15
|
-
};
|
|
13
|
+
export const tools: { env: { inject: (filename?: string) => void } };
|
|
14
|
+
export const console: Console;
|
|
16
15
|
export const errors: ErrorsModule;
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
17
|
// see: https://github.com/zapier/zapier-platform-cli/issues/339#issue-336888249
|
|
21
18
|
export const createAppTester: (
|
|
22
19
|
appRaw: object,
|
package/types/functions.d.ts
CHANGED
|
@@ -118,9 +118,17 @@ export type CreatePerformGet<
|
|
|
118
118
|
> = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
|
-
*
|
|
121
|
+
* Helper type for search results that can optionally include pagination.
|
|
122
|
+
* Returns either:
|
|
123
|
+
* - an array of objects, matching the search query.
|
|
124
|
+
* - an object with a `results` array of objects and a `paging_token` string.
|
|
122
125
|
*
|
|
123
|
-
*
|
|
126
|
+
* When `canPaginate` is true for the search, the object shape is required.
|
|
127
|
+
*/
|
|
128
|
+
type SearchResult<T> = T[] | { results: T[], paging_token: string };
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Search for objects on a partner API.
|
|
124
132
|
*
|
|
125
133
|
* @remarks
|
|
126
134
|
* This type requires a one-item array. Multiple items *can* be
|
|
@@ -130,7 +138,7 @@ export type CreatePerformGet<
|
|
|
130
138
|
export type SearchPerform<
|
|
131
139
|
$InputData extends DefaultInputData = DefaultInputData,
|
|
132
140
|
$Return extends {} = {},
|
|
133
|
-
> = (z: ZObject, bundle: Bundle<$InputData>) =>
|
|
141
|
+
> = (z: ZObject, bundle: Bundle<$InputData>) => SearchResult<$Return> | Promise<SearchResult<$Return>>;
|
|
134
142
|
|
|
135
143
|
/**
|
|
136
144
|
* Follow up a search's perform with additional data.
|
|
@@ -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: 17.
|
|
7
|
+
* zapier-platform-schema version: 17.6.0
|
|
8
8
|
* schema-to-ts compiler version: 0.1.0
|
|
9
9
|
*/
|
|
10
10
|
import type {
|
|
@@ -1193,6 +1193,9 @@ export interface BasicSearchOperation<
|
|
|
1193
1193
|
*/
|
|
1194
1194
|
performGet?: Request | SearchPerformGet<InferInputData<$InputFields>>;
|
|
1195
1195
|
|
|
1196
|
+
/** Does this search support pagination? */
|
|
1197
|
+
canPaginate?: boolean;
|
|
1198
|
+
|
|
1196
1199
|
/** What should the form a user sees and configures look like? */
|
|
1197
1200
|
inputFields?: $InputFields;
|
|
1198
1201
|
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
const { simpleTruncate } = require('../tools/data');
|
|
5
|
-
|
|
6
|
-
const isSearch = require('./is-search');
|
|
7
|
-
|
|
8
|
-
/*
|
|
9
|
-
Searches should always return an array of objects.
|
|
10
|
-
*/
|
|
11
|
-
const searchIsArray = {
|
|
12
|
-
name: 'triggerIsArray',
|
|
13
|
-
shouldRun: isSearch,
|
|
14
|
-
run: (method, results) => {
|
|
15
|
-
if (!_.isArray(results)) {
|
|
16
|
-
const repr = simpleTruncate(JSON.stringify(results), 50);
|
|
17
|
-
return [`Results must be an array, got: ${typeof results}, (${repr})`];
|
|
18
|
-
}
|
|
19
|
-
return [];
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
module.exports = searchIsArray;
|