@terreno/api 0.13.2 → 0.14.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/__tests__/versionCheckPlugin.test.js +53 -3
- package/dist/api.arrayOperations.test.js +1 -0
- package/dist/api.asyncHandler.test.d.ts +1 -0
- package/dist/api.asyncHandler.test.js +236 -0
- package/dist/api.d.ts +15 -4
- package/dist/api.errors.test.js +1 -0
- package/dist/api.hooks.test.js +1 -0
- package/dist/api.js +153 -104
- package/dist/api.query.test.js +1 -0
- package/dist/api.test.js +174 -0
- package/dist/auth.d.ts +10 -5
- package/dist/auth.js +163 -90
- package/dist/auth.test.js +159 -0
- package/dist/betterAuthApp.test.js +1 -0
- package/dist/betterAuthSetup.d.ts +5 -6
- package/dist/betterAuthSetup.js +17 -14
- package/dist/betterAuthSetup.test.js +1 -0
- package/dist/config.d.ts +48 -0
- package/dist/config.js +248 -0
- package/dist/config.test.d.ts +1 -0
- package/dist/config.test.js +328 -0
- package/dist/configuration.test.js +1 -0
- package/dist/configurationApp.d.ts +1 -1
- package/dist/configurationApp.js +17 -13
- package/dist/configurationPlugin.test.js +1 -0
- package/dist/consentApp.test.js +1 -0
- package/dist/envConfigurationPlugin.d.ts +2 -0
- package/dist/envConfigurationPlugin.js +173 -0
- package/dist/envConfigurationPlugin.test.d.ts +1 -0
- package/dist/envConfigurationPlugin.test.js +322 -0
- package/dist/errors.d.ts +18 -7
- package/dist/errors.js +106 -10
- package/dist/errors.test.js +16 -1
- package/dist/example.js +16 -7
- package/dist/expressServer.d.ts +10 -9
- package/dist/expressServer.js +62 -53
- package/dist/expressServer.test.js +53 -2
- package/dist/githubAuth.d.ts +2 -1
- package/dist/githubAuth.js +41 -26
- package/dist/githubAuth.test.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +42 -20
- package/dist/models/versionConfig.d.ts +2 -0
- package/dist/models/versionConfig.js +8 -0
- package/dist/notifiers/googleChatNotifier.js +14 -16
- package/dist/notifiers/googleChatNotifier.test.js +1 -0
- package/dist/notifiers/slackNotifier.js +16 -14
- package/dist/notifiers/slackNotifier.test.js +41 -3
- package/dist/notifiers/zoomNotifier.js +7 -10
- package/dist/notifiers/zoomNotifier.test.js +1 -0
- package/dist/openApi.d.ts +1 -1
- package/dist/openApi.test.js +1 -0
- package/dist/openApiBuilder.d.ts +39 -6
- package/dist/openApiBuilder.js +1 -31
- package/dist/openApiBuilder.test.js +1 -0
- package/dist/openApiValidator.js +1 -0
- package/dist/openApiValidator.test.js +65 -0
- package/dist/permissions.d.ts +4 -4
- package/dist/permissions.js +67 -65
- package/dist/permissions.middleware.test.js +1 -0
- package/dist/permissions.test.js +1 -0
- package/dist/plugins.d.ts +5 -5
- package/dist/plugins.js +18 -9
- package/dist/plugins.test.js +1 -1
- package/dist/populate.d.ts +15 -8
- package/dist/populate.js +23 -24
- package/dist/populate.test.js +1 -0
- package/dist/realtime/changeStreamWatcher.d.ts +73 -0
- package/dist/realtime/changeStreamWatcher.js +720 -0
- package/dist/realtime/index.d.ts +6 -0
- package/dist/realtime/index.js +27 -0
- package/dist/realtime/queryMatcher.d.ts +14 -0
- package/dist/realtime/queryMatcher.js +250 -0
- package/dist/realtime/queryStore.d.ts +37 -0
- package/dist/realtime/queryStore.js +195 -0
- package/dist/realtime/realtime.test.d.ts +10 -0
- package/dist/realtime/realtime.test.js +2158 -0
- package/dist/realtime/realtimeApp.d.ts +93 -0
- package/dist/realtime/realtimeApp.js +560 -0
- package/dist/realtime/registry.d.ts +40 -0
- package/dist/realtime/registry.js +38 -0
- package/dist/realtime/socketUser.d.ts +10 -0
- package/dist/realtime/socketUser.js +17 -0
- package/dist/realtime/types.d.ts +100 -0
- package/dist/realtime/types.js +2 -0
- package/dist/requestContext.d.ts +37 -0
- package/dist/requestContext.js +344 -0
- package/dist/requestContext.test.d.ts +1 -0
- package/dist/requestContext.test.js +241 -0
- package/dist/terrenoApp.d.ts +8 -0
- package/dist/terrenoApp.js +50 -13
- package/dist/terrenoApp.test.js +194 -21
- package/dist/terrenoPlugin.d.ts +11 -0
- package/dist/tests/bunSetup.js +1 -0
- package/dist/tests.js +1 -1
- package/dist/transformers.d.ts +2 -2
- package/dist/transformers.js +5 -3
- package/dist/transformers.test.js +90 -0
- package/dist/types/consentResponse.d.ts +6 -3
- package/dist/versionCheckPlugin.d.ts +2 -0
- package/dist/versionCheckPlugin.js +18 -12
- package/package.json +4 -2
- package/src/__tests__/versionCheckPlugin.test.ts +37 -3
- package/src/api.arrayOperations.test.ts +1 -0
- package/src/api.asyncHandler.test.ts +177 -0
- package/src/api.errors.test.ts +1 -0
- package/src/api.hooks.test.ts +1 -0
- package/src/api.query.test.ts +1 -0
- package/src/api.test.ts +132 -0
- package/src/api.ts +199 -84
- package/src/auth.test.ts +160 -0
- package/src/auth.ts +120 -50
- package/src/betterAuthApp.test.ts +1 -0
- package/src/betterAuthSetup.test.ts +1 -0
- package/src/betterAuthSetup.ts +46 -19
- package/src/config.test.ts +255 -0
- package/src/config.ts +206 -0
- package/src/configuration.test.ts +1 -0
- package/src/configurationApp.ts +59 -24
- package/src/configurationPlugin.test.ts +1 -0
- package/src/consentApp.test.ts +1 -0
- package/src/envConfigurationPlugin.test.ts +143 -0
- package/src/envConfigurationPlugin.ts +100 -0
- package/src/errors.test.ts +19 -1
- package/src/errors.ts +94 -20
- package/src/example.ts +46 -21
- package/src/express.d.ts +18 -1
- package/src/expressServer.test.ts +50 -2
- package/src/expressServer.ts +80 -50
- package/src/githubAuth.test.ts +1 -0
- package/src/githubAuth.ts +59 -38
- package/src/index.ts +4 -0
- package/src/logger.ts +47 -17
- package/src/models/versionConfig.ts +13 -2
- package/src/notifiers/googleChatNotifier.test.ts +1 -0
- package/src/notifiers/googleChatNotifier.ts +7 -9
- package/src/notifiers/slackNotifier.test.ts +29 -3
- package/src/notifiers/slackNotifier.ts +9 -7
- package/src/notifiers/zoomNotifier.test.ts +1 -0
- package/src/notifiers/zoomNotifier.ts +8 -11
- package/src/openApi.test.ts +1 -0
- package/src/openApi.ts +4 -4
- package/src/openApiBuilder.test.ts +1 -0
- package/src/openApiBuilder.ts +14 -11
- package/src/openApiValidator.test.ts +59 -0
- package/src/openApiValidator.ts +3 -2
- package/src/permissions.middleware.test.ts +1 -0
- package/src/permissions.test.ts +1 -0
- package/src/permissions.ts +30 -25
- package/src/plugins.test.ts +1 -1
- package/src/plugins.ts +21 -14
- package/src/populate.test.ts +1 -0
- package/src/populate.ts +44 -36
- package/src/realtime/changeStreamWatcher.ts +568 -0
- package/src/realtime/index.ts +34 -0
- package/src/realtime/queryMatcher.ts +179 -0
- package/src/realtime/queryStore.ts +132 -0
- package/src/realtime/realtime.test.ts +1755 -0
- package/src/realtime/realtimeApp.ts +478 -0
- package/src/realtime/registry.ts +64 -0
- package/src/realtime/socketUser.ts +25 -0
- package/src/realtime/types.ts +112 -0
- package/src/requestContext.test.ts +196 -0
- package/src/requestContext.ts +368 -0
- package/src/terrenoApp.test.ts +137 -11
- package/src/terrenoApp.ts +64 -17
- package/src/terrenoPlugin.ts +12 -0
- package/src/tests/bunSetup.ts +1 -0
- package/src/tests.ts +7 -2
- package/src/transformers.test.ts +70 -2
- package/src/transformers.ts +15 -7
- package/src/types/consentResponse.ts +8 -10
- package/src/versionCheckPlugin.ts +15 -7
package/dist/expressServer.d.ts
CHANGED
|
@@ -5,13 +5,13 @@ import type { ModelRouterOptions } from "./api";
|
|
|
5
5
|
import { type UserModel as UserMongooseModel } from "./auth";
|
|
6
6
|
import { type GitHubAuthOptions } from "./githubAuth";
|
|
7
7
|
import { type LoggingOptions } from "./logger";
|
|
8
|
-
export declare
|
|
8
|
+
export declare const setupEnvironment: () => void;
|
|
9
9
|
export type AddRoutes = (router: Router, options?: Partial<ModelRouterOptions<unknown>>) => void;
|
|
10
|
-
export declare
|
|
11
|
-
export declare
|
|
12
|
-
export declare
|
|
10
|
+
export declare const logRequests: (req: any, res: any, next: express.NextFunction) => void;
|
|
11
|
+
export declare const createRouter: (rootPath: string, addRoutes: AddRoutes, middleware?: express.RequestHandler[]) => Array<string | express.RequestHandler | Router>;
|
|
12
|
+
export declare const createRouterWithAuth: (rootPath: string, addRoutes: (router: Router) => void, middleware?: express.RequestHandler[]) => Array<string | express.RequestHandler | Router>;
|
|
13
13
|
export interface AuthOptions {
|
|
14
|
-
generateJWTPayload?: (user: any) => Record<string,
|
|
14
|
+
generateJWTPayload?: (user: any) => Record<string, unknown>;
|
|
15
15
|
generateTokenExpiration?: (user: any) => number | jwt.SignOptions["expiresIn"];
|
|
16
16
|
generateRefreshTokenExpiration?: (user: any) => number | jwt.SignOptions["expiresIn"];
|
|
17
17
|
}
|
|
@@ -19,6 +19,7 @@ export interface SetupServerOptions {
|
|
|
19
19
|
userModel: UserMongooseModel;
|
|
20
20
|
addRoutes: AddRoutes;
|
|
21
21
|
loggingOptions?: LoggingOptions;
|
|
22
|
+
logRequests?: boolean;
|
|
22
23
|
authOptions?: AuthOptions;
|
|
23
24
|
/**
|
|
24
25
|
* GitHub OAuth configuration. When provided, enables GitHub authentication.
|
|
@@ -31,11 +32,11 @@ export interface SetupServerOptions {
|
|
|
31
32
|
ignoreTraces?: string[];
|
|
32
33
|
sentryOptions?: Sentry.BunOptions;
|
|
33
34
|
}
|
|
34
|
-
export declare
|
|
35
|
-
export declare
|
|
35
|
+
export declare const setupServer: (options: SetupServerOptions) => express.Application;
|
|
36
|
+
export declare const cronjob: (name: string, schedule: "hourly" | "minutely" | string, callback: () => void) => void;
|
|
36
37
|
export interface WrapScriptOptions {
|
|
37
|
-
onFinish?: (result?:
|
|
38
|
+
onFinish?: (result?: unknown) => void | Promise<void>;
|
|
38
39
|
terminateTimeout?: number;
|
|
39
40
|
slackChannel?: string;
|
|
40
41
|
}
|
|
41
|
-
export declare
|
|
42
|
+
export declare const wrapScript: (func: () => Promise<unknown>, options?: WrapScriptOptions) => Promise<void>;
|
package/dist/expressServer.js
CHANGED
|
@@ -97,13 +97,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
97
97
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
98
98
|
};
|
|
99
99
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
100
|
-
exports.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;
|
|
100
|
+
exports.wrapScript = exports.cronjob = exports.setupServer = exports.createRouterWithAuth = exports.createRouter = exports.logRequests = exports.setupEnvironment = void 0;
|
|
107
101
|
var Sentry = __importStar(require("@sentry/bun"));
|
|
108
102
|
var cors_1 = __importDefault(require("cors"));
|
|
109
103
|
var cron_1 = __importDefault(require("cron"));
|
|
@@ -119,11 +113,12 @@ var logger_1 = require("./logger");
|
|
|
119
113
|
var notifiers_1 = require("./notifiers");
|
|
120
114
|
var openApiCompat_1 = require("./openApiCompat");
|
|
121
115
|
var openApiEtag_1 = require("./openApiEtag");
|
|
116
|
+
var requestContext_1 = require("./requestContext");
|
|
122
117
|
var index_1 = __importDefault(require("./vendor/wesleytodd-openapi/index"));
|
|
123
118
|
var SLOW_READ_MAX = 200;
|
|
124
119
|
var SLOW_WRITE_MAX = 500;
|
|
125
120
|
var IS_JEST = process.env.JEST_WORKER_ID !== undefined;
|
|
126
|
-
function
|
|
121
|
+
var setupEnvironment = function () {
|
|
127
122
|
if (!process.env.TOKEN_ISSUER) {
|
|
128
123
|
throw new Error("TOKEN_ISSUER must be set in env.");
|
|
129
124
|
}
|
|
@@ -142,12 +137,14 @@ function setupEnvironment() {
|
|
|
142
137
|
if (!process.env.REFRESH_TOKEN_EXPIRES_IN && !IS_JEST) {
|
|
143
138
|
logger_1.logger.warn("REFRESH_TOKEN_EXPIRES_IN not set so using default.");
|
|
144
139
|
}
|
|
145
|
-
}
|
|
140
|
+
};
|
|
141
|
+
exports.setupEnvironment = setupEnvironment;
|
|
142
|
+
// biome-ignore lint/suspicious/noExplicitAny: also called from tests with mock request/response objects
|
|
146
143
|
var logRequestsFinished = function (req, res, startTime) {
|
|
147
|
-
var _a, _b, _c;
|
|
148
|
-
var options = ((_a = res.locals.loggingOptions) !== null &&
|
|
149
|
-
var slowReadMs = (
|
|
150
|
-
var slowWriteMs = (
|
|
144
|
+
var _a, _b, _c, _d;
|
|
145
|
+
var options = ((_b = (_a = res.locals) === null || _a === void 0 ? void 0 : _a.loggingOptions) !== null && _b !== void 0 ? _b : {});
|
|
146
|
+
var slowReadMs = (_c = options.logSlowRequestsReadMs) !== null && _c !== void 0 ? _c : SLOW_READ_MAX;
|
|
147
|
+
var slowWriteMs = (_d = options.logSlowRequestsWriteMs) !== null && _d !== void 0 ? _d : SLOW_WRITE_MAX;
|
|
151
148
|
var diff = process.hrtime.bigint() - startTime;
|
|
152
149
|
var diffInMs = Number(diff) / 1000000;
|
|
153
150
|
var pathName = "unknown";
|
|
@@ -180,7 +177,8 @@ var logRequestsFinished = function (req, res, startTime) {
|
|
|
180
177
|
}
|
|
181
178
|
}
|
|
182
179
|
};
|
|
183
|
-
|
|
180
|
+
// biome-ignore lint/suspicious/noExplicitAny: also called from tests with mock request/response objects
|
|
181
|
+
var logRequests = function (req, res, next) {
|
|
184
182
|
var _a, _b, _c, _d;
|
|
185
183
|
var startTime = process.hrtime.bigint();
|
|
186
184
|
var userString = "";
|
|
@@ -210,35 +208,38 @@ function logRequests(req, res, next) {
|
|
|
210
208
|
}
|
|
211
209
|
(0, on_finished_1.default)(res, function () { return logRequestsFinished(req, res, startTime); });
|
|
212
210
|
next();
|
|
213
|
-
}
|
|
214
|
-
|
|
211
|
+
};
|
|
212
|
+
exports.logRequests = logRequests;
|
|
213
|
+
var createRouter = function (rootPath, addRoutes, middleware) {
|
|
215
214
|
if (middleware === void 0) { middleware = []; }
|
|
216
|
-
function
|
|
215
|
+
var routePathMiddleware = function (req, _res, next) {
|
|
217
216
|
if (!req.routeMount) {
|
|
218
217
|
req.routeMount = [];
|
|
219
218
|
}
|
|
220
219
|
req.routeMount.push(rootPath);
|
|
221
220
|
next();
|
|
222
|
-
}
|
|
221
|
+
};
|
|
223
222
|
var router = express_1.default.Router();
|
|
224
223
|
router.use(routePathMiddleware);
|
|
225
224
|
addRoutes(router);
|
|
226
225
|
return __spreadArray(__spreadArray([rootPath], __read(middleware), false), [router], false);
|
|
227
|
-
}
|
|
228
|
-
|
|
226
|
+
};
|
|
227
|
+
exports.createRouter = createRouter;
|
|
228
|
+
var createRouterWithAuth = function (rootPath, addRoutes, middleware) {
|
|
229
229
|
if (middleware === void 0) { middleware = []; }
|
|
230
|
-
return createRouter(rootPath, addRoutes, __spreadArray([
|
|
230
|
+
return (0, exports.createRouter)(rootPath, addRoutes, __spreadArray([
|
|
231
231
|
passport_1.default.authenticate("firebase-jwt", { session: false })
|
|
232
232
|
], __read(middleware), false));
|
|
233
|
-
}
|
|
234
|
-
|
|
233
|
+
};
|
|
234
|
+
exports.createRouterWithAuth = createRouterWithAuth;
|
|
235
|
+
var initializeRoutes = function (UserModel, addRoutes, options) {
|
|
235
236
|
var _a;
|
|
236
237
|
if (options === void 0) { options = {}; }
|
|
237
238
|
var app = (0, express_1.default)();
|
|
238
239
|
// Record mount paths on layers for Express 5 → OpenAPI compat
|
|
239
240
|
(0, openApiCompat_1.patchAppUse)(app);
|
|
240
|
-
// TODO: Log a warning when we hit the array limit.
|
|
241
241
|
app.set("query parser", function (str) { var _a; return qs_1.default.parse(str, { arrayLimit: (_a = options.arrayLimit) !== null && _a !== void 0 ? _a : 200 }); });
|
|
242
|
+
app.use(requestContext_1.requestContextMiddleware);
|
|
242
243
|
app.use((0, cors_1.default)({
|
|
243
244
|
origin: (_a = options.corsOrigin) !== null && _a !== void 0 ? _a : "*",
|
|
244
245
|
}));
|
|
@@ -249,8 +250,12 @@ function initializeRoutes(UserModel, addRoutes, options) {
|
|
|
249
250
|
// Add login/signup/refresh_token before the JWT/auth middlewares
|
|
250
251
|
(0, auth_1.addAuthRoutes)(app, UserModel, options === null || options === void 0 ? void 0 : options.authOptions);
|
|
251
252
|
(0, auth_1.setupAuth)(app, UserModel);
|
|
253
|
+
app.use(function (req, res, next) {
|
|
254
|
+
(0, requestContext_1.updateRequestContextFromRequest)(req, res);
|
|
255
|
+
next();
|
|
256
|
+
});
|
|
252
257
|
if (options.logRequests !== false) {
|
|
253
|
-
app.use(logRequests);
|
|
258
|
+
app.use(exports.logRequests);
|
|
254
259
|
}
|
|
255
260
|
// Store the logging options on the request so we can access them later.
|
|
256
261
|
app.use(function (_req, res, next) {
|
|
@@ -259,17 +264,21 @@ function initializeRoutes(UserModel, addRoutes, options) {
|
|
|
259
264
|
});
|
|
260
265
|
// Add Sentry scopes for session, transaction, and userId if any are set
|
|
261
266
|
app.use(function (req, _res, next) {
|
|
262
|
-
var _a;
|
|
267
|
+
var _a, _b;
|
|
268
|
+
var context = (0, requestContext_1.getCurrentRequestContext)();
|
|
263
269
|
var transactionId = req.header("X-Transaction-ID");
|
|
264
|
-
var sessionId = req.header("X-Session-ID");
|
|
270
|
+
var sessionId = (_a = context === null || context === void 0 ? void 0 : context.sessionId) !== null && _a !== void 0 ? _a : req.header("X-Session-ID");
|
|
271
|
+
if (context === null || context === void 0 ? void 0 : context.requestId) {
|
|
272
|
+
Sentry.getCurrentScope().setTag("request_id", context.requestId);
|
|
273
|
+
}
|
|
265
274
|
if (transactionId) {
|
|
266
275
|
Sentry.getCurrentScope().setTag("transaction_id", transactionId);
|
|
267
276
|
}
|
|
268
277
|
if (sessionId) {
|
|
269
278
|
Sentry.getCurrentScope().setTag("session_id", sessionId);
|
|
270
279
|
}
|
|
271
|
-
if ((
|
|
272
|
-
Sentry.getCurrentScope().setTag("user", req.user._id);
|
|
280
|
+
if ((_b = req.user) === null || _b === void 0 ? void 0 : _b._id) {
|
|
281
|
+
Sentry.getCurrentScope().setTag("user", String(req.user._id));
|
|
273
282
|
}
|
|
274
283
|
next();
|
|
275
284
|
});
|
|
@@ -299,16 +308,10 @@ function initializeRoutes(UserModel, addRoutes, options) {
|
|
|
299
308
|
// Catch any thrown APIErrors and return them in an OpenAPI compatible format
|
|
300
309
|
app.use(errors_1.apiUnauthorizedMiddleware);
|
|
301
310
|
app.use(errors_1.apiErrorMiddleware);
|
|
302
|
-
app.use(
|
|
303
|
-
logger_1.logger.error("Fallthrough error: ".concat(err).concat((err === null || err === void 0 ? void 0 : err.stack) ? "\n".concat(err.stack) : "", "}"));
|
|
304
|
-
Sentry.captureException(err);
|
|
305
|
-
res.statusCode = 500;
|
|
306
|
-
res.end("".concat(res.sentry, "\n"));
|
|
307
|
-
});
|
|
311
|
+
app.use(errors_1.apiFallthroughErrorMiddleware);
|
|
308
312
|
return app;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function setupServer(options) {
|
|
313
|
+
};
|
|
314
|
+
var setupServer = function (options) {
|
|
312
315
|
var UserModel = options.userModel;
|
|
313
316
|
var addRoutes = options.addRoutes;
|
|
314
317
|
(0, logger_1.setupLogging)(options.loggingOptions);
|
|
@@ -319,10 +322,13 @@ function setupServer(options) {
|
|
|
319
322
|
authOptions: options.authOptions,
|
|
320
323
|
corsOrigin: options.corsOrigin,
|
|
321
324
|
githubAuth: options.githubAuth,
|
|
325
|
+
loggingOptions: options.loggingOptions,
|
|
326
|
+
logRequests: options.logRequests,
|
|
322
327
|
});
|
|
323
328
|
}
|
|
324
329
|
catch (error) {
|
|
325
|
-
|
|
330
|
+
var stack = error instanceof Error && error.stack ? error.stack : String(error);
|
|
331
|
+
logger_1.logger.error("Error initializing routes: ".concat(stack));
|
|
326
332
|
throw error;
|
|
327
333
|
}
|
|
328
334
|
if (!options.skipListen) {
|
|
@@ -333,14 +339,15 @@ function setupServer(options) {
|
|
|
333
339
|
});
|
|
334
340
|
}
|
|
335
341
|
catch (error) {
|
|
336
|
-
|
|
342
|
+
var stack = error instanceof Error ? error.stack : String(error);
|
|
343
|
+
logger_1.logger.error("Error trying to start HTTP server: ".concat(error, "\n").concat(stack));
|
|
337
344
|
process.exit(1);
|
|
338
345
|
}
|
|
339
346
|
}
|
|
340
347
|
return app;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function
|
|
348
|
+
};
|
|
349
|
+
exports.setupServer = setupServer;
|
|
350
|
+
var cronjob = function (name, schedule, callback) {
|
|
344
351
|
var cronSchedule = schedule === "hourly" ? "0 * * * *" : schedule === "minutely" ? "* * * * *" : schedule;
|
|
345
352
|
logger_1.logger.info("Adding cronjob ".concat(name, ", running at: ").concat(cronSchedule));
|
|
346
353
|
try {
|
|
@@ -349,13 +356,15 @@ function cronjob(name, schedule, callback) {
|
|
|
349
356
|
catch (error) {
|
|
350
357
|
throw new Error("Failed to create cronjob: ".concat(error));
|
|
351
358
|
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
359
|
+
};
|
|
360
|
+
exports.cronjob = cronjob;
|
|
361
|
+
var wrapScript = function (func_1) {
|
|
362
|
+
var args_1 = [];
|
|
363
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
364
|
+
args_1[_i - 1] = arguments[_i];
|
|
365
|
+
}
|
|
366
|
+
return __awaiter(void 0, __spreadArray([func_1], __read(args_1), false), void 0, function (func, options) {
|
|
357
367
|
var name, warnTime_1, closeTime, result, error_1;
|
|
358
|
-
var _this = this;
|
|
359
368
|
var _a, _b, _c;
|
|
360
369
|
if (options === void 0) { options = {}; }
|
|
361
370
|
return __generator(this, function (_d) {
|
|
@@ -371,7 +380,7 @@ function wrapScript(func_1) {
|
|
|
371
380
|
if (options.terminateTimeout !== 0) {
|
|
372
381
|
warnTime_1 = (((_b = options.terminateTimeout) !== null && _b !== void 0 ? _b : 300) / 2) * 1000;
|
|
373
382
|
closeTime = ((_c = options.terminateTimeout) !== null && _c !== void 0 ? _c : 300) * 1000;
|
|
374
|
-
setTimeout(function () { return __awaiter(
|
|
383
|
+
setTimeout(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
375
384
|
var msg;
|
|
376
385
|
return __generator(this, function (_a) {
|
|
377
386
|
switch (_a.label) {
|
|
@@ -385,7 +394,7 @@ function wrapScript(func_1) {
|
|
|
385
394
|
}
|
|
386
395
|
});
|
|
387
396
|
}); }, warnTime_1);
|
|
388
|
-
setTimeout(function () { return __awaiter(
|
|
397
|
+
setTimeout(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
389
398
|
var msg;
|
|
390
399
|
return __generator(this, function (_a) {
|
|
391
400
|
switch (_a.label) {
|
|
@@ -432,10 +441,10 @@ function wrapScript(func_1) {
|
|
|
432
441
|
case 9: return [4 /*yield*/, (0, notifiers_1.sendToSlack)("Success running script ".concat(name, ": ").concat(result))];
|
|
433
442
|
case 10:
|
|
434
443
|
_d.sent();
|
|
435
|
-
// Unclear why we have to exit here to prevent the script for continuing to run.
|
|
436
444
|
process.exit(0);
|
|
437
445
|
return [2 /*return*/];
|
|
438
446
|
}
|
|
439
447
|
});
|
|
440
448
|
});
|
|
441
|
-
}
|
|
449
|
+
};
|
|
450
|
+
exports.wrapScript = wrapScript;
|
|
@@ -86,10 +86,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
86
86
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
87
87
|
};
|
|
88
88
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
89
|
+
// biome-ignore-all lint/suspicious/noExplicitAny: test mock typing
|
|
89
90
|
var bun_test_1 = require("bun:test");
|
|
91
|
+
var node_stream_1 = require("node:stream");
|
|
90
92
|
var express_1 = __importDefault(require("express"));
|
|
91
93
|
var supertest_1 = __importDefault(require("supertest"));
|
|
94
|
+
var winston_1 = __importDefault(require("winston"));
|
|
92
95
|
var expressServer_1 = require("./expressServer");
|
|
96
|
+
var logger_1 = require("./logger");
|
|
93
97
|
var tests_1 = require("./tests");
|
|
94
98
|
(0, bun_test_1.describe)("expressServer", function () {
|
|
95
99
|
(0, bun_test_1.describe)("setupEnvironment", function () {
|
|
@@ -122,6 +126,55 @@ var tests_1 = require("./tests");
|
|
|
122
126
|
});
|
|
123
127
|
});
|
|
124
128
|
(0, bun_test_1.describe)("logRequests", function () {
|
|
129
|
+
(0, bun_test_1.it)("attaches request and session context to route logs", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
130
|
+
var logs, logStream, transport, app, res, parsedLog;
|
|
131
|
+
return __generator(this, function (_a) {
|
|
132
|
+
switch (_a.label) {
|
|
133
|
+
case 0:
|
|
134
|
+
logs = [];
|
|
135
|
+
logStream = new node_stream_1.Writable({
|
|
136
|
+
write: function (chunk, _encoding, callback) {
|
|
137
|
+
logs.push(chunk.toString());
|
|
138
|
+
callback();
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
transport = new winston_1.default.transports.Stream({
|
|
142
|
+
format: winston_1.default.format.json(),
|
|
143
|
+
stream: logStream,
|
|
144
|
+
});
|
|
145
|
+
app = (0, expressServer_1.setupServer)({
|
|
146
|
+
addRoutes: function (router) {
|
|
147
|
+
router.get("/context-test", function (req, res) {
|
|
148
|
+
logger_1.logger.info("context route log");
|
|
149
|
+
return res.json({ requestId: req.requestId, sessionId: req.sessionId });
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
logRequests: false,
|
|
153
|
+
skipListen: true,
|
|
154
|
+
userModel: tests_1.UserModel,
|
|
155
|
+
});
|
|
156
|
+
logger_1.winstonLogger.add(transport);
|
|
157
|
+
return [4 /*yield*/, (0, supertest_1.default)(app)
|
|
158
|
+
.get("/context-test")
|
|
159
|
+
.set("X-Request-ID", "req-123")
|
|
160
|
+
.set("X-Session-ID", "session-123")
|
|
161
|
+
.expect(200)];
|
|
162
|
+
case 1:
|
|
163
|
+
res = _a.sent();
|
|
164
|
+
(0, bun_test_1.expect)(res.headers["x-request-id"]).toBe("req-123");
|
|
165
|
+
(0, bun_test_1.expect)(res.headers["x-session-id"]).toBe("session-123");
|
|
166
|
+
(0, bun_test_1.expect)(res.body).toEqual({ requestId: "req-123", sessionId: "session-123" });
|
|
167
|
+
parsedLog = logs
|
|
168
|
+
.map(function (entry) { return JSON.parse(entry); })
|
|
169
|
+
.find(function (entry) { return entry.message === "context route log"; });
|
|
170
|
+
(0, bun_test_1.expect)(parsedLog).toBeDefined();
|
|
171
|
+
(0, bun_test_1.expect)(parsedLog.requestId).toBe("req-123");
|
|
172
|
+
(0, bun_test_1.expect)(parsedLog.sessionId).toBe("session-123");
|
|
173
|
+
logger_1.winstonLogger.remove(transport);
|
|
174
|
+
return [2 /*return*/];
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}); });
|
|
125
178
|
(0, bun_test_1.it)("logs request with admin user type", function () {
|
|
126
179
|
var req = {
|
|
127
180
|
body: {},
|
|
@@ -793,7 +846,6 @@ var tests_1 = require("./tests");
|
|
|
793
846
|
var originalSetTimeout = globalThis.setTimeout;
|
|
794
847
|
var timerIds = [];
|
|
795
848
|
(0, bun_test_1.beforeEach)(function () {
|
|
796
|
-
// biome-ignore lint/suspicious/noExplicitAny: Mock requires type override for process.exit.
|
|
797
849
|
process.exit = (0, bun_test_1.mock)(function () {
|
|
798
850
|
throw new Error("process.exit called");
|
|
799
851
|
});
|
|
@@ -930,7 +982,6 @@ var tests_1 = require("./tests");
|
|
|
930
982
|
return (0, expressServer_1.setupServer)({
|
|
931
983
|
addRoutes: addRoutes,
|
|
932
984
|
skipListen: true,
|
|
933
|
-
// biome-ignore lint/suspicious/noExplicitAny: Test mock for UserModel.
|
|
934
985
|
userModel: tests_1.UserModel,
|
|
935
986
|
});
|
|
936
987
|
}).toThrow("route initialization failed");
|
package/dist/githubAuth.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type express from "express";
|
|
2
|
+
import type { Schema } from "mongoose";
|
|
2
3
|
import { type Profile } from "passport-github2";
|
|
3
4
|
import { type UserModel } from "./auth";
|
|
4
5
|
import type { AuthOptions } from "./expressServer";
|
|
@@ -46,7 +47,7 @@ export interface GitHubUserFields {
|
|
|
46
47
|
* userSchema.plugin(githubUserPlugin);
|
|
47
48
|
* ```
|
|
48
49
|
*/
|
|
49
|
-
export declare const githubUserPlugin: (schema: any) => void;
|
|
50
|
+
export declare const githubUserPlugin: (schema: Schema<any, any, any, any>) => void;
|
|
50
51
|
/**
|
|
51
52
|
* Sets up GitHub OAuth authentication strategy.
|
|
52
53
|
* Call this after setupAuth() in your server initialization.
|
package/dist/githubAuth.js
CHANGED
|
@@ -58,12 +58,19 @@ var plugins_1 = require("./plugins");
|
|
|
58
58
|
* userSchema.plugin(githubUserPlugin);
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema generics must be loose to accept arbitrary consumer schemas
|
|
61
62
|
var githubUserPlugin = function (schema) {
|
|
62
63
|
schema.add({
|
|
63
|
-
githubAvatarUrl: { type: String },
|
|
64
|
-
githubId: {
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
githubAvatarUrl: { description: "GitHub avatar image URL", type: String },
|
|
65
|
+
githubId: {
|
|
66
|
+
description: "GitHub user ID",
|
|
67
|
+
index: true,
|
|
68
|
+
sparse: true,
|
|
69
|
+
type: String,
|
|
70
|
+
unique: true,
|
|
71
|
+
},
|
|
72
|
+
githubProfileUrl: { description: "GitHub profile URL", type: String },
|
|
73
|
+
githubUsername: { description: "GitHub username", type: String },
|
|
67
74
|
});
|
|
68
75
|
};
|
|
69
76
|
exports.githubUserPlugin = githubUserPlugin;
|
|
@@ -74,14 +81,16 @@ exports.githubUserPlugin = githubUserPlugin;
|
|
|
74
81
|
var setupGitHubAuth = function (_app, userModel, githubOptions) {
|
|
75
82
|
var _a;
|
|
76
83
|
var scope = (_a = githubOptions.scope) !== null && _a !== void 0 ? _a : ["user:email"];
|
|
77
|
-
passport_1.default.use("github",
|
|
84
|
+
passport_1.default.use("github",
|
|
85
|
+
// biome-ignore lint/suspicious/noExplicitAny: passport-github2's typed constructor overloads don't match passReqToCallback variant
|
|
86
|
+
new passport_github2_1.Strategy({
|
|
78
87
|
callbackURL: githubOptions.callbackURL,
|
|
79
88
|
clientID: githubOptions.clientId,
|
|
80
89
|
clientSecret: githubOptions.clientSecret,
|
|
81
90
|
passReqToCallback: true,
|
|
82
91
|
scope: scope,
|
|
83
|
-
},
|
|
84
|
-
var existingUser, user, githubId, existingGitHubUser, user, email, existingEmailUser, newUser, error_1;
|
|
92
|
+
}, function (req, accessToken, refreshToken, profile, done) { return __awaiter(void 0, void 0, void 0, function () {
|
|
93
|
+
var existingUser, user, githubId, existingGitHubUser, user, userWithGitHub, email, existingEmailUser, emailUserWithGitHub, newUser, error_1;
|
|
85
94
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
86
95
|
return __generator(this, function (_j) {
|
|
87
96
|
switch (_j.label) {
|
|
@@ -113,10 +122,11 @@ var setupGitHubAuth = function (_app, userModel, githubOptions) {
|
|
|
113
122
|
case 4:
|
|
114
123
|
user = _j.sent();
|
|
115
124
|
if (!user) return [3 /*break*/, 6];
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
userWithGitHub = user;
|
|
126
|
+
userWithGitHub.githubId = githubId;
|
|
127
|
+
userWithGitHub.githubUsername = profile.username;
|
|
128
|
+
userWithGitHub.githubProfileUrl = profile.profileUrl;
|
|
129
|
+
userWithGitHub.githubAvatarUrl = (_b = (_a = profile.photos) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value;
|
|
120
130
|
return [4 /*yield*/, user.save()];
|
|
121
131
|
case 5:
|
|
122
132
|
_j.sent();
|
|
@@ -134,10 +144,11 @@ var setupGitHubAuth = function (_app, userModel, githubOptions) {
|
|
|
134
144
|
existingEmailUser = _j.sent();
|
|
135
145
|
if (!existingEmailUser) return [3 /*break*/, 11];
|
|
136
146
|
if (!(githubOptions.allowAccountLinking !== false)) return [3 /*break*/, 10];
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
147
|
+
emailUserWithGitHub = existingEmailUser;
|
|
148
|
+
emailUserWithGitHub.githubId = githubId;
|
|
149
|
+
emailUserWithGitHub.githubUsername = profile.username;
|
|
150
|
+
emailUserWithGitHub.githubProfileUrl = profile.profileUrl;
|
|
151
|
+
emailUserWithGitHub.githubAvatarUrl = (_f = (_e = profile.photos) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.value;
|
|
141
152
|
return [4 /*yield*/, existingEmailUser.save()];
|
|
142
153
|
case 9:
|
|
143
154
|
_j.sent();
|
|
@@ -166,7 +177,7 @@ var setupGitHubAuth = function (_app, userModel, githubOptions) {
|
|
|
166
177
|
case 14: return [2 /*return*/];
|
|
167
178
|
}
|
|
168
179
|
});
|
|
169
|
-
}); }))
|
|
180
|
+
}); }));
|
|
170
181
|
};
|
|
171
182
|
exports.setupGitHubAuth = setupGitHubAuth;
|
|
172
183
|
/**
|
|
@@ -182,11 +193,13 @@ var addGitHubAuthRoutes = function (app, userModel, githubOptions, authOptions)
|
|
|
182
193
|
var router = (0, express_1.Router)();
|
|
183
194
|
// Initiate GitHub OAuth flow
|
|
184
195
|
router.get("/github", function (req, _res, next) {
|
|
196
|
+
var _a;
|
|
185
197
|
// Store the return URL in session or query for redirect after auth
|
|
186
198
|
var returnTo = req.query.returnTo;
|
|
187
199
|
if (returnTo) {
|
|
188
|
-
|
|
189
|
-
|
|
200
|
+
var reqWithSession = req;
|
|
201
|
+
reqWithSession.session = (_a = reqWithSession.session) !== null && _a !== void 0 ? _a : {};
|
|
202
|
+
reqWithSession.session.returnTo = returnTo;
|
|
190
203
|
}
|
|
191
204
|
next();
|
|
192
205
|
}, passport_1.default.authenticate("github", { session: false }));
|
|
@@ -208,11 +221,11 @@ var addGitHubAuthRoutes = function (app, userModel, githubOptions, authOptions)
|
|
|
208
221
|
// If there's a return URL, redirect with tokens as query params
|
|
209
222
|
if (returnTo) {
|
|
210
223
|
url = new URL(returnTo);
|
|
211
|
-
url.searchParams.set("token", tokens.token
|
|
224
|
+
url.searchParams.set("token", (_b = tokens.token) !== null && _b !== void 0 ? _b : "");
|
|
212
225
|
if (tokens.refreshToken) {
|
|
213
226
|
url.searchParams.set("refreshToken", tokens.refreshToken);
|
|
214
227
|
}
|
|
215
|
-
url.searchParams.set("userId", ((_c =
|
|
228
|
+
url.searchParams.set("userId", ((_c = req.user) === null || _c === void 0 ? void 0 : _c._id) ? String(req.user._id) : "");
|
|
216
229
|
return [2 /*return*/, res.redirect(url.toString())];
|
|
217
230
|
}
|
|
218
231
|
// Otherwise return JSON response
|
|
@@ -250,7 +263,7 @@ var addGitHubAuthRoutes = function (app, userModel, githubOptions, authOptions)
|
|
|
250
263
|
}, passport_1.default.authenticate("github", { session: false }));
|
|
251
264
|
// Unlink GitHub from user account
|
|
252
265
|
router.delete("/github/unlink", passport_1.default.authenticate("jwt", { session: false }), function (req, res) { return __awaiter(void 0, void 0, void 0, function () {
|
|
253
|
-
var user, hasPassword, error_3;
|
|
266
|
+
var user, userWithAuth, hasPassword, userWithGitHub, error_3;
|
|
254
267
|
return __generator(this, function (_a) {
|
|
255
268
|
switch (_a.label) {
|
|
256
269
|
case 0:
|
|
@@ -266,16 +279,18 @@ var addGitHubAuthRoutes = function (app, userModel, githubOptions, authOptions)
|
|
|
266
279
|
if (!user) {
|
|
267
280
|
return [2 /*return*/, res.status(404).json({ message: "User not found" })];
|
|
268
281
|
}
|
|
269
|
-
|
|
282
|
+
userWithAuth = user;
|
|
283
|
+
hasPassword = !!userWithAuth.hash || !!userWithAuth.salt;
|
|
270
284
|
if (!hasPassword) {
|
|
271
285
|
return [2 /*return*/, res.status(400).json({
|
|
272
286
|
message: "Cannot unlink GitHub account without another authentication method. Set a password first.",
|
|
273
287
|
})];
|
|
274
288
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
289
|
+
userWithGitHub = user;
|
|
290
|
+
userWithGitHub.githubId = undefined;
|
|
291
|
+
userWithGitHub.githubUsername = undefined;
|
|
292
|
+
userWithGitHub.githubProfileUrl = undefined;
|
|
293
|
+
userWithGitHub.githubAvatarUrl = undefined;
|
|
279
294
|
return [4 /*yield*/, user.save()];
|
|
280
295
|
case 3:
|
|
281
296
|
_a.sent();
|
package/dist/githubAuth.test.js
CHANGED
|
@@ -72,6 +72,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
72
72
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
73
73
|
};
|
|
74
74
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
75
|
+
// biome-ignore-all lint/suspicious/noExplicitAny: test mock typing
|
|
75
76
|
var bun_test_1 = require("bun:test");
|
|
76
77
|
var mongoose_1 = __importStar(require("mongoose"));
|
|
77
78
|
var passport_1 = __importDefault(require("passport"));
|
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,11 @@ export * from "./auth";
|
|
|
3
3
|
export * from "./betterAuth";
|
|
4
4
|
export * from "./betterAuthApp";
|
|
5
5
|
export * from "./betterAuthSetup";
|
|
6
|
+
export * from "./config";
|
|
6
7
|
export * from "./configurationApp";
|
|
7
8
|
export * from "./configurationPlugin";
|
|
8
9
|
export * from "./consentApp";
|
|
10
|
+
export * from "./envConfigurationPlugin";
|
|
9
11
|
export * from "./errors";
|
|
10
12
|
export * from "./expressServer";
|
|
11
13
|
export * from "./githubAuth";
|
|
@@ -22,6 +24,8 @@ export * from "./openApiValidator";
|
|
|
22
24
|
export * from "./permissions";
|
|
23
25
|
export * from "./plugins";
|
|
24
26
|
export * from "./populate";
|
|
27
|
+
export * from "./realtime";
|
|
28
|
+
export * from "./requestContext";
|
|
25
29
|
export * from "./scriptRunner";
|
|
26
30
|
export * from "./secretProviders";
|
|
27
31
|
export * from "./syncConsents";
|
package/dist/index.js
CHANGED
|
@@ -19,9 +19,11 @@ __exportStar(require("./auth"), exports);
|
|
|
19
19
|
__exportStar(require("./betterAuth"), exports);
|
|
20
20
|
__exportStar(require("./betterAuthApp"), exports);
|
|
21
21
|
__exportStar(require("./betterAuthSetup"), exports);
|
|
22
|
+
__exportStar(require("./config"), exports);
|
|
22
23
|
__exportStar(require("./configurationApp"), exports);
|
|
23
24
|
__exportStar(require("./configurationPlugin"), exports);
|
|
24
25
|
__exportStar(require("./consentApp"), exports);
|
|
26
|
+
__exportStar(require("./envConfigurationPlugin"), exports);
|
|
25
27
|
__exportStar(require("./errors"), exports);
|
|
26
28
|
__exportStar(require("./expressServer"), exports);
|
|
27
29
|
__exportStar(require("./githubAuth"), exports);
|
|
@@ -38,6 +40,8 @@ __exportStar(require("./openApiValidator"), exports);
|
|
|
38
40
|
__exportStar(require("./permissions"), exports);
|
|
39
41
|
__exportStar(require("./plugins"), exports);
|
|
40
42
|
__exportStar(require("./populate"), exports);
|
|
43
|
+
__exportStar(require("./realtime"), exports);
|
|
44
|
+
__exportStar(require("./requestContext"), exports);
|
|
41
45
|
__exportStar(require("./scriptRunner"), exports);
|
|
42
46
|
__exportStar(require("./secretProviders"), exports);
|
|
43
47
|
__exportStar(require("./syncConsents"), exports);
|
package/dist/logger.d.ts
CHANGED