@terreno/api 0.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/LICENSE +202 -0
- package/README.md +170 -0
- package/biome.jsonc +22 -0
- package/bunfig.toml +4 -0
- package/dist/api.d.ts +227 -0
- package/dist/api.js +1024 -0
- package/dist/api.test.d.ts +1 -0
- package/dist/api.test.js +2143 -0
- package/dist/auth.d.ts +50 -0
- package/dist/auth.js +512 -0
- package/dist/auth.test.d.ts +1 -0
- package/dist/auth.test.js +778 -0
- package/dist/errors.d.ts +75 -0
- package/dist/errors.js +216 -0
- package/dist/example.d.ts +1 -0
- package/dist/example.js +118 -0
- package/dist/expressServer.d.ts +35 -0
- package/dist/expressServer.js +436 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +30 -0
- package/dist/logger.d.ts +23 -0
- package/dist/logger.js +249 -0
- package/dist/middleware.d.ts +10 -0
- package/dist/middleware.js +52 -0
- package/dist/notifiers/googleChatNotifier.d.ts +5 -0
- package/dist/notifiers/googleChatNotifier.js +130 -0
- package/dist/notifiers/googleChatNotifier.test.d.ts +1 -0
- package/dist/notifiers/googleChatNotifier.test.js +260 -0
- package/dist/notifiers/index.d.ts +3 -0
- package/dist/notifiers/index.js +19 -0
- package/dist/notifiers/slackNotifier.d.ts +5 -0
- package/dist/notifiers/slackNotifier.js +130 -0
- package/dist/notifiers/slackNotifier.test.d.ts +1 -0
- package/dist/notifiers/slackNotifier.test.js +259 -0
- package/dist/notifiers/zoomNotifier.d.ts +34 -0
- package/dist/notifiers/zoomNotifier.js +181 -0
- package/dist/notifiers/zoomNotifier.test.d.ts +1 -0
- package/dist/notifiers/zoomNotifier.test.js +370 -0
- package/dist/openApi.d.ts +60 -0
- package/dist/openApi.js +441 -0
- package/dist/openApi.test.d.ts +1 -0
- package/dist/openApi.test.js +445 -0
- package/dist/openApiBuilder.d.ts +419 -0
- package/dist/openApiBuilder.js +424 -0
- package/dist/openApiBuilder.test.d.ts +1 -0
- package/dist/openApiBuilder.test.js +509 -0
- package/dist/openApiEtag.d.ts +7 -0
- package/dist/openApiEtag.js +38 -0
- package/dist/permissions.d.ts +26 -0
- package/dist/permissions.js +331 -0
- package/dist/permissions.test.d.ts +1 -0
- package/dist/permissions.test.js +413 -0
- package/dist/plugins.d.ts +67 -0
- package/dist/plugins.js +315 -0
- package/dist/plugins.test.d.ts +1 -0
- package/dist/plugins.test.js +639 -0
- package/dist/populate.d.ts +14 -0
- package/dist/populate.js +315 -0
- package/dist/populate.test.d.ts +1 -0
- package/dist/populate.test.js +133 -0
- package/dist/response.d.ts +0 -0
- package/dist/response.js +1 -0
- package/dist/tests/bunSetup.d.ts +1 -0
- package/dist/tests/bunSetup.js +297 -0
- package/dist/tests/index.d.ts +1 -0
- package/dist/tests/index.js +17 -0
- package/dist/tests.d.ts +99 -0
- package/dist/tests.js +273 -0
- package/dist/transformers.d.ts +25 -0
- package/dist/transformers.js +217 -0
- package/dist/transformers.test.d.ts +1 -0
- package/dist/transformers.test.js +370 -0
- package/dist/utils.d.ts +11 -0
- package/dist/utils.js +143 -0
- package/dist/utils.test.d.ts +1 -0
- package/dist/utils.test.js +14 -0
- package/index.ts +1 -0
- package/package.json +88 -0
- package/src/__snapshots__/openApi.test.ts.snap +4814 -0
- package/src/__snapshots__/openApiBuilder.test.ts.snap +1485 -0
- package/src/api.test.ts +1661 -0
- package/src/api.ts +1036 -0
- package/src/auth.test.ts +550 -0
- package/src/auth.ts +408 -0
- package/src/errors.ts +225 -0
- package/src/example.ts +99 -0
- package/src/express.d.ts +5 -0
- package/src/expressServer.ts +387 -0
- package/src/index.ts +14 -0
- package/src/logger.ts +190 -0
- package/src/middleware.ts +18 -0
- package/src/notifiers/googleChatNotifier.test.ts +114 -0
- package/src/notifiers/googleChatNotifier.ts +47 -0
- package/src/notifiers/index.ts +3 -0
- package/src/notifiers/slackNotifier.test.ts +113 -0
- package/src/notifiers/slackNotifier.ts +55 -0
- package/src/notifiers/zoomNotifier.test.ts +207 -0
- package/src/notifiers/zoomNotifier.ts +111 -0
- package/src/openApi.test.ts +331 -0
- package/src/openApi.ts +494 -0
- package/src/openApiBuilder.test.ts +442 -0
- package/src/openApiBuilder.ts +636 -0
- package/src/openApiEtag.ts +40 -0
- package/src/permissions.test.ts +219 -0
- package/src/permissions.ts +228 -0
- package/src/plugins.test.ts +390 -0
- package/src/plugins.ts +289 -0
- package/src/populate.test.ts +65 -0
- package/src/populate.ts +258 -0
- package/src/response.ts +0 -0
- package/src/tests/bunSetup.ts +234 -0
- package/src/tests/index.ts +1 -0
- package/src/tests.ts +218 -0
- package/src/transformers.test.ts +202 -0
- package/src/transformers.ts +170 -0
- package/src/utils.test.ts +14 -0
- package/src/utils.ts +47 -0
- package/tsconfig.json +60 -0
- package/types.d.ts +17 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
45
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
46
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
47
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
48
|
+
function step(op) {
|
|
49
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
50
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
51
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
52
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
53
|
+
switch (op[0]) {
|
|
54
|
+
case 0: case 1: t = op; break;
|
|
55
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
56
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
57
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
58
|
+
default:
|
|
59
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
60
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
61
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
62
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
63
|
+
if (t[2]) _.ops.pop();
|
|
64
|
+
_.trys.pop(); continue;
|
|
65
|
+
}
|
|
66
|
+
op = body.call(thisArg, _);
|
|
67
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
68
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
72
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
73
|
+
if (!m) return o;
|
|
74
|
+
var i = m.call(o), r, ar = [], e;
|
|
75
|
+
try {
|
|
76
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
77
|
+
}
|
|
78
|
+
catch (error) { e = { error: error }; }
|
|
79
|
+
finally {
|
|
80
|
+
try {
|
|
81
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
82
|
+
}
|
|
83
|
+
finally { if (e) throw e.error; }
|
|
84
|
+
}
|
|
85
|
+
return ar;
|
|
86
|
+
};
|
|
87
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
88
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
89
|
+
if (ar || !(i in from)) {
|
|
90
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
91
|
+
ar[i] = from[i];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
95
|
+
};
|
|
96
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
97
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
98
|
+
};
|
|
99
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
100
|
+
exports.setupEnvironment = setupEnvironment;
|
|
101
|
+
exports.logRequests = logRequests;
|
|
102
|
+
exports.createRouter = createRouter;
|
|
103
|
+
exports.createRouterWithAuth = createRouterWithAuth;
|
|
104
|
+
exports.setupServer = setupServer;
|
|
105
|
+
exports.cronjob = cronjob;
|
|
106
|
+
exports.wrapScript = wrapScript;
|
|
107
|
+
var Sentry = __importStar(require("@sentry/node"));
|
|
108
|
+
var openapi_1 = __importDefault(require("@wesleytodd/openapi"));
|
|
109
|
+
var cors_1 = __importDefault(require("cors"));
|
|
110
|
+
var cron_1 = __importDefault(require("cron"));
|
|
111
|
+
var express_1 = __importDefault(require("express"));
|
|
112
|
+
var cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
|
|
113
|
+
var on_finished_1 = __importDefault(require("on-finished"));
|
|
114
|
+
var passport_1 = __importDefault(require("passport"));
|
|
115
|
+
var qs_1 = __importDefault(require("qs"));
|
|
116
|
+
var auth_1 = require("./auth");
|
|
117
|
+
var errors_1 = require("./errors");
|
|
118
|
+
var logger_1 = require("./logger");
|
|
119
|
+
var notifiers_1 = require("./notifiers");
|
|
120
|
+
var openApiEtag_1 = require("./openApiEtag");
|
|
121
|
+
var SLOW_READ_MAX = 200;
|
|
122
|
+
var SLOW_WRITE_MAX = 500;
|
|
123
|
+
var IS_JEST = process.env.JEST_WORKER_ID !== undefined;
|
|
124
|
+
function setupEnvironment() {
|
|
125
|
+
if (!process.env.TOKEN_ISSUER) {
|
|
126
|
+
throw new Error("TOKEN_ISSUER must be set in env.");
|
|
127
|
+
}
|
|
128
|
+
if (!process.env.TOKEN_SECRET) {
|
|
129
|
+
throw new Error("TOKEN_SECRET must be set.");
|
|
130
|
+
}
|
|
131
|
+
if (!process.env.REFRESH_TOKEN_SECRET) {
|
|
132
|
+
throw new Error("REFRESH_TOKEN_SECRET must be set.");
|
|
133
|
+
}
|
|
134
|
+
if (!process.env.SESSION_SECRET) {
|
|
135
|
+
throw new Error("SESSION_SECRET must be set.");
|
|
136
|
+
}
|
|
137
|
+
if (!process.env.TOKEN_EXPIRES_IN && !IS_JEST) {
|
|
138
|
+
logger_1.logger.warn("TOKEN_EXPIRES_IN is not set so using default.");
|
|
139
|
+
}
|
|
140
|
+
if (!process.env.REFRESH_TOKEN_EXPIRES_IN && !IS_JEST) {
|
|
141
|
+
logger_1.logger.warn("REFRESH_TOKEN_EXPIRES_IN not set so using default.");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
var logRequestsFinished = function (req, res, startTime) {
|
|
145
|
+
var _a, _b, _c;
|
|
146
|
+
var options = ((_a = res.locals.loggingOptions) !== null && _a !== void 0 ? _a : {});
|
|
147
|
+
var slowReadMs = (_b = options.logSlowRequestsReadMs) !== null && _b !== void 0 ? _b : SLOW_READ_MAX;
|
|
148
|
+
var slowWriteMs = (_c = options.logSlowRequestsWriteMs) !== null && _c !== void 0 ? _c : SLOW_WRITE_MAX;
|
|
149
|
+
var diff = process.hrtime.bigint() - startTime;
|
|
150
|
+
var diffInMs = Number(diff) / 1000000;
|
|
151
|
+
var pathName = "unknown";
|
|
152
|
+
if (req.route && req.routeMount) {
|
|
153
|
+
pathName = "".concat(req.routeMount).concat(req.route.path);
|
|
154
|
+
}
|
|
155
|
+
else if (req.route) {
|
|
156
|
+
pathName = req.route.path;
|
|
157
|
+
}
|
|
158
|
+
else if (res.statusCode < 400) {
|
|
159
|
+
logger_1.logger.warn("Request without route: ".concat(req.originalUrl));
|
|
160
|
+
}
|
|
161
|
+
if (process.env.DISABLE_LOG_ALL_REQUESTS !== "true") {
|
|
162
|
+
logger_1.logger.debug("".concat(req.method, " -> ").concat(req.originalUrl, " ").concat(res.statusCode, " ").concat("".concat(diffInMs, "ms")));
|
|
163
|
+
}
|
|
164
|
+
if (options.logSlowRequests) {
|
|
165
|
+
if (diffInMs > slowReadMs && req.method === "GET") {
|
|
166
|
+
logger_1.logger.warn("Slow GET request, ".concat(JSON.stringify({
|
|
167
|
+
pathName: pathName,
|
|
168
|
+
requestTime: diffInMs,
|
|
169
|
+
url: req.originalUrl,
|
|
170
|
+
})));
|
|
171
|
+
}
|
|
172
|
+
else if (diffInMs > slowWriteMs) {
|
|
173
|
+
logger_1.logger.warn("Slow write request ".concat(JSON.stringify({
|
|
174
|
+
pathName: pathName,
|
|
175
|
+
requestTime: diffInMs,
|
|
176
|
+
url: req.originalUrl,
|
|
177
|
+
})));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
function logRequests(req, res, next) {
|
|
182
|
+
var _a, _b, _c, _d;
|
|
183
|
+
var startTime = process.hrtime.bigint();
|
|
184
|
+
var userString = "";
|
|
185
|
+
if (req.user) {
|
|
186
|
+
var type = "User";
|
|
187
|
+
if ((_a = req.user) === null || _a === void 0 ? void 0 : _a.admin) {
|
|
188
|
+
type = "Admin";
|
|
189
|
+
}
|
|
190
|
+
else if ((_b = req.user) === null || _b === void 0 ? void 0 : _b.testUser) {
|
|
191
|
+
type = "Test User";
|
|
192
|
+
}
|
|
193
|
+
else if ((_c = req.user) === null || _c === void 0 ? void 0 : _c.type) {
|
|
194
|
+
type = (_d = req.user) === null || _d === void 0 ? void 0 : _d.type;
|
|
195
|
+
}
|
|
196
|
+
userString = " <".concat(type, ":").concat(req.user.id, ">");
|
|
197
|
+
}
|
|
198
|
+
var body = "";
|
|
199
|
+
if (req.body && Object.keys(req.body).length > 0) {
|
|
200
|
+
var bodyCopy = (0, cloneDeep_1.default)(req.body);
|
|
201
|
+
if (bodyCopy.password) {
|
|
202
|
+
bodyCopy.password = "<PASSWORD>";
|
|
203
|
+
}
|
|
204
|
+
body = " Body: ".concat(JSON.stringify(bodyCopy));
|
|
205
|
+
}
|
|
206
|
+
if (process.env.DISABLE_LOG_ALL_REQUESTS !== "true") {
|
|
207
|
+
logger_1.logger.debug("".concat(req.method, " <- ").concat(req.url).concat(userString).concat(body));
|
|
208
|
+
}
|
|
209
|
+
(0, on_finished_1.default)(res, function () { return logRequestsFinished(req, res, startTime); });
|
|
210
|
+
next();
|
|
211
|
+
}
|
|
212
|
+
function createRouter(rootPath, addRoutes, middleware) {
|
|
213
|
+
if (middleware === void 0) { middleware = []; }
|
|
214
|
+
function routePathMiddleware(req, _res, next) {
|
|
215
|
+
if (!req.routeMount) {
|
|
216
|
+
req.routeMount = [];
|
|
217
|
+
}
|
|
218
|
+
req.routeMount.push(rootPath);
|
|
219
|
+
next();
|
|
220
|
+
}
|
|
221
|
+
var router = express_1.default.Router();
|
|
222
|
+
router.use(routePathMiddleware);
|
|
223
|
+
addRoutes(router);
|
|
224
|
+
return __spreadArray(__spreadArray([rootPath], __read(middleware), false), [router], false);
|
|
225
|
+
}
|
|
226
|
+
function createRouterWithAuth(rootPath, addRoutes, middleware) {
|
|
227
|
+
if (middleware === void 0) { middleware = []; }
|
|
228
|
+
return createRouter(rootPath, addRoutes, __spreadArray([
|
|
229
|
+
passport_1.default.authenticate("firebase-jwt", { session: false })
|
|
230
|
+
], __read(middleware), false));
|
|
231
|
+
}
|
|
232
|
+
function initializeRoutes(UserModel, addRoutes, options) {
|
|
233
|
+
var _a;
|
|
234
|
+
if (options === void 0) { options = {}; }
|
|
235
|
+
var app = (0, express_1.default)();
|
|
236
|
+
// TODO: Log a warning when we hit the array limit.
|
|
237
|
+
app.set("query parser", function (str) { var _a; return qs_1.default.parse(str, { arrayLimit: (_a = options.arrayLimit) !== null && _a !== void 0 ? _a : 200 }); });
|
|
238
|
+
app.use((0, cors_1.default)({
|
|
239
|
+
origin: (_a = options.corsOrigin) !== null && _a !== void 0 ? _a : "*",
|
|
240
|
+
}));
|
|
241
|
+
if (options.addMiddleware) {
|
|
242
|
+
options.addMiddleware(app);
|
|
243
|
+
}
|
|
244
|
+
app.use(express_1.default.json());
|
|
245
|
+
// Add login/signup/refresh_token before the JWT/auth middlewares
|
|
246
|
+
(0, auth_1.addAuthRoutes)(app, UserModel, options === null || options === void 0 ? void 0 : options.authOptions);
|
|
247
|
+
(0, auth_1.setupAuth)(app, UserModel);
|
|
248
|
+
if (options.logRequests !== false) {
|
|
249
|
+
app.use(logRequests);
|
|
250
|
+
}
|
|
251
|
+
// Store the logging options on the request so we can access them later.
|
|
252
|
+
app.use(function (_req, res, next) {
|
|
253
|
+
res.locals.loggingOptions = options.loggingOptions;
|
|
254
|
+
next();
|
|
255
|
+
});
|
|
256
|
+
// Add Sentry scopes for session, transaction, and userId if any are set
|
|
257
|
+
app.all("*", function (req, _res, next) {
|
|
258
|
+
var _a;
|
|
259
|
+
var transactionId = req.header("X-Transaction-ID");
|
|
260
|
+
var sessionId = req.header("X-Session-ID");
|
|
261
|
+
if (transactionId) {
|
|
262
|
+
Sentry.getCurrentScope().setTag("transaction_id", transactionId);
|
|
263
|
+
}
|
|
264
|
+
if (sessionId) {
|
|
265
|
+
Sentry.getCurrentScope().setTag("session_id", sessionId);
|
|
266
|
+
}
|
|
267
|
+
if ((_a = req.user) === null || _a === void 0 ? void 0 : _a._id) {
|
|
268
|
+
Sentry.getCurrentScope().setTag("user", req.user._id);
|
|
269
|
+
}
|
|
270
|
+
next();
|
|
271
|
+
});
|
|
272
|
+
// Add ETag middleware for OpenAPI JSON endpoint before the openapi middleware
|
|
273
|
+
app.use(openApiEtag_1.openApiEtagMiddleware);
|
|
274
|
+
var oapi = (0, openapi_1.default)({
|
|
275
|
+
info: {
|
|
276
|
+
description: "Generated docs from an Express api",
|
|
277
|
+
title: "Express Application",
|
|
278
|
+
version: "1.0.0",
|
|
279
|
+
},
|
|
280
|
+
openapi: "3.0.0",
|
|
281
|
+
});
|
|
282
|
+
app.use(oapi);
|
|
283
|
+
if (process.env.ENABLE_SWAGGER === "true") {
|
|
284
|
+
app.use("/swagger", oapi.swaggerui());
|
|
285
|
+
}
|
|
286
|
+
(0, auth_1.addMeRoutes)(app, UserModel, options === null || options === void 0 ? void 0 : options.authOptions);
|
|
287
|
+
addRoutes(app, { openApi: oapi });
|
|
288
|
+
Sentry.setupExpressErrorHandler(app);
|
|
289
|
+
// Catch any thrown APIErrors and return them in an OpenAPI compatible format
|
|
290
|
+
app.use(errors_1.apiUnauthorizedMiddleware);
|
|
291
|
+
app.use(errors_1.apiErrorMiddleware);
|
|
292
|
+
app.use(function onError(err, _req, res, _next) {
|
|
293
|
+
logger_1.logger.error("Fallthrough error: ".concat(err).concat((err === null || err === void 0 ? void 0 : err.stack) ? "\n".concat(err.stack) : "", "}"));
|
|
294
|
+
Sentry.captureException(err);
|
|
295
|
+
res.statusCode = 500;
|
|
296
|
+
res.end("".concat(res.sentry, "\n"));
|
|
297
|
+
});
|
|
298
|
+
return app;
|
|
299
|
+
}
|
|
300
|
+
// Sets up the routes and returns a function to launch the API.
|
|
301
|
+
function setupServer(options) {
|
|
302
|
+
var UserModel = options.userModel;
|
|
303
|
+
var addRoutes = options.addRoutes;
|
|
304
|
+
(0, logger_1.setupLogging)(options.loggingOptions);
|
|
305
|
+
var app;
|
|
306
|
+
try {
|
|
307
|
+
app = initializeRoutes(UserModel, addRoutes, {
|
|
308
|
+
addMiddleware: options.addMiddleware,
|
|
309
|
+
authOptions: options.authOptions,
|
|
310
|
+
corsOrigin: options.corsOrigin,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
logger_1.logger.error("Error initializing routes: ".concat(error.stack));
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
if (!options.skipListen) {
|
|
318
|
+
var port_1 = process.env.PORT || "9000";
|
|
319
|
+
try {
|
|
320
|
+
app.listen(port_1, function () {
|
|
321
|
+
logger_1.logger.info("Listening on port ".concat(port_1));
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
catch (error) {
|
|
325
|
+
logger_1.logger.error("Error trying to start HTTP server: ".concat(error, "\n").concat(error.stack));
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return app;
|
|
330
|
+
}
|
|
331
|
+
// Convenience method to execute cronjobs with an always-running server.
|
|
332
|
+
function cronjob(name, schedule, callback) {
|
|
333
|
+
var _cronSchedule = schedule;
|
|
334
|
+
if (schedule === "hourly") {
|
|
335
|
+
_cronSchedule = "0 * * * *";
|
|
336
|
+
}
|
|
337
|
+
else if (schedule === "minutely") {
|
|
338
|
+
_cronSchedule = "* * * * *";
|
|
339
|
+
}
|
|
340
|
+
logger_1.logger.info("Adding cronjob ".concat(name, ", running at: ").concat(schedule));
|
|
341
|
+
try {
|
|
342
|
+
new cron_1.default.CronJob(schedule, callback, null, true, "America/Chicago");
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
throw new Error("Failed to create cronjob: ".concat(error));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Wrap up a script with some helpers, such as catching errors, reporting them to sentry, notifying
|
|
349
|
+
// Slack of runs, etc. Also supports timeouts.
|
|
350
|
+
function wrapScript(func_1) {
|
|
351
|
+
return __awaiter(this, arguments, void 0, function (func, options) {
|
|
352
|
+
var name, warnTime_1, closeTime, result, error_1;
|
|
353
|
+
var _this = this;
|
|
354
|
+
var _a, _b, _c;
|
|
355
|
+
if (options === void 0) { options = {}; }
|
|
356
|
+
return __generator(this, function (_d) {
|
|
357
|
+
switch (_d.label) {
|
|
358
|
+
case 0:
|
|
359
|
+
name = (_a = require.main) === null || _a === void 0 ? void 0 : _a.filename.split("/").slice(-1)[0].replace(".ts", "");
|
|
360
|
+
logger_1.logger.info("Running script ".concat(name));
|
|
361
|
+
return [4 /*yield*/, (0, notifiers_1.sendToSlack)("Running script ".concat(name), {
|
|
362
|
+
slackChannel: options.slackChannel,
|
|
363
|
+
})];
|
|
364
|
+
case 1:
|
|
365
|
+
_d.sent();
|
|
366
|
+
if (options.terminateTimeout !== 0) {
|
|
367
|
+
warnTime_1 = (((_b = options.terminateTimeout) !== null && _b !== void 0 ? _b : 300) / 2) * 1000;
|
|
368
|
+
closeTime = ((_c = options.terminateTimeout) !== null && _c !== void 0 ? _c : 300) * 1000;
|
|
369
|
+
setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
370
|
+
var msg;
|
|
371
|
+
return __generator(this, function (_a) {
|
|
372
|
+
switch (_a.label) {
|
|
373
|
+
case 0:
|
|
374
|
+
msg = "Script ".concat(name, " is taking a while, currently ").concat(warnTime_1 / 1000, " seconds");
|
|
375
|
+
return [4 /*yield*/, (0, notifiers_1.sendToSlack)(msg)];
|
|
376
|
+
case 1:
|
|
377
|
+
_a.sent();
|
|
378
|
+
logger_1.logger.warn(msg);
|
|
379
|
+
return [2 /*return*/];
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}); }, warnTime_1);
|
|
383
|
+
setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
384
|
+
var msg;
|
|
385
|
+
return __generator(this, function (_a) {
|
|
386
|
+
switch (_a.label) {
|
|
387
|
+
case 0:
|
|
388
|
+
msg = "Script ".concat(name, " took too long, exiting");
|
|
389
|
+
return [4 /*yield*/, (0, notifiers_1.sendToSlack)(msg)];
|
|
390
|
+
case 1:
|
|
391
|
+
_a.sent();
|
|
392
|
+
logger_1.logger.error(msg);
|
|
393
|
+
Sentry.captureException(new Error("Script ".concat(name, " took too long, exiting")));
|
|
394
|
+
return [4 /*yield*/, Sentry.flush()];
|
|
395
|
+
case 2:
|
|
396
|
+
_a.sent();
|
|
397
|
+
process.exit(2);
|
|
398
|
+
return [2 /*return*/];
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}); }, closeTime);
|
|
402
|
+
}
|
|
403
|
+
_d.label = 2;
|
|
404
|
+
case 2:
|
|
405
|
+
_d.trys.push([2, 6, , 9]);
|
|
406
|
+
return [4 /*yield*/, func()];
|
|
407
|
+
case 3:
|
|
408
|
+
result = _d.sent();
|
|
409
|
+
if (!options.onFinish) return [3 /*break*/, 5];
|
|
410
|
+
return [4 /*yield*/, options.onFinish(result)];
|
|
411
|
+
case 4:
|
|
412
|
+
_d.sent();
|
|
413
|
+
_d.label = 5;
|
|
414
|
+
case 5: return [3 /*break*/, 9];
|
|
415
|
+
case 6:
|
|
416
|
+
error_1 = _d.sent();
|
|
417
|
+
Sentry.captureException(error_1);
|
|
418
|
+
logger_1.logger.error("Error running script ".concat(name, ": ").concat(error_1, "\n").concat(error_1.stack));
|
|
419
|
+
return [4 /*yield*/, (0, notifiers_1.sendToSlack)("Error running script ".concat(name, ": ").concat(error_1, "\n").concat(error_1.stack))];
|
|
420
|
+
case 7:
|
|
421
|
+
_d.sent();
|
|
422
|
+
return [4 /*yield*/, Sentry.flush()];
|
|
423
|
+
case 8:
|
|
424
|
+
_d.sent();
|
|
425
|
+
process.exit(1);
|
|
426
|
+
return [3 /*break*/, 9];
|
|
427
|
+
case 9: return [4 /*yield*/, (0, notifiers_1.sendToSlack)("Success running script ".concat(name, ": ").concat(result))];
|
|
428
|
+
case 10:
|
|
429
|
+
_d.sent();
|
|
430
|
+
// Unclear why we have to exit here to prevent the script for continuing to run.
|
|
431
|
+
process.exit(0);
|
|
432
|
+
return [2 /*return*/];
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./api";
|
|
2
|
+
export * from "./auth";
|
|
3
|
+
export * from "./errors";
|
|
4
|
+
export * from "./expressServer";
|
|
5
|
+
export * from "./logger";
|
|
6
|
+
export * from "./middleware";
|
|
7
|
+
export * from "./notifiers";
|
|
8
|
+
export * from "./openApiBuilder";
|
|
9
|
+
export * from "./openApiEtag";
|
|
10
|
+
export * from "./permissions";
|
|
11
|
+
export * from "./plugins";
|
|
12
|
+
export * from "./populate";
|
|
13
|
+
export * from "./transformers";
|
|
14
|
+
export * from "./utils";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./api"), exports);
|
|
18
|
+
__exportStar(require("./auth"), exports);
|
|
19
|
+
__exportStar(require("./errors"), exports);
|
|
20
|
+
__exportStar(require("./expressServer"), exports);
|
|
21
|
+
__exportStar(require("./logger"), exports);
|
|
22
|
+
__exportStar(require("./middleware"), exports);
|
|
23
|
+
__exportStar(require("./notifiers"), exports);
|
|
24
|
+
__exportStar(require("./openApiBuilder"), exports);
|
|
25
|
+
__exportStar(require("./openApiEtag"), exports);
|
|
26
|
+
__exportStar(require("./permissions"), exports);
|
|
27
|
+
__exportStar(require("./plugins"), exports);
|
|
28
|
+
__exportStar(require("./populate"), exports);
|
|
29
|
+
__exportStar(require("./transformers"), exports);
|
|
30
|
+
__exportStar(require("./utils"), exports);
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import winston from "winston";
|
|
2
|
+
export declare const winstonLogger: winston.Logger;
|
|
3
|
+
export declare const logger: {
|
|
4
|
+
catch: (e: unknown) => void;
|
|
5
|
+
debug: (msg: string, ...args: unknown[]) => void;
|
|
6
|
+
error: (msg: string, ...args: unknown[]) => void;
|
|
7
|
+
info: (msg: string, ...args: unknown[]) => void;
|
|
8
|
+
warn: (msg: string, ...args: unknown[]) => void;
|
|
9
|
+
};
|
|
10
|
+
export interface LoggingOptions {
|
|
11
|
+
level?: "debug" | "info" | "warn" | "error";
|
|
12
|
+
transports?: winston.transport[];
|
|
13
|
+
disableFileLogging?: boolean;
|
|
14
|
+
disableConsoleLogging?: boolean;
|
|
15
|
+
disableConsoleColors?: boolean;
|
|
16
|
+
showConsoleTimestamps?: boolean;
|
|
17
|
+
logDirectory?: string;
|
|
18
|
+
logRequests?: boolean;
|
|
19
|
+
logSlowRequests?: boolean;
|
|
20
|
+
logSlowRequestsReadMs?: number;
|
|
21
|
+
logSlowRequestsWriteMs?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function setupLogging(options?: LoggingOptions): void;
|