@saasquatch/program-boilerplate 3.6.0-0 → 3.6.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/dist/conversion.js +14 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/jsonata.d.ts +8 -1
- package/dist/jsonata.js +32 -12
- package/package.json +2 -2
package/dist/conversion.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.meetEventTriggerRules = exports.meetCustomFieldRules = exports.meetEdgeTriggerConditions = void 0;
|
|
7
7
|
const assert = require("assert");
|
|
8
|
-
const
|
|
8
|
+
const jsonata_1 = require("./jsonata");
|
|
9
9
|
//functions
|
|
10
10
|
/**
|
|
11
11
|
* Turns a string scalar into a Number, Boolean or String
|
|
@@ -40,11 +40,20 @@ function meetEdgeTriggerConditions(fields, activeTrigger) {
|
|
|
40
40
|
}
|
|
41
41
|
for (const field of fields) {
|
|
42
42
|
if (!field.startsWith("user.")) {
|
|
43
|
-
//
|
|
44
|
-
|
|
43
|
+
// we consider a malformed edge field to be "not passing"
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
// a simple query to retrieve the value of a field from the user should
|
|
47
|
+
// not take more than a few milliseconds. if it takes longer than 500ms
|
|
48
|
+
// something is definitely wrong with the query
|
|
49
|
+
const jsonataTimeoutMs = 500;
|
|
50
|
+
const { success: prevSuccess, result: previousValue } = jsonata_1.timeboxedJsonata(field.replace("user.", "previous."), activeTrigger, jsonataTimeoutMs);
|
|
51
|
+
const { success: currentSuccess, result: currentValue } = jsonata_1.timeboxedJsonata(field, activeTrigger, jsonataTimeoutMs);
|
|
52
|
+
// one of the JSONata expressions failed to evaluate -- edge field is considered
|
|
53
|
+
// "not passing"
|
|
54
|
+
if (!prevSuccess || !currentSuccess) {
|
|
55
|
+
return false;
|
|
45
56
|
}
|
|
46
|
-
const previousValue = jsonata(field.replace("user.", "previous.")).evaluate(activeTrigger);
|
|
47
|
-
const currentValue = jsonata(field).evaluate(activeTrigger);
|
|
48
57
|
try {
|
|
49
58
|
assert.deepStrictEqual(currentValue, previousValue);
|
|
50
59
|
// assertion passed -- field did not change
|
package/dist/index.d.ts
CHANGED
|
@@ -6,11 +6,11 @@ import { triggerProgram } from "./trigger";
|
|
|
6
6
|
import { getLogger, setLogLevel } from "./logger";
|
|
7
7
|
import * as types from "./types";
|
|
8
8
|
import { Program, ProgramRequirement, RequirementValidationResult, ValidationProgramField, ProgramTriggerBody } from "./types/rpc";
|
|
9
|
-
import { timeboxExpression, safeJsonata } from "./jsonata";
|
|
9
|
+
import { timeboxExpression, timeboxedJsonata, safeJsonata } from "./jsonata";
|
|
10
10
|
import { ProgramType } from "./types/saasquatch";
|
|
11
11
|
import { inferType, getGoalAnalyticTimestamp, setRewardSchedule, numToEquality, getTriggerSchema, getUserCustomFieldsFromJsonata } from "./utils";
|
|
12
12
|
export { types };
|
|
13
|
-
export { Transaction, ProgramTriggerBody, Program, ProgramType, RequirementValidationResult, ProgramRequirement, ValidationProgramField, meetEventTriggerRules, meetCustomFieldRules, meetEdgeTriggerConditions, rewardEmailQuery, setRewardSchedule, getGoalAnalyticTimestamp, triggerProgram, inferType, numToEquality, getTriggerSchema, getUserCustomFieldsFromJsonata, timeboxExpression, safeJsonata, getLogger, setLogLevel, };
|
|
13
|
+
export { Transaction, ProgramTriggerBody, Program, ProgramType, RequirementValidationResult, ProgramRequirement, ValidationProgramField, meetEventTriggerRules, meetCustomFieldRules, meetEdgeTriggerConditions, rewardEmailQuery, setRewardSchedule, getGoalAnalyticTimestamp, triggerProgram, inferType, numToEquality, getTriggerSchema, getUserCustomFieldsFromJsonata, timeboxExpression, timeboxedJsonata, safeJsonata, getLogger, setLogLevel, };
|
|
14
14
|
/**
|
|
15
15
|
* Returns an express server that serves the provided handlers
|
|
16
16
|
* as a program
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.webtask = exports.setLogLevel = exports.getLogger = exports.safeJsonata = exports.timeboxExpression = exports.getUserCustomFieldsFromJsonata = exports.getTriggerSchema = exports.numToEquality = exports.inferType = exports.triggerProgram = exports.getGoalAnalyticTimestamp = exports.setRewardSchedule = exports.rewardEmailQuery = exports.meetEdgeTriggerConditions = exports.meetCustomFieldRules = exports.meetEventTriggerRules = exports.Transaction = exports.types = void 0;
|
|
3
|
+
exports.webtask = exports.setLogLevel = exports.getLogger = exports.safeJsonata = exports.timeboxedJsonata = exports.timeboxExpression = exports.getUserCustomFieldsFromJsonata = exports.getTriggerSchema = exports.numToEquality = exports.inferType = exports.triggerProgram = exports.getGoalAnalyticTimestamp = exports.setRewardSchedule = exports.rewardEmailQuery = exports.meetEdgeTriggerConditions = exports.meetCustomFieldRules = exports.meetEventTriggerRules = exports.Transaction = exports.types = void 0;
|
|
4
4
|
const express = require("express");
|
|
5
5
|
const conversion_1 = require("./conversion");
|
|
6
6
|
Object.defineProperty(exports, "meetCustomFieldRules", { enumerable: true, get: function () { return conversion_1.meetCustomFieldRules; } });
|
|
@@ -19,6 +19,7 @@ const types = require("./types");
|
|
|
19
19
|
exports.types = types;
|
|
20
20
|
const jsonata_1 = require("./jsonata");
|
|
21
21
|
Object.defineProperty(exports, "timeboxExpression", { enumerable: true, get: function () { return jsonata_1.timeboxExpression; } });
|
|
22
|
+
Object.defineProperty(exports, "timeboxedJsonata", { enumerable: true, get: function () { return jsonata_1.timeboxedJsonata; } });
|
|
22
23
|
Object.defineProperty(exports, "safeJsonata", { enumerable: true, get: function () { return jsonata_1.safeJsonata; } });
|
|
23
24
|
const utils_1 = require("./utils");
|
|
24
25
|
Object.defineProperty(exports, "inferType", { enumerable: true, get: function () { return utils_1.inferType; } });
|
package/dist/jsonata.d.ts
CHANGED
|
@@ -7,5 +7,12 @@ import * as jsonata from "jsonata";
|
|
|
7
7
|
* @param {Number} timeout - max time in ms
|
|
8
8
|
* @param {Number} maxDepth - max stack depth
|
|
9
9
|
*/
|
|
10
|
-
export declare function timeboxExpression(expr: jsonata.Expression): void;
|
|
10
|
+
export declare function timeboxExpression(expr: jsonata.Expression, timeout?: number, maxDepth?: number): void;
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Use timeboxedJsonata instead
|
|
13
|
+
*/
|
|
11
14
|
export declare function safeJsonata(expression: string, inputData: any): any;
|
|
15
|
+
export declare function timeboxedJsonata(expression: string, inputData: any, timeout?: number, maxDepth?: number): {
|
|
16
|
+
success: boolean;
|
|
17
|
+
result: any;
|
|
18
|
+
};
|
package/dist/jsonata.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.safeJsonata = exports.timeboxExpression = void 0;
|
|
3
|
+
exports.timeboxedJsonata = exports.safeJsonata = exports.timeboxExpression = void 0;
|
|
4
4
|
const jsonata = require("jsonata");
|
|
5
5
|
const logger_1 = require("./logger");
|
|
6
6
|
const TIMEOUT = 5000;
|
|
@@ -14,19 +14,21 @@ const logger = logger_1.getLogger(process.env.PROGRAM_LOG_LEVEL || "debug");
|
|
|
14
14
|
* @param {Number} timeout - max time in ms
|
|
15
15
|
* @param {Number} maxDepth - max stack depth
|
|
16
16
|
*/
|
|
17
|
-
function timeboxExpression(expr) {
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
function timeboxExpression(expr, timeout, maxDepth) {
|
|
18
|
+
const startTime = Date.now();
|
|
19
|
+
const actualTimeout = timeout !== null && timeout !== void 0 ? timeout : TIMEOUT;
|
|
20
|
+
const actualMaxDepth = maxDepth !== null && maxDepth !== void 0 ? maxDepth : MAXDEPTH;
|
|
21
|
+
let currentDepth = 0;
|
|
22
|
+
const checkRunnaway = function () {
|
|
23
|
+
if (currentDepth > actualMaxDepth) {
|
|
22
24
|
// stack too deep
|
|
23
25
|
throw {
|
|
24
26
|
code: "U1001",
|
|
25
|
-
message: "Stack overflow error: Check for non-terminating recursive function.
|
|
27
|
+
message: "Stack overflow error: Check for non-terminating recursive function. Consider rewriting as tail-recursive.",
|
|
26
28
|
stack: new Error().stack,
|
|
27
29
|
};
|
|
28
30
|
}
|
|
29
|
-
if (Date.now() -
|
|
31
|
+
if (Date.now() - startTime > actualTimeout) {
|
|
30
32
|
// expression has run for too long
|
|
31
33
|
throw {
|
|
32
34
|
code: "U1002",
|
|
@@ -36,16 +38,19 @@ function timeboxExpression(expr) {
|
|
|
36
38
|
}
|
|
37
39
|
};
|
|
38
40
|
// register callbacks
|
|
39
|
-
expr.assign("__evaluate_entry",
|
|
40
|
-
|
|
41
|
+
expr.assign("__evaluate_entry", () => {
|
|
42
|
+
currentDepth++;
|
|
41
43
|
checkRunnaway();
|
|
42
44
|
});
|
|
43
|
-
expr.assign("__evaluate_exit",
|
|
44
|
-
|
|
45
|
+
expr.assign("__evaluate_exit", () => {
|
|
46
|
+
currentDepth--;
|
|
45
47
|
checkRunnaway();
|
|
46
48
|
});
|
|
47
49
|
}
|
|
48
50
|
exports.timeboxExpression = timeboxExpression;
|
|
51
|
+
/**
|
|
52
|
+
* @deprecated Use timeboxedJsonata instead
|
|
53
|
+
*/
|
|
49
54
|
function safeJsonata(expression, inputData) {
|
|
50
55
|
try {
|
|
51
56
|
const jsonataQuery = jsonata(expression);
|
|
@@ -57,3 +62,18 @@ function safeJsonata(expression, inputData) {
|
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
64
|
exports.safeJsonata = safeJsonata;
|
|
65
|
+
function timeboxedJsonata(expression, inputData, timeout, maxDepth) {
|
|
66
|
+
try {
|
|
67
|
+
const jsonataQuery = jsonata(expression);
|
|
68
|
+
timeboxExpression(jsonataQuery, timeout, maxDepth);
|
|
69
|
+
const result = jsonataQuery.evaluate(inputData);
|
|
70
|
+
return { success: true, result };
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
if (e instanceof Error) {
|
|
74
|
+
logger.warn(`Failed to evaluate JSONata expression: ${e.message}`);
|
|
75
|
+
}
|
|
76
|
+
return { success: false, result: undefined };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.timeboxedJsonata = timeboxedJsonata;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saasquatch/program-boilerplate",
|
|
3
|
-
"version": "3.6.0
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Boilerplate for writing programs",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"typescript": "^3.9.9"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@saasquatch/jsonata-paths-extractor": "^1.0.
|
|
35
|
+
"@saasquatch/jsonata-paths-extractor": "^1.0.1",
|
|
36
36
|
"bson-objectid": "^1.3.1",
|
|
37
37
|
"compression": "^1.7.4",
|
|
38
38
|
"express": "^4.17.1",
|