@api3/commons 0.1.0 → 0.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.
Files changed (48) hide show
  1. package/README.md +14 -5
  2. package/dist/eslint/jest.d.ts +1 -0
  3. package/dist/eslint/jest.js +1 -0
  4. package/dist/eslint/jest.js.map +1 -1
  5. package/dist/eslint/react.d.ts +0 -1
  6. package/dist/eslint/react.js +0 -1
  7. package/dist/eslint/react.js.map +1 -1
  8. package/dist/eslint/universal.d.ts +1 -5
  9. package/dist/eslint/universal.js +2 -19
  10. package/dist/eslint/universal.js.map +1 -1
  11. package/dist/processing/index.d.ts +4 -0
  12. package/dist/processing/index.d.ts.map +1 -0
  13. package/dist/processing/index.js +20 -0
  14. package/dist/processing/index.js.map +1 -0
  15. package/dist/processing/processing.d.ts +39 -0
  16. package/dist/processing/processing.d.ts.map +1 -0
  17. package/dist/processing/processing.js +122 -0
  18. package/dist/processing/processing.js.map +1 -0
  19. package/dist/processing/schema.d.ts +4 -0
  20. package/dist/processing/schema.d.ts.map +1 -0
  21. package/dist/processing/schema.js +6 -0
  22. package/dist/processing/schema.js.map +1 -0
  23. package/dist/processing/unsafe-evaluate.d.ts +50 -0
  24. package/dist/processing/unsafe-evaluate.d.ts.map +1 -0
  25. package/dist/processing/unsafe-evaluate.js +178 -0
  26. package/dist/processing/unsafe-evaluate.js.map +1 -0
  27. package/dist/processing/vm-timers.d.ts +21 -0
  28. package/dist/processing/vm-timers.d.ts.map +1 -0
  29. package/dist/processing/vm-timers.js +54 -0
  30. package/dist/processing/vm-timers.js.map +1 -0
  31. package/package.json +6 -4
  32. package/src/eslint/README.md +0 -5
  33. package/src/eslint/jest.js +1 -0
  34. package/src/eslint/react.js +0 -1
  35. package/src/eslint/universal.js +2 -20
  36. package/src/processing/README.md +49 -0
  37. package/src/processing/index.ts +3 -0
  38. package/src/processing/processing.test.ts +272 -0
  39. package/src/processing/processing.ts +160 -0
  40. package/src/processing/schema.ts +5 -0
  41. package/src/processing/unsafe-evaluate.test.ts +103 -0
  42. package/src/processing/unsafe-evaluate.ts +178 -0
  43. package/src/processing/vm-timers.ts +58 -0
  44. package/dist/index.d.ts +0 -1
  45. package/dist/index.d.ts.map +0 -1
  46. package/dist/index.js +0 -4
  47. package/dist/index.js.map +0 -1
  48. package/src/index.ts +0 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unsafe-evaluate.js","sourceRoot":"","sources":["../../src/processing/unsafe-evaluate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ /// <reference types="node" />
5
+ /// <reference types="node" />
6
+ /**
7
+ * Timers (setTimeout, setInterval) do not work in Node.js vm, see: https://github.com/nodejs/help/issues/1875
8
+ *
9
+ * The API is wrapped in a "create" function so that every processing snippet keeps track of its timers and properly
10
+ * cleans them up after use.
11
+ */
12
+ export declare const createTimers: () => {
13
+ customSetTimeout: (fn: () => void, ms: number) => void;
14
+ customClearTimeout: (id: NodeJS.Timeout) => void;
15
+ clearAllTimeouts: () => void;
16
+ customSetInterval: (fn: () => void, ms: number) => void;
17
+ customClearInterval: (id: NodeJS.Timeout) => void;
18
+ clearAllIntervals: () => void;
19
+ clearAll: () => void;
20
+ };
21
+ //# sourceMappingURL=vm-timers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vm-timers.d.ts","sourceRoot":"","sources":["../../src/processing/vm-timers.ts"],"names":[],"mappings":";;;;;AAAA;;;;;GAKG;AACH,eAAO,MAAM,YAAY;2BAGO,MAAM,IAAI,MAAM,MAAM;6BAIpB,OAAO,OAAO;;4BAcf,MAAM,IAAI,MAAM,MAAM;8BAIpB,OAAO,OAAO;;;CA0BhD,CAAC"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTimers = void 0;
4
+ /**
5
+ * Timers (setTimeout, setInterval) do not work in Node.js vm, see: https://github.com/nodejs/help/issues/1875
6
+ *
7
+ * The API is wrapped in a "create" function so that every processing snippet keeps track of its timers and properly
8
+ * cleans them up after use.
9
+ */
10
+ const createTimers = () => {
11
+ let timeouts = [];
12
+ const customSetTimeout = (fn, ms) => {
13
+ timeouts.push(setTimeout(fn, ms));
14
+ };
15
+ const customClearTimeout = (id) => {
16
+ timeouts = timeouts.filter((timeoutId) => timeoutId !== id);
17
+ clearTimeout(id);
18
+ };
19
+ const clearAllTimeouts = () => {
20
+ for (const element of timeouts) {
21
+ clearTimeout(element);
22
+ }
23
+ timeouts = [];
24
+ };
25
+ let intervals = [];
26
+ const customSetInterval = (fn, ms) => {
27
+ intervals.push(setInterval(fn, ms));
28
+ };
29
+ const customClearInterval = (id) => {
30
+ intervals = intervals.filter((intervalId) => intervalId !== id);
31
+ clearInterval(id);
32
+ };
33
+ const clearAllIntervals = () => {
34
+ for (const element of intervals) {
35
+ clearInterval(element);
36
+ }
37
+ intervals = [];
38
+ };
39
+ const clearAll = () => {
40
+ clearAllTimeouts();
41
+ clearAllIntervals();
42
+ };
43
+ return {
44
+ customSetTimeout,
45
+ customClearTimeout,
46
+ clearAllTimeouts,
47
+ customSetInterval,
48
+ customClearInterval,
49
+ clearAllIntervals,
50
+ clearAll,
51
+ };
52
+ };
53
+ exports.createTimers = createTimers;
54
+ //# sourceMappingURL=vm-timers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vm-timers.js","sourceRoot":"","sources":["../../src/processing/vm-timers.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACI,MAAM,YAAY,GAAG,GAAG,EAAE;IAC/B,IAAI,QAAQ,GAAqB,EAAE,CAAC;IAEpC,MAAM,gBAAgB,GAAG,CAAC,EAAc,EAAE,EAAU,EAAE,EAAE;QACtD,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC;IAEF,MAAM,kBAAkB,GAAG,CAAC,EAAkB,EAAE,EAAE;QAChD,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;QAC5D,YAAY,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;YAC9B,YAAY,CAAC,OAAO,CAAC,CAAC;SACvB;QACD,QAAQ,GAAG,EAAE,CAAC;IAChB,CAAC,CAAC;IAEF,IAAI,SAAS,GAAqB,EAAE,CAAC;IAErC,MAAM,iBAAiB,GAAG,CAAC,EAAc,EAAE,EAAU,EAAE,EAAE;QACvD,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,MAAM,mBAAmB,GAAG,CAAC,EAAkB,EAAE,EAAE;QACjD,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC;QAChE,aAAa,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC7B,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE;YAC/B,aAAa,CAAC,OAAO,CAAC,CAAC;SACxB;QACD,SAAS,GAAG,EAAE,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,gBAAgB,EAAE,CAAC;QACnB,iBAAiB,EAAE,CAAC;IACtB,CAAC,CAAC;IAEF,OAAO;QACL,gBAAgB;QAChB,kBAAkB;QAClB,gBAAgB;QAChB,iBAAiB;QACjB,mBAAmB;QACnB,iBAAiB;QACjB,QAAQ;KACT,CAAC;AACJ,CAAC,CAAC;AAnDW,QAAA,YAAY,gBAmDvB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@api3/commons",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "keywords": [],
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -12,10 +12,13 @@
12
12
  "src"
13
13
  ],
14
14
  "exports": {
15
+ "./eslint": "./dist/eslint/index.js",
15
16
  "./logger": "./dist/logger/index.js",
16
- "./eslint": "./dist/logger/index.js"
17
+ "./processing": "./dist/processing/index.js"
17
18
  },
18
19
  "dependencies": {
20
+ "@api3/ois": "^2.2.1",
21
+ "@api3/promise-utils": "^0.4.0",
19
22
  "@typescript-eslint/eslint-plugin": "^6.2.1",
20
23
  "@typescript-eslint/parser": "^6.2.1",
21
24
  "eslint-config-next": "^13.1.6",
@@ -28,7 +31,6 @@
28
31
  "eslint-plugin-jest-formatting": "^3.1.0",
29
32
  "eslint-plugin-lodash": "^7.4.0",
30
33
  "eslint-plugin-no-only-tests": "^3.1.0",
31
- "eslint-plugin-prefer-arrow": "^1.2.3",
32
34
  "eslint-plugin-promise": "^6.1.1",
33
35
  "eslint-plugin-react": "^7.32.1",
34
36
  "eslint-plugin-react-hooks": "^4.6.0",
@@ -64,7 +66,7 @@
64
66
  "eslint:fix": "pnpm run eslint:check --fix",
65
67
  "prettier:check": "prettier --check \"./**/*.{js,ts,md,json}\"",
66
68
  "prettier:fix": "prettier --write \"./**/*.{js,ts,md,json}\"",
67
- "test": "jest --passWithNoTests",
69
+ "test": "jest",
68
70
  "tsc": "tsc --project ."
69
71
  }
70
72
  }
@@ -58,11 +58,6 @@ The configurations are a collection of various rulesets and the config is quite
58
58
  - Fix outdated stuff (avoid `!` ts operator when not necessary)
59
59
  - Avoid vulnerabilities and errors (Number.parseInt without radix)
60
60
 
61
- But some stylistical rules are too strict for certain projects, for example:
62
-
63
- - Enforce `camelCase` for variables and functions, but `kebab-case` for filenames.
64
- - Prefer arrow functions everywhere instead of regular `function` functions.
65
-
66
61
  Tip: Some rules do have fixer with multiple variants of the fixes. You need to use the IDE to prompt the fixes and
67
62
  choose the one you want.
68
63
 
@@ -29,6 +29,7 @@ module.exports = {
29
29
  allow: ['afterEach', 'afterAll'],
30
30
  },
31
31
  ],
32
+ 'prefer-lowercase-title': 'off', // Sometimes we want to start the test with a capital letter and some words are all uppercase (e.g. AWS).
32
33
  },
33
34
  },
34
35
  ],
@@ -42,7 +42,6 @@ module.exports = {
42
42
  'react/destructuring-assignment': ['error', 'always', { destructureInSignature: 'ignore' }],
43
43
  'react/forbid-component-props': ['error', { forbid: [] }],
44
44
  'react/forbid-dom-props': ['error', { forbid: [] }],
45
- 'react/function-component-definition': 'off', // Arrow functions are managed by other rules.
46
45
  'react/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never', propElementValues: 'always' }],
47
46
  'react/jsx-curly-newline': 'off', // Conflicts with prettier.
48
47
  'react/jsx-filename-extension': 'off', // We use .tsx extension.
@@ -20,16 +20,7 @@ module.exports = {
20
20
  'plugin:promise/recommended',
21
21
  'plugin:lodash/recommended',
22
22
  ],
23
- plugins: [
24
- '@typescript-eslint',
25
- 'deprecation',
26
- 'functional',
27
- 'prefer-arrow',
28
- 'unicorn',
29
- 'check-file',
30
- 'import',
31
- 'lodash',
32
- ],
23
+ plugins: ['@typescript-eslint', 'deprecation', 'functional', 'unicorn', 'check-file', 'import', 'lodash'],
33
24
  rules: {
34
25
  /* Rule definitions and overrides for standard ESLint rules */
35
26
  camelcase: 'error',
@@ -78,16 +69,6 @@ module.exports = {
78
69
  },
79
70
  ],
80
71
 
81
- /* Rules to setup enforcement of arrow functions over regular functions */
82
- 'prefer-arrow/prefer-arrow-functions': [
83
- 'error',
84
- {
85
- disallowPrototype: true,
86
- singleReturnOnly: false,
87
- classPropertiesAllowed: false,
88
- },
89
- ],
90
-
91
72
  /* Rules to enforce kebab-case folder structure */
92
73
  'check-file/folder-naming-convention': [
93
74
  'error',
@@ -110,6 +91,7 @@ module.exports = {
110
91
  'unicorn/no-array-reduce': 'off', // We are OK with using reduce occasionally, but I agree with the author that the code using reduce can easily get complex.
111
92
  'unicorn/no-nested-ternary': 'off', // This rule is smarter than the standard ESLint rule, but conflicts with prettier so it needs to be turned off. Nested ternaries are very unreadable so it's OK if all of them are flagged.
112
93
  'unicorn/no-null': 'off', // We use both null and undefined for representing three state objects. We could use a string union instead, but using combination of null and undefined is less verbose.
94
+ 'unicorn/no-object-as-default-parameter': 'off', // Too restrictive. TypeScript can ensure that the default value matches the type.
113
95
  'unicorn/no-useless-undefined': ['error', { checkArguments: false }], // We need to disable "checkArguments", because if a function expects a value of type "T | undefined" the undefined value needs to be passed explicitly.
114
96
  'unicorn/prefer-module': 'off', // We use CJS for configuration files and tests. There is no rush to migrate to ESM and the configuration files are probably not yet ready for ESM yet.
115
97
  'unicorn/prevent-abbreviations': 'off', // This rule reports many false positives and leads to more verbose code.
@@ -0,0 +1,49 @@
1
+ # Processing
2
+
3
+ > Implementation of [OIS processing](https://docs.api3.org/reference/ois/latest/processing.html).
4
+
5
+ The pre/post processing is only supported for Node.js environments and uses internal Node.js modules.
6
+
7
+ ## Getting started
8
+
9
+ 1. Install `zod` which is a peer dependency of this module. Zod is used for validating the logger configuration.
10
+
11
+ ## Documentation
12
+
13
+ The processing module exports two main functions:
14
+
15
+ <!-- NOTE: These are copied over from "processing.d.ts" from "dist" file. -->
16
+
17
+ ```ts
18
+ /**
19
+ * Pre-processes API call parameters based on the provided endpoint's processing specifications.
20
+ *
21
+ * @param endpoint The endpoint containing processing specifications.
22
+ * @param apiCallParameters The parameters to be pre-processed.
23
+ * @param processingOptions Options to control the async processing behavior like retries and timeouts.
24
+ *
25
+ * @returns A promise that resolves to the pre-processed parameters.
26
+ */
27
+ export declare const preProcessApiCallParameters: (
28
+ endpoint: Endpoint,
29
+ apiCallParameters: ApiCallParameters,
30
+ processingOptions?: GoAsyncOptions
31
+ ) => Promise<ApiCallParameters>;
32
+
33
+ /**
34
+ * Post-processes the API call response based on the provided endpoint's processing specifications.
35
+ *
36
+ * @param apiCallResponse The raw response obtained from the API call.
37
+ * @param endpoint The endpoint containing processing specifications.
38
+ * @param apiCallParameters The parameters used in the API call.
39
+ * @param processingOptions Options to control the async processing behavior like retries and timeouts.
40
+ *
41
+ * @returns A promise that resolves to the post-processed API call response.
42
+ */
43
+ export declare const postProcessApiCallResponse: (
44
+ apiCallResponse: unknown,
45
+ endpoint: Endpoint,
46
+ apiCallParameters: ApiCallParameters,
47
+ processingOptions?: GoAsyncOptions
48
+ ) => Promise<unknown>;
49
+ ```
@@ -0,0 +1,3 @@
1
+ export * from './processing';
2
+ export * from './schema';
3
+ export * from './unsafe-evaluate';
@@ -0,0 +1,272 @@
1
+ /* eslint-disable jest/prefer-strict-equal */ // Because the errors are thrown from the "vm" module (different context), they are not strictly equal.
2
+ import { createEndpoint } from '../../test/fixtures';
3
+
4
+ import {
5
+ addReservedParameters,
6
+ postProcessApiCallResponse,
7
+ preProcessApiCallParameters,
8
+ removeReservedParameters,
9
+ } from './processing';
10
+
11
+ describe(preProcessApiCallParameters.name, () => {
12
+ it('valid processing code', async () => {
13
+ const endpoint = createEndpoint({
14
+ preProcessingSpecifications: [
15
+ {
16
+ environment: 'Node',
17
+ value: 'const output = {...input, from: "ETH"};',
18
+ timeoutMs: 5000,
19
+ },
20
+ {
21
+ environment: 'Node',
22
+ value: 'const output = {...input, newProp: "airnode"};',
23
+ timeoutMs: 5000,
24
+ },
25
+ ],
26
+ });
27
+ const parameters = { _type: 'int256', _path: 'price' };
28
+
29
+ const result = await preProcessApiCallParameters(endpoint, parameters);
30
+
31
+ expect(result).toEqual({
32
+ _path: 'price',
33
+ _type: 'int256',
34
+ from: 'ETH',
35
+ newProp: 'airnode',
36
+ });
37
+ });
38
+
39
+ it('invalid processing code', async () => {
40
+ const endpoint = createEndpoint({
41
+ preProcessingSpecifications: [
42
+ {
43
+ environment: 'Node',
44
+ value: 'something invalid; const output = {...input, from: `ETH`};',
45
+ timeoutMs: 5000,
46
+ },
47
+ {
48
+ environment: 'Node',
49
+ value: 'const output = {...input, newProp: "airnode"};',
50
+ timeoutMs: 5000,
51
+ },
52
+ ],
53
+ });
54
+ const parameters = { _type: 'int256', _path: 'price', from: 'TBD' };
55
+
56
+ const throwingFunc = async () => preProcessApiCallParameters(endpoint, parameters);
57
+
58
+ await expect(throwingFunc).rejects.toEqual(new Error('SyntaxError: Unexpected identifier'));
59
+ });
60
+
61
+ it('demonstrates access to endpointParameters, but reserved parameters are inaccessible', async () => {
62
+ const parameters = { _type: 'int256', _path: 'price', to: 'USD' };
63
+ const endpoint = createEndpoint({
64
+ preProcessingSpecifications: [
65
+ {
66
+ environment: 'Node',
67
+ // pretend the user is trying to 1) override _path and 2) set a new parameter based on
68
+ // the presence of the reserved parameter _type (which is inaccessible)
69
+ value:
70
+ 'const output = {...input, from: "ETH", _path: "price.newpath", myVal: input._type ? "123" : "456", newTo: endpointParameters.to };',
71
+ timeoutMs: 5000,
72
+ },
73
+ ],
74
+ });
75
+
76
+ const result = await preProcessApiCallParameters(endpoint, parameters);
77
+
78
+ expect(result).toEqual({
79
+ _path: 'price', // is not overridden
80
+ _type: 'int256',
81
+ from: 'ETH', // originates from the processing code
82
+ to: 'USD', // should be unchanged from the original parameters
83
+ myVal: '456', // is set to "456" because _type is not present in the environment
84
+ newTo: 'USD', // demonstrates access to endpointParameters
85
+ });
86
+ });
87
+
88
+ it('uses native modules for processing', async () => {
89
+ const endpoint = createEndpoint({
90
+ preProcessingSpecifications: [
91
+ {
92
+ environment: 'Node',
93
+ value: `
94
+ const randomValue = crypto.randomBytes(4).toString('hex');
95
+ const output = {...input, randomValue};
96
+ `,
97
+ timeoutMs: 5000,
98
+ },
99
+ ],
100
+ });
101
+ const parameters = { _type: 'int256', _path: 'price' };
102
+
103
+ const result = await preProcessApiCallParameters(endpoint, parameters);
104
+
105
+ // Check that the result contains the original parameters and a valid 8-character hex random value.
106
+ expect(result).toMatchObject({
107
+ _path: 'price',
108
+ _type: 'int256',
109
+ });
110
+ expect(result.randomValue).toHaveLength(8);
111
+ expect(/^[\da-f]{8}$/i.test(result.randomValue)).toBe(true);
112
+ });
113
+
114
+ it('throws error due to processing timeout', async () => {
115
+ const endpoint = createEndpoint({
116
+ preProcessingSpecifications: [
117
+ {
118
+ environment: 'Node async',
119
+ value: `
120
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
121
+ delay(5000);
122
+ const output = {...input, from: 'ETH'};
123
+ `,
124
+ timeoutMs: 100, // This timeout is shorter than the delay in the processing code.
125
+ },
126
+ ],
127
+ });
128
+ const parameters = { _type: 'int256', _path: 'price' };
129
+
130
+ const throwingFunc = async () => preProcessApiCallParameters(endpoint, parameters);
131
+
132
+ await expect(throwingFunc).rejects.toThrow('Timeout exceeded');
133
+ });
134
+ });
135
+
136
+ describe(postProcessApiCallResponse.name, () => {
137
+ it('processes valid code', async () => {
138
+ const parameters = { _type: 'int256', _path: 'price' };
139
+ const endpoint = createEndpoint({
140
+ postProcessingSpecifications: [
141
+ {
142
+ environment: 'Node',
143
+ value: 'const output = parseInt(input.price)*2;',
144
+ timeoutMs: 5000,
145
+ },
146
+ {
147
+ environment: 'Node',
148
+ value: 'const output = parseInt(input)*2;',
149
+ timeoutMs: 5000,
150
+ },
151
+ ],
152
+ });
153
+
154
+ const result = await postProcessApiCallResponse({ price: 1000 }, endpoint, parameters);
155
+
156
+ expect(result).toBe(4000);
157
+ });
158
+
159
+ it('demonstrates access to endpointParameters, but reserved parameters are inaccessible', async () => {
160
+ const myMultiplier = 10;
161
+ const parameters = { _type: 'int256', _path: 'price', myMultiplier };
162
+ const endpoint = createEndpoint({
163
+ postProcessingSpecifications: [
164
+ {
165
+ environment: 'Node',
166
+ value: `
167
+ const reservedMultiplier = endpointParameters._times ? 1 : 2;
168
+ const output = parseInt(input.price) * endpointParameters.myMultiplier * reservedMultiplier
169
+ `,
170
+ timeoutMs: 5000,
171
+ },
172
+ ],
173
+ });
174
+
175
+ const price = 1000;
176
+ const result = await postProcessApiCallResponse({ price }, endpoint, parameters);
177
+
178
+ // reserved parameters (_times) should be inaccessible to post-processing for the
179
+ // http-gateway, hence multiplication by 2 instead of 1
180
+ expect(result).toEqual(price * myMultiplier * 2);
181
+ });
182
+
183
+ it('throws on invalid code', async () => {
184
+ const parameters = { _type: 'int256', _path: 'price' };
185
+ const endpoint = createEndpoint({
186
+ postProcessingSpecifications: [
187
+ {
188
+ environment: 'Node',
189
+ value: 'const output = parseInt(input.price)*1000;',
190
+ timeoutMs: 5000,
191
+ },
192
+ {
193
+ environment: 'Node',
194
+ value: `
195
+ Something Unexpected;
196
+ const output = parseInt(input)*2;
197
+ `,
198
+ timeoutMs: 5000,
199
+ },
200
+ ],
201
+ });
202
+
203
+ const throwingFunc = async () => postProcessApiCallResponse({ price: 1000 }, endpoint, parameters);
204
+
205
+ await expect(throwingFunc).rejects.toEqual(new Error('SyntaxError: Unexpected identifier'));
206
+ });
207
+ });
208
+
209
+ describe(removeReservedParameters.name, () => {
210
+ it('removes all reserved parameters', () => {
211
+ const parameters = {
212
+ normalParam1: 'value1',
213
+ _type: 'int256',
214
+ _path: 'price',
215
+ normalParam2: 'value2',
216
+ };
217
+
218
+ const result = removeReservedParameters(parameters);
219
+
220
+ expect(result).toEqual({
221
+ normalParam1: 'value1',
222
+ normalParam2: 'value2',
223
+ });
224
+ });
225
+
226
+ it('returns same object if no reserved parameters found', () => {
227
+ const parameters = {
228
+ normalParam1: 'value1',
229
+ normalParam2: 'value2',
230
+ };
231
+
232
+ const result = removeReservedParameters(parameters);
233
+
234
+ expect(result).toEqual(parameters);
235
+ });
236
+ });
237
+
238
+ describe(addReservedParameters.name, () => {
239
+ it('adds reserved parameters from initial to modified parameters', () => {
240
+ const initialParameters = {
241
+ _type: 'int256',
242
+ _path: 'price',
243
+ };
244
+ const modifiedParameters = {
245
+ normalParam1: 'value1',
246
+ normalParam2: 'value2',
247
+ };
248
+
249
+ const result = addReservedParameters(initialParameters, modifiedParameters);
250
+
251
+ expect(result).toEqual({
252
+ normalParam1: 'value1',
253
+ normalParam2: 'value2',
254
+ _type: 'int256',
255
+ _path: 'price',
256
+ });
257
+ });
258
+
259
+ it('does not modify modifiedParameters if no reserved parameters in initialParameters', () => {
260
+ const initialParameters = {
261
+ normalParam3: 'value3',
262
+ };
263
+ const modifiedParameters = {
264
+ normalParam1: 'value1',
265
+ normalParam2: 'value2',
266
+ };
267
+
268
+ const result = addReservedParameters(initialParameters, modifiedParameters);
269
+
270
+ expect(result).toEqual(modifiedParameters);
271
+ });
272
+ });