@saasquatch/program-boilerplate 3.5.12-1 → 3.6.0-1
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.d.ts +10 -0
- package/dist/conversion.js +45 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/jsonata.d.ts +5 -1
- package/dist/jsonata.js +29 -12
- package/dist/utils.d.ts +4 -4
- package/dist/utils.js +4 -4
- package/package.json +1 -1
package/dist/conversion.d.ts
CHANGED
|
@@ -38,6 +38,16 @@ declare type UserQueryResult = {
|
|
|
38
38
|
* The value of a rule
|
|
39
39
|
*/
|
|
40
40
|
declare type RuleValue = string | boolean | number;
|
|
41
|
+
/**
|
|
42
|
+
* Checks whether any of the edge trigger conditions are met given
|
|
43
|
+
* a list of fields to check and the current context.
|
|
44
|
+
*
|
|
45
|
+
* @param {string[] | undefined} fields The list of edge trigger fields
|
|
46
|
+
* @param {any} activeTrigger The current program `activeTrigger`
|
|
47
|
+
*
|
|
48
|
+
* @return {boolean} Whether any of the edge fields have changed
|
|
49
|
+
*/
|
|
50
|
+
export declare function meetEdgeTriggerConditions(fields: string[] | undefined, activeTrigger: any): boolean;
|
|
41
51
|
/**
|
|
42
52
|
* @deprecated No longer in use, use JSONata expression and evaluation instead
|
|
43
53
|
* Checks if the customFields of the user meet every rule that defines customFields-based conversion
|
package/dist/conversion.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* @module conversion
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.meetEventTriggerRules = exports.meetCustomFieldRules = void 0;
|
|
6
|
+
exports.meetEventTriggerRules = exports.meetCustomFieldRules = exports.meetEdgeTriggerConditions = void 0;
|
|
7
|
+
const assert = require("assert");
|
|
8
|
+
const jsonata_1 = require("./jsonata");
|
|
7
9
|
//functions
|
|
8
10
|
/**
|
|
9
11
|
* Turns a string scalar into a Number, Boolean or String
|
|
@@ -23,6 +25,48 @@ function parseValue(value) {
|
|
|
23
25
|
}
|
|
24
26
|
return value;
|
|
25
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Checks whether any of the edge trigger conditions are met given
|
|
30
|
+
* a list of fields to check and the current context.
|
|
31
|
+
*
|
|
32
|
+
* @param {string[] | undefined} fields The list of edge trigger fields
|
|
33
|
+
* @param {any} activeTrigger The current program `activeTrigger`
|
|
34
|
+
*
|
|
35
|
+
* @return {boolean} Whether any of the edge fields have changed
|
|
36
|
+
*/
|
|
37
|
+
function meetEdgeTriggerConditions(fields, activeTrigger) {
|
|
38
|
+
if (fields === undefined || fields.length === 0) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
for (const field of fields) {
|
|
42
|
+
if (!field.startsWith("user.")) {
|
|
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.safeJsonata2(field.replace("user.", "previous."), activeTrigger, jsonataTimeoutMs);
|
|
51
|
+
const { success: currentSuccess, result: currentValue } = jsonata_1.safeJsonata2(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;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
assert.deepStrictEqual(currentValue, previousValue);
|
|
59
|
+
// assertion passed -- field did not change
|
|
60
|
+
// continue on to other fields and see if any changed
|
|
61
|
+
}
|
|
62
|
+
catch (_e) {
|
|
63
|
+
// assertion failed -- field must have changed
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
exports.meetEdgeTriggerConditions = meetEdgeTriggerConditions;
|
|
26
70
|
/**
|
|
27
71
|
* Checks if the customFields of a user meet a certain customField-based conversion rule.
|
|
28
72
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as express from "express";
|
|
2
|
-
import { meetCustomFieldRules, meetEventTriggerRules } from "./conversion";
|
|
2
|
+
import { meetCustomFieldRules, meetEventTriggerRules, meetEdgeTriggerConditions } from "./conversion";
|
|
3
3
|
import { rewardEmailQuery } from "./queries";
|
|
4
4
|
import Transaction from "./transaction";
|
|
5
5
|
import { triggerProgram } from "./trigger";
|
|
@@ -10,7 +10,7 @@ import { timeboxExpression, 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, 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, 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,10 +1,11 @@
|
|
|
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.meetCustomFieldRules = exports.meetEventTriggerRules = exports.Transaction = exports.types = void 0;
|
|
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;
|
|
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; } });
|
|
7
7
|
Object.defineProperty(exports, "meetEventTriggerRules", { enumerable: true, get: function () { return conversion_1.meetEventTriggerRules; } });
|
|
8
|
+
Object.defineProperty(exports, "meetEdgeTriggerConditions", { enumerable: true, get: function () { return conversion_1.meetEdgeTriggerConditions; } });
|
|
8
9
|
const queries_1 = require("./queries");
|
|
9
10
|
Object.defineProperty(exports, "rewardEmailQuery", { enumerable: true, get: function () { return queries_1.rewardEmailQuery; } });
|
|
10
11
|
const transaction_1 = require("./transaction");
|
package/dist/jsonata.d.ts
CHANGED
|
@@ -7,5 +7,9 @@ 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
11
|
export declare function safeJsonata(expression: string, inputData: any): any;
|
|
12
|
+
export declare function safeJsonata2(expression: string, inputData: any, timeout?: number, maxDepth?: number): {
|
|
13
|
+
success: boolean;
|
|
14
|
+
result: any;
|
|
15
|
+
};
|
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.safeJsonata2 = 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,12 +38,12 @@ 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
|
}
|
|
@@ -57,3 +59,18 @@ function safeJsonata(expression, inputData) {
|
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
exports.safeJsonata = safeJsonata;
|
|
62
|
+
function safeJsonata2(expression, inputData, timeout, maxDepth) {
|
|
63
|
+
try {
|
|
64
|
+
const jsonataQuery = jsonata(expression);
|
|
65
|
+
timeboxExpression(jsonataQuery, timeout, maxDepth);
|
|
66
|
+
const result = jsonataQuery.evaluate(inputData);
|
|
67
|
+
return { success: true, result };
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
if (e instanceof Error) {
|
|
71
|
+
logger.warn(`Failed to evaluate JSONata expression: ${e.message}`);
|
|
72
|
+
}
|
|
73
|
+
return { success: false, result: undefined };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.safeJsonata2 = safeJsonata2;
|
package/dist/utils.d.ts
CHANGED
|
@@ -56,15 +56,15 @@ export declare function getGoalAnalyticTimestamp(trigger: any): number;
|
|
|
56
56
|
export declare function inferType(val: string): any;
|
|
57
57
|
/**
|
|
58
58
|
* Converts a number representation of a conversion operator set in program
|
|
59
|
-
* rules to a string that can be user in a
|
|
60
|
-
* @param num
|
|
59
|
+
* rules to a string that can be user in a GraphQL query
|
|
60
|
+
* @param {number} num conversion criteria set in a program
|
|
61
61
|
* @return {string} the string representation of the conversion operator
|
|
62
62
|
*/
|
|
63
63
|
export declare function numToEquality(num: number): string;
|
|
64
64
|
/**
|
|
65
|
-
* Converts a trigger context into the
|
|
65
|
+
* Converts a trigger context into the relevant information for the specified trigger type.
|
|
66
66
|
* @param body the body of the trigger
|
|
67
|
-
* @return object[] The
|
|
67
|
+
* @return object[] The transformed data that is relevant for the trigger type
|
|
68
68
|
*/
|
|
69
69
|
export declare function getTriggerSchema(body: ProgramTriggerBody): object[];
|
|
70
70
|
/**
|
package/dist/utils.js
CHANGED
|
@@ -120,8 +120,8 @@ function inferType(val) {
|
|
|
120
120
|
exports.inferType = inferType;
|
|
121
121
|
/**
|
|
122
122
|
* Converts a number representation of a conversion operator set in program
|
|
123
|
-
* rules to a string that can be user in a
|
|
124
|
-
* @param num
|
|
123
|
+
* rules to a string that can be user in a GraphQL query
|
|
124
|
+
* @param {number} num conversion criteria set in a program
|
|
125
125
|
* @return {string} the string representation of the conversion operator
|
|
126
126
|
*/
|
|
127
127
|
function numToEquality(num) {
|
|
@@ -138,9 +138,9 @@ function numToEquality(num) {
|
|
|
138
138
|
}
|
|
139
139
|
exports.numToEquality = numToEquality;
|
|
140
140
|
/**
|
|
141
|
-
* Converts a trigger context into the
|
|
141
|
+
* Converts a trigger context into the relevant information for the specified trigger type.
|
|
142
142
|
* @param body the body of the trigger
|
|
143
|
-
* @return object[] The
|
|
143
|
+
* @return object[] The transformed data that is relevant for the trigger type
|
|
144
144
|
*/
|
|
145
145
|
function getTriggerSchema(body) {
|
|
146
146
|
const activeTrigger = body.activeTrigger;
|