@saasquatch/program-boilerplate 3.7.4 → 3.10.0-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/buh.d.ts +1 -0
- package/dist/buh.js +7 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +45 -6
- package/dist/trigger.js +1 -2
- package/dist/types/rpc.d.ts +20 -8
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +25 -1
- package/package.json +7 -3
package/dist/buh.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/buh.js
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -8,9 +8,9 @@ import * as types from "./types";
|
|
|
8
8
|
import { Program, ProgramRequirement, RequirementValidationResult, ValidationProgramField, ProgramTriggerBody } from "./types/rpc";
|
|
9
9
|
import { timeboxExpression, timeboxedJsonata, safeJsonata } from "./jsonata";
|
|
10
10
|
import { ProgramType } from "./types/saasquatch";
|
|
11
|
-
import { inferType, getGoalAnalyticTimestamp, setRewardSchedule, numToEquality, getTriggerSchema, getUserCustomFieldsFromJsonata, getRewardUnitsFromJsonata } from "./utils";
|
|
11
|
+
import { inferType, getGoalAnalyticTimestamp, setRewardSchedule, numToEquality, getTriggerSchema, getUserCustomFieldsFromJsonata, getRewardUnitsFromJsonata, loadStandardWebtaskConfig, WebtaskConfig } 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, getRewardUnitsFromJsonata, timeboxExpression, timeboxedJsonata, safeJsonata, getLogger, setLogLevel, };
|
|
13
|
+
export { Transaction, ProgramTriggerBody, Program, ProgramType, RequirementValidationResult, ProgramRequirement, ValidationProgramField, meetEventTriggerRules, meetCustomFieldRules, meetEdgeTriggerConditions, rewardEmailQuery, setRewardSchedule, getGoalAnalyticTimestamp, triggerProgram, inferType, numToEquality, getTriggerSchema, getUserCustomFieldsFromJsonata, getRewardUnitsFromJsonata, timeboxExpression, timeboxedJsonata, safeJsonata, getLogger, setLogLevel, loadStandardWebtaskConfig, };
|
|
14
14
|
/**
|
|
15
15
|
* Returns an express server that serves the provided handlers
|
|
16
16
|
* as a program
|
|
@@ -20,3 +20,4 @@ export { Transaction, ProgramTriggerBody, Program, ProgramType, RequirementValid
|
|
|
20
20
|
* @return {Object} The express server
|
|
21
21
|
*/
|
|
22
22
|
export declare function webtask(program?: Program): express.Application;
|
|
23
|
+
export declare function runWebtask(webtask: express.Application, config: WebtaskConfig): void;
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.webtask = exports.setLogLevel = exports.getLogger = exports.safeJsonata = exports.timeboxedJsonata = exports.timeboxExpression = exports.getRewardUnitsFromJsonata = 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;
|
|
25
|
+
exports.runWebtask = exports.webtask = exports.loadStandardWebtaskConfig = exports.setLogLevel = exports.getLogger = exports.safeJsonata = exports.timeboxedJsonata = exports.timeboxExpression = exports.getRewardUnitsFromJsonata = 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;
|
|
26
26
|
const express_1 = __importDefault(require("express"));
|
|
27
27
|
const conversion_1 = require("./conversion");
|
|
28
28
|
Object.defineProperty(exports, "meetCustomFieldRules", { enumerable: true, get: function () { return conversion_1.meetCustomFieldRules; } });
|
|
@@ -52,6 +52,7 @@ Object.defineProperty(exports, "numToEquality", { enumerable: true, get: functio
|
|
|
52
52
|
Object.defineProperty(exports, "getTriggerSchema", { enumerable: true, get: function () { return utils_1.getTriggerSchema; } });
|
|
53
53
|
Object.defineProperty(exports, "getUserCustomFieldsFromJsonata", { enumerable: true, get: function () { return utils_1.getUserCustomFieldsFromJsonata; } });
|
|
54
54
|
Object.defineProperty(exports, "getRewardUnitsFromJsonata", { enumerable: true, get: function () { return utils_1.getRewardUnitsFromJsonata; } });
|
|
55
|
+
Object.defineProperty(exports, "loadStandardWebtaskConfig", { enumerable: true, get: function () { return utils_1.loadStandardWebtaskConfig; } });
|
|
55
56
|
const logger_3 = require("@saasquatch/logger");
|
|
56
57
|
/**
|
|
57
58
|
* Returns an express server that serves the provided handlers
|
|
@@ -67,21 +68,59 @@ function webtask(program = {}) {
|
|
|
67
68
|
const logger = logger_2.getLogger("program-boilerplate");
|
|
68
69
|
app.use(express_1.default.json({ limit: process.env.MAX_PAYLOAD_SIZE || "1mb" }));
|
|
69
70
|
app.use(compression());
|
|
70
|
-
app.use(logger_3.httpLogMiddleware(logger));
|
|
71
|
+
app.use(logger_3.httpLogMiddleware(logger, { logNonErrorResponses: false }));
|
|
71
72
|
// Enforce HTTPS. The server does not redirect http -> https
|
|
72
73
|
// because OWASP advises not to
|
|
73
74
|
app.use((req, res, next) => {
|
|
74
75
|
if (process.env.NODE_ENV === "production" &&
|
|
75
|
-
req.header("X-Forwarded-Proto") !== "https"
|
|
76
|
+
req.header("X-Forwarded-Proto") !== "https" &&
|
|
77
|
+
!["/healthz", "/livez", "/readyz"].includes(req.path)) {
|
|
76
78
|
return res.status(403).send({ message: "SSL required" });
|
|
77
79
|
}
|
|
78
80
|
// allow the request to continue if https is used
|
|
79
81
|
next();
|
|
80
82
|
});
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
83
|
+
const healthCheck = (_req, res) => {
|
|
84
|
+
const terminating = app.locals["terminating"];
|
|
85
|
+
if (typeof terminating === "boolean" && terminating) {
|
|
86
|
+
logger.info("App is in TERMINATING state, sending health check failure");
|
|
87
|
+
return res.status(503).json({ status: "TERMINATING" });
|
|
88
|
+
}
|
|
89
|
+
return res.status(200).json({ status: "OK" });
|
|
90
|
+
};
|
|
91
|
+
app.get("/healthz", healthCheck);
|
|
92
|
+
app.get("/livez", healthCheck);
|
|
93
|
+
app.get("/readyz", healthCheck);
|
|
94
|
+
app.post("/*", (req, res) => {
|
|
95
|
+
const { json, code } = trigger_1.triggerProgram(req.body, program);
|
|
96
|
+
return res.status(code).json(json);
|
|
84
97
|
});
|
|
85
98
|
return app;
|
|
86
99
|
}
|
|
87
100
|
exports.webtask = webtask;
|
|
101
|
+
function runWebtask(webtask, config) {
|
|
102
|
+
const logger = logger_2.getLogger("program-boilerplate");
|
|
103
|
+
const server = webtask.listen(config.port, () => logger.notice(`${config.webtaskName} running on port ${config.port}`));
|
|
104
|
+
if (config.keepAliveTimeoutSeconds !== undefined) {
|
|
105
|
+
// https://cloud.google.com/load-balancing/docs/https/https-logging-monitoring#failure-messages
|
|
106
|
+
// (see the section on backend_connection_closed_before_data_sent_to_client)
|
|
107
|
+
server.keepAliveTimeout = config.keepAliveTimeoutSeconds * 1000;
|
|
108
|
+
server.headersTimeout = (config.keepAliveTimeoutSeconds + 1) * 1000;
|
|
109
|
+
}
|
|
110
|
+
const gracefulShutdown = (signal) => () => {
|
|
111
|
+
var _a;
|
|
112
|
+
const isTerminating = webtask.locals["terminating"];
|
|
113
|
+
if (typeof isTerminating === "boolean" && isTerminating) {
|
|
114
|
+
logger.warn("Server is already in TERMINATING state, not starting shutdown procedure again");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
webtask.locals["terminating"] = true;
|
|
118
|
+
logger.notice(`Received ${signal} signal, starting shutdown procedure`);
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
server.close(() => logger.notice("Server closed"));
|
|
121
|
+
}, ((_a = config.terminationDelaySeconds) !== null && _a !== void 0 ? _a : 1) * 1000);
|
|
122
|
+
};
|
|
123
|
+
process.on("SIGTERM", gracefulShutdown("SIGTERM"));
|
|
124
|
+
process.on("SIGINT", gracefulShutdown("SIGINT"));
|
|
125
|
+
}
|
|
126
|
+
exports.runWebtask = runWebtask;
|
package/dist/trigger.js
CHANGED
|
@@ -103,8 +103,7 @@ function handleProgramIntrospection(body, program) {
|
|
|
103
103
|
const handleIntrospection = program["PROGRAM_INTROSPECTION"];
|
|
104
104
|
try {
|
|
105
105
|
const newTemplate = (handleIntrospection &&
|
|
106
|
-
|
|
107
|
-
handleIntrospection(template, rules))) ||
|
|
106
|
+
handleIntrospection(template, rules, bodyProgram, tenant)) ||
|
|
108
107
|
template;
|
|
109
108
|
return {
|
|
110
109
|
json: newTemplate,
|
package/dist/types/rpc.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ProgramTemplateBuilder } from "@saasquatch/schema/types/ProgramTemplate";
|
|
1
2
|
import Transaction from "../transaction";
|
|
2
3
|
/********************************************************/
|
|
3
4
|
/********************************************************/
|
|
@@ -29,12 +30,18 @@ export declare type ProgramTriggerBody = {
|
|
|
29
30
|
activeTrigger: any;
|
|
30
31
|
program: any;
|
|
31
32
|
tenant: {
|
|
33
|
+
impactBrandId: number | undefined | null;
|
|
32
34
|
settings: {
|
|
33
35
|
suspectedFraudModerationState: string;
|
|
34
36
|
};
|
|
35
37
|
};
|
|
36
38
|
ids: string[];
|
|
37
39
|
};
|
|
40
|
+
declare type TenantInfo = {
|
|
41
|
+
tenantAlias: string;
|
|
42
|
+
featureFlags?: string[] | null;
|
|
43
|
+
isLiveMode: boolean;
|
|
44
|
+
};
|
|
38
45
|
/**
|
|
39
46
|
* A JSON request body for the PROGRAM_INTROSPECTION case
|
|
40
47
|
*/
|
|
@@ -43,10 +50,7 @@ export declare type ProgramIntrospectionBody = {
|
|
|
43
50
|
template: any;
|
|
44
51
|
rules: any;
|
|
45
52
|
program: any;
|
|
46
|
-
tenant:
|
|
47
|
-
tenantAlias: string;
|
|
48
|
-
isLiveMode: boolean;
|
|
49
|
-
};
|
|
53
|
+
tenant: TenantInfo;
|
|
50
54
|
};
|
|
51
55
|
/**
|
|
52
56
|
* The program validation request contains the requirement key
|
|
@@ -90,13 +94,21 @@ export declare type ProgramVariableSchemaRequestBody = {
|
|
|
90
94
|
* Handler for the default program trigger cases
|
|
91
95
|
*/
|
|
92
96
|
export declare type ProgramTriggerHandler = (transaction: Transaction) => void;
|
|
97
|
+
/**
|
|
98
|
+
* Output of program introspection
|
|
99
|
+
*/
|
|
100
|
+
export declare type ProgramIntrospectionResponse = ProgramTemplateBuilder | {
|
|
101
|
+
template: ProgramTemplateBuilder;
|
|
102
|
+
errors?: {
|
|
103
|
+
key: string;
|
|
104
|
+
jsonPointer: string;
|
|
105
|
+
description: string;
|
|
106
|
+
}[];
|
|
107
|
+
};
|
|
93
108
|
/**
|
|
94
109
|
* Introspection handler
|
|
95
110
|
*/
|
|
96
|
-
export declare type ProgramIntrospectionHandler = (template:
|
|
97
|
-
tenantAlias: string;
|
|
98
|
-
isLiveMode: boolean;
|
|
99
|
-
}) => any;
|
|
111
|
+
export declare type ProgramIntrospectionHandler = (template: ProgramTemplateBuilder, rules: any, program: any, tenant: TenantInfo) => ProgramIntrospectionResponse;
|
|
100
112
|
/**
|
|
101
113
|
* Handler for an individual program requirement validation.
|
|
102
114
|
* Handlers will be exported as key-value pairs in the
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { ProgramTriggerBody } from "./types/rpc";
|
|
2
2
|
import jsonata from "jsonata";
|
|
3
|
+
export declare type WebtaskConfig = {
|
|
4
|
+
port: number;
|
|
5
|
+
webtaskName: string;
|
|
6
|
+
keepAliveTimeoutSeconds: number;
|
|
7
|
+
terminationDelaySeconds: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function loadStandardWebtaskConfig(): WebtaskConfig;
|
|
3
10
|
/**
|
|
4
11
|
* Append a reward schedule to the template and return the new template
|
|
5
12
|
*
|
package/dist/utils.js
CHANGED
|
@@ -3,9 +3,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getRewardUnitsFromJsonata = exports.getUserCustomFieldsFromJsonata = exports.getTriggerSchema = exports.numToEquality = exports.inferType = exports.getGoalAnalyticTimestamp = exports.setRewardSchedule = void 0;
|
|
6
|
+
exports.getRewardUnitsFromJsonata = exports.getUserCustomFieldsFromJsonata = exports.getTriggerSchema = exports.numToEquality = exports.inferType = exports.getGoalAnalyticTimestamp = exports.setRewardSchedule = exports.loadStandardWebtaskConfig = void 0;
|
|
7
7
|
const queries_1 = require("./queries");
|
|
8
8
|
const jsonata_paths_extractor_1 = __importDefault(require("@saasquatch/jsonata-paths-extractor"));
|
|
9
|
+
function loadStandardWebtaskConfig() {
|
|
10
|
+
const optionalInt = (key, defaultVal) => {
|
|
11
|
+
const env = process.env[key];
|
|
12
|
+
if (!env) {
|
|
13
|
+
return defaultVal;
|
|
14
|
+
}
|
|
15
|
+
const parsedEnv = parseInt(env, 10);
|
|
16
|
+
if (Number.isNaN(parsedEnv)) {
|
|
17
|
+
throw new Error(`Environment variable "${key}" is not an integer`);
|
|
18
|
+
}
|
|
19
|
+
return parsedEnv;
|
|
20
|
+
};
|
|
21
|
+
const port = optionalInt("PORT", 3000);
|
|
22
|
+
const keepAliveTimeoutSeconds = optionalInt("HTTP_KEEP_ALIVE_SECONDS", 60);
|
|
23
|
+
const terminationDelaySeconds = optionalInt("TERMINATION_DELAY_SECONDS", 0);
|
|
24
|
+
const webtaskName = process.env["PROGRAM_NAME"] || "Unknown Program";
|
|
25
|
+
return {
|
|
26
|
+
port,
|
|
27
|
+
webtaskName,
|
|
28
|
+
keepAliveTimeoutSeconds,
|
|
29
|
+
terminationDelaySeconds,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
exports.loadStandardWebtaskConfig = loadStandardWebtaskConfig;
|
|
9
33
|
/**
|
|
10
34
|
* Append a reward schedule to the template and return the new template
|
|
11
35
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saasquatch/program-boilerplate",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0-0",
|
|
4
4
|
"description": "Boilerplate for writing programs",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -17,14 +17,17 @@
|
|
|
17
17
|
},
|
|
18
18
|
"author": "ReferralSaaSquatch.com, Inc.",
|
|
19
19
|
"license": "MIT",
|
|
20
|
+
"resolutions": {
|
|
21
|
+
"source-map": "^0.7.4"
|
|
22
|
+
},
|
|
20
23
|
"devDependencies": {
|
|
21
24
|
"@types/express": "^4.17.11",
|
|
22
25
|
"@types/node": "^13.13.50",
|
|
23
26
|
"@types/supertest": "^2.0.11",
|
|
24
27
|
"jest": "^26.6.3",
|
|
25
28
|
"jest-cucumber": "^3.0.1",
|
|
26
|
-
"np": "^7.7.0",
|
|
27
29
|
"prettier": "^2.2.1",
|
|
30
|
+
"source-map": "^0.7.4",
|
|
28
31
|
"supertest": "^6.1.3",
|
|
29
32
|
"ts-jest": "^26.5.5",
|
|
30
33
|
"ts-node": "^9.1.1",
|
|
@@ -33,7 +36,8 @@
|
|
|
33
36
|
},
|
|
34
37
|
"dependencies": {
|
|
35
38
|
"@saasquatch/jsonata-paths-extractor": "^1.0.1",
|
|
36
|
-
"@saasquatch/logger": "^1.
|
|
39
|
+
"@saasquatch/logger": "^1.5.1",
|
|
40
|
+
"@saasquatch/schema": "^1.28.2",
|
|
37
41
|
"bson-objectid": "^1.3.1",
|
|
38
42
|
"compression": "^1.7.4",
|
|
39
43
|
"express": "^4.17.1",
|