@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.
Files changed (175) hide show
  1. package/dist/__tests__/versionCheckPlugin.test.js +53 -3
  2. package/dist/api.arrayOperations.test.js +1 -0
  3. package/dist/api.asyncHandler.test.d.ts +1 -0
  4. package/dist/api.asyncHandler.test.js +236 -0
  5. package/dist/api.d.ts +15 -4
  6. package/dist/api.errors.test.js +1 -0
  7. package/dist/api.hooks.test.js +1 -0
  8. package/dist/api.js +153 -104
  9. package/dist/api.query.test.js +1 -0
  10. package/dist/api.test.js +174 -0
  11. package/dist/auth.d.ts +10 -5
  12. package/dist/auth.js +163 -90
  13. package/dist/auth.test.js +159 -0
  14. package/dist/betterAuthApp.test.js +1 -0
  15. package/dist/betterAuthSetup.d.ts +5 -6
  16. package/dist/betterAuthSetup.js +17 -14
  17. package/dist/betterAuthSetup.test.js +1 -0
  18. package/dist/config.d.ts +48 -0
  19. package/dist/config.js +248 -0
  20. package/dist/config.test.d.ts +1 -0
  21. package/dist/config.test.js +328 -0
  22. package/dist/configuration.test.js +1 -0
  23. package/dist/configurationApp.d.ts +1 -1
  24. package/dist/configurationApp.js +17 -13
  25. package/dist/configurationPlugin.test.js +1 -0
  26. package/dist/consentApp.test.js +1 -0
  27. package/dist/envConfigurationPlugin.d.ts +2 -0
  28. package/dist/envConfigurationPlugin.js +173 -0
  29. package/dist/envConfigurationPlugin.test.d.ts +1 -0
  30. package/dist/envConfigurationPlugin.test.js +322 -0
  31. package/dist/errors.d.ts +18 -7
  32. package/dist/errors.js +106 -10
  33. package/dist/errors.test.js +16 -1
  34. package/dist/example.js +16 -7
  35. package/dist/expressServer.d.ts +10 -9
  36. package/dist/expressServer.js +62 -53
  37. package/dist/expressServer.test.js +53 -2
  38. package/dist/githubAuth.d.ts +2 -1
  39. package/dist/githubAuth.js +41 -26
  40. package/dist/githubAuth.test.js +1 -0
  41. package/dist/index.d.ts +4 -0
  42. package/dist/index.js +4 -0
  43. package/dist/logger.d.ts +1 -1
  44. package/dist/logger.js +42 -20
  45. package/dist/models/versionConfig.d.ts +2 -0
  46. package/dist/models/versionConfig.js +8 -0
  47. package/dist/notifiers/googleChatNotifier.js +14 -16
  48. package/dist/notifiers/googleChatNotifier.test.js +1 -0
  49. package/dist/notifiers/slackNotifier.js +16 -14
  50. package/dist/notifiers/slackNotifier.test.js +41 -3
  51. package/dist/notifiers/zoomNotifier.js +7 -10
  52. package/dist/notifiers/zoomNotifier.test.js +1 -0
  53. package/dist/openApi.d.ts +1 -1
  54. package/dist/openApi.test.js +1 -0
  55. package/dist/openApiBuilder.d.ts +39 -6
  56. package/dist/openApiBuilder.js +1 -31
  57. package/dist/openApiBuilder.test.js +1 -0
  58. package/dist/openApiValidator.js +1 -0
  59. package/dist/openApiValidator.test.js +65 -0
  60. package/dist/permissions.d.ts +4 -4
  61. package/dist/permissions.js +67 -65
  62. package/dist/permissions.middleware.test.js +1 -0
  63. package/dist/permissions.test.js +1 -0
  64. package/dist/plugins.d.ts +5 -5
  65. package/dist/plugins.js +18 -9
  66. package/dist/plugins.test.js +1 -1
  67. package/dist/populate.d.ts +15 -8
  68. package/dist/populate.js +23 -24
  69. package/dist/populate.test.js +1 -0
  70. package/dist/realtime/changeStreamWatcher.d.ts +73 -0
  71. package/dist/realtime/changeStreamWatcher.js +720 -0
  72. package/dist/realtime/index.d.ts +6 -0
  73. package/dist/realtime/index.js +27 -0
  74. package/dist/realtime/queryMatcher.d.ts +14 -0
  75. package/dist/realtime/queryMatcher.js +250 -0
  76. package/dist/realtime/queryStore.d.ts +37 -0
  77. package/dist/realtime/queryStore.js +195 -0
  78. package/dist/realtime/realtime.test.d.ts +10 -0
  79. package/dist/realtime/realtime.test.js +2158 -0
  80. package/dist/realtime/realtimeApp.d.ts +93 -0
  81. package/dist/realtime/realtimeApp.js +560 -0
  82. package/dist/realtime/registry.d.ts +40 -0
  83. package/dist/realtime/registry.js +38 -0
  84. package/dist/realtime/socketUser.d.ts +10 -0
  85. package/dist/realtime/socketUser.js +17 -0
  86. package/dist/realtime/types.d.ts +100 -0
  87. package/dist/realtime/types.js +2 -0
  88. package/dist/requestContext.d.ts +37 -0
  89. package/dist/requestContext.js +344 -0
  90. package/dist/requestContext.test.d.ts +1 -0
  91. package/dist/requestContext.test.js +241 -0
  92. package/dist/terrenoApp.d.ts +8 -0
  93. package/dist/terrenoApp.js +50 -13
  94. package/dist/terrenoApp.test.js +194 -21
  95. package/dist/terrenoPlugin.d.ts +11 -0
  96. package/dist/tests/bunSetup.js +1 -0
  97. package/dist/tests.js +1 -1
  98. package/dist/transformers.d.ts +2 -2
  99. package/dist/transformers.js +5 -3
  100. package/dist/transformers.test.js +90 -0
  101. package/dist/types/consentResponse.d.ts +6 -3
  102. package/dist/versionCheckPlugin.d.ts +2 -0
  103. package/dist/versionCheckPlugin.js +18 -12
  104. package/package.json +4 -2
  105. package/src/__tests__/versionCheckPlugin.test.ts +37 -3
  106. package/src/api.arrayOperations.test.ts +1 -0
  107. package/src/api.asyncHandler.test.ts +177 -0
  108. package/src/api.errors.test.ts +1 -0
  109. package/src/api.hooks.test.ts +1 -0
  110. package/src/api.query.test.ts +1 -0
  111. package/src/api.test.ts +132 -0
  112. package/src/api.ts +199 -84
  113. package/src/auth.test.ts +160 -0
  114. package/src/auth.ts +120 -50
  115. package/src/betterAuthApp.test.ts +1 -0
  116. package/src/betterAuthSetup.test.ts +1 -0
  117. package/src/betterAuthSetup.ts +46 -19
  118. package/src/config.test.ts +255 -0
  119. package/src/config.ts +206 -0
  120. package/src/configuration.test.ts +1 -0
  121. package/src/configurationApp.ts +59 -24
  122. package/src/configurationPlugin.test.ts +1 -0
  123. package/src/consentApp.test.ts +1 -0
  124. package/src/envConfigurationPlugin.test.ts +143 -0
  125. package/src/envConfigurationPlugin.ts +100 -0
  126. package/src/errors.test.ts +19 -1
  127. package/src/errors.ts +94 -20
  128. package/src/example.ts +46 -21
  129. package/src/express.d.ts +18 -1
  130. package/src/expressServer.test.ts +50 -2
  131. package/src/expressServer.ts +80 -50
  132. package/src/githubAuth.test.ts +1 -0
  133. package/src/githubAuth.ts +59 -38
  134. package/src/index.ts +4 -0
  135. package/src/logger.ts +47 -17
  136. package/src/models/versionConfig.ts +13 -2
  137. package/src/notifiers/googleChatNotifier.test.ts +1 -0
  138. package/src/notifiers/googleChatNotifier.ts +7 -9
  139. package/src/notifiers/slackNotifier.test.ts +29 -3
  140. package/src/notifiers/slackNotifier.ts +9 -7
  141. package/src/notifiers/zoomNotifier.test.ts +1 -0
  142. package/src/notifiers/zoomNotifier.ts +8 -11
  143. package/src/openApi.test.ts +1 -0
  144. package/src/openApi.ts +4 -4
  145. package/src/openApiBuilder.test.ts +1 -0
  146. package/src/openApiBuilder.ts +14 -11
  147. package/src/openApiValidator.test.ts +59 -0
  148. package/src/openApiValidator.ts +3 -2
  149. package/src/permissions.middleware.test.ts +1 -0
  150. package/src/permissions.test.ts +1 -0
  151. package/src/permissions.ts +30 -25
  152. package/src/plugins.test.ts +1 -1
  153. package/src/plugins.ts +21 -14
  154. package/src/populate.test.ts +1 -0
  155. package/src/populate.ts +44 -36
  156. package/src/realtime/changeStreamWatcher.ts +568 -0
  157. package/src/realtime/index.ts +34 -0
  158. package/src/realtime/queryMatcher.ts +179 -0
  159. package/src/realtime/queryStore.ts +132 -0
  160. package/src/realtime/realtime.test.ts +1755 -0
  161. package/src/realtime/realtimeApp.ts +478 -0
  162. package/src/realtime/registry.ts +64 -0
  163. package/src/realtime/socketUser.ts +25 -0
  164. package/src/realtime/types.ts +112 -0
  165. package/src/requestContext.test.ts +196 -0
  166. package/src/requestContext.ts +368 -0
  167. package/src/terrenoApp.test.ts +137 -11
  168. package/src/terrenoApp.ts +64 -17
  169. package/src/terrenoPlugin.ts +12 -0
  170. package/src/tests/bunSetup.ts +1 -0
  171. package/src/tests.ts +7 -2
  172. package/src/transformers.test.ts +70 -2
  173. package/src/transformers.ts +15 -7
  174. package/src/types/consentResponse.ts +8 -10
  175. package/src/versionCheckPlugin.ts +15 -7
@@ -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 function setupEnvironment(): void;
8
+ export declare const setupEnvironment: () => void;
9
9
  export type AddRoutes = (router: Router, options?: Partial<ModelRouterOptions<unknown>>) => void;
10
- export declare function logRequests(req: any, res: any, next: any): void;
11
- export declare function createRouter(rootPath: string, addRoutes: AddRoutes, middleware?: any[]): any[];
12
- export declare function createRouterWithAuth(rootPath: string, addRoutes: (router: Router) => void, middleware?: any[]): any[];
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, any>;
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 function setupServer(options: SetupServerOptions): express.Application;
35
- export declare function cronjob(name: string, schedule: "hourly" | "minutely" | string, callback: () => void): void;
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?: any) => void | Promise<void>;
38
+ onFinish?: (result?: unknown) => void | Promise<void>;
38
39
  terminateTimeout?: number;
39
40
  slackChannel?: string;
40
41
  }
41
- export declare function wrapScript(func: () => Promise<any>, options?: WrapScriptOptions): Promise<void>;
42
+ export declare const wrapScript: (func: () => Promise<unknown>, options?: WrapScriptOptions) => Promise<void>;
@@ -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 = 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 setupEnvironment() {
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 && _a !== void 0 ? _a : {});
149
- var slowReadMs = (_b = options.logSlowRequestsReadMs) !== null && _b !== void 0 ? _b : SLOW_READ_MAX;
150
- var slowWriteMs = (_c = options.logSlowRequestsWriteMs) !== null && _c !== void 0 ? _c : SLOW_WRITE_MAX;
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
- function logRequests(req, res, next) {
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
- function createRouter(rootPath, addRoutes, middleware) {
211
+ };
212
+ exports.logRequests = logRequests;
213
+ var createRouter = function (rootPath, addRoutes, middleware) {
215
214
  if (middleware === void 0) { middleware = []; }
216
- function routePathMiddleware(req, _res, next) {
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
- function createRouterWithAuth(rootPath, addRoutes, middleware) {
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
- function initializeRoutes(UserModel, addRoutes, options) {
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 ((_a = req.user) === null || _a === void 0 ? void 0 : _a._id) {
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(function onError(err, _req, res, _next) {
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
- // Sets up the routes and returns the app.
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
- logger_1.logger.error("Error initializing routes: ".concat(error.stack));
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
- logger_1.logger.error("Error trying to start HTTP server: ".concat(error, "\n").concat(error.stack));
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
- // Convenience method to execute cronjobs with an always-running server.
343
- function cronjob(name, schedule, callback) {
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
- // Wrap up a script with some helpers, such as catching errors, reporting them to sentry, notifying
354
- // Slack of runs, etc. Also supports timeouts.
355
- function wrapScript(func_1) {
356
- return __awaiter(this, arguments, void 0, function (func, options) {
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(_this, void 0, void 0, function () {
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(_this, void 0, void 0, function () {
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");
@@ -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.
@@ -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: { index: true, sparse: true, type: String, unique: true },
65
- githubProfileUrl: { type: String },
66
- githubUsername: { type: String },
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", new passport_github2_1.Strategy({
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
- }, (function (req, accessToken, refreshToken, profile, done) { return __awaiter(void 0, void 0, void 0, function () {
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
- user.githubId = githubId;
117
- user.githubUsername = profile.username;
118
- user.githubProfileUrl = profile.profileUrl;
119
- user.githubAvatarUrl = (_b = (_a = profile.photos) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value;
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
- existingEmailUser.githubId = githubId;
138
- existingEmailUser.githubUsername = profile.username;
139
- existingEmailUser.githubProfileUrl = profile.profileUrl;
140
- existingEmailUser.githubAvatarUrl = (_f = (_e = profile.photos) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.value;
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
- req.session = req.session || {};
189
- req.session.returnTo = returnTo;
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 = (_b = req.user) === null || _b === void 0 ? void 0 : _b._id) === null || _c === void 0 ? void 0 : _c.toString()) || "");
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
- hasPassword = !!user.hash || !!user.salt;
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
- user.githubId = undefined;
276
- user.githubUsername = undefined;
277
- user.githubProfileUrl = undefined;
278
- user.githubAvatarUrl = undefined;
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();
@@ -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
@@ -20,4 +20,4 @@ export interface LoggingOptions {
20
20
  logSlowRequestsReadMs?: number;
21
21
  logSlowRequestsWriteMs?: number;
22
22
  }
23
- export declare function setupLogging(options?: LoggingOptions): void;
23
+ export declare const setupLogging: (options?: LoggingOptions) => void;