@terreno/api 0.18.0 → 0.19.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/api.test.js CHANGED
@@ -2545,14 +2545,20 @@ var transformers_1 = require("./transformers");
2545
2545
  });
2546
2546
  }); });
2547
2547
  (0, bun_test_1.it)("returns 409 when precise conflict timestamp is older than doc.updated", function () { return __awaiter(void 0, void 0, void 0, function () {
2548
+ var ifUnmodifiedSince;
2548
2549
  return __generator(this, function (_a) {
2549
2550
  switch (_a.label) {
2550
- case 0: return [4 /*yield*/, agent
2551
- .patch("/food/".concat(spinach._id))
2552
- .set("If-Unmodified-Since", luxon_1.DateTime.fromISO("2025-06-15T12:00:01.000Z").toHTTP())
2553
- .set("X-Unmodified-Since-ISO", "2025-06-15T11:59:59.500Z")
2554
- .send({ name: "Precise Stale" })
2555
- .expect(409)];
2551
+ case 0:
2552
+ ifUnmodifiedSince = luxon_1.DateTime.fromISO("2025-06-15T12:00:01.000Z").toHTTP();
2553
+ if (ifUnmodifiedSince === null) {
2554
+ throw new Error("expected HTTP If-Unmodified-Since value");
2555
+ }
2556
+ return [4 /*yield*/, agent
2557
+ .patch("/food/".concat(spinach._id))
2558
+ .set("If-Unmodified-Since", ifUnmodifiedSince)
2559
+ .set("X-Unmodified-Since-ISO", "2025-06-15T11:59:59.500Z")
2560
+ .send({ name: "Precise Stale" })
2561
+ .expect(409)];
2556
2562
  case 1:
2557
2563
  _a.sent();
2558
2564
  return [2 /*return*/];
@@ -2560,15 +2566,19 @@ var transformers_1 = require("./transformers");
2560
2566
  });
2561
2567
  }); });
2562
2568
  (0, bun_test_1.it)("falls back to doc.created when doc.updated is unavailable", function () { return __awaiter(void 0, void 0, void 0, function () {
2563
- var res;
2569
+ var ifUnmodifiedSince, res;
2564
2570
  return __generator(this, function (_a) {
2565
2571
  switch (_a.label) {
2566
2572
  case 0: return [4 /*yield*/, tests_1.FoodModel.collection.updateOne({ _id: spinach._id }, { $unset: { updated: "" } })];
2567
2573
  case 1:
2568
2574
  _a.sent();
2575
+ ifUnmodifiedSince = luxon_1.DateTime.fromISO("2025-06-15T11:59:59.999Z").toHTTP();
2576
+ if (ifUnmodifiedSince === null) {
2577
+ throw new Error("expected HTTP If-Unmodified-Since value");
2578
+ }
2569
2579
  return [4 /*yield*/, agent
2570
2580
  .patch("/food/".concat(spinach._id))
2571
- .set("If-Unmodified-Since", luxon_1.DateTime.fromISO("2025-06-15T11:59:59.999Z").toHTTP())
2581
+ .set("If-Unmodified-Since", ifUnmodifiedSince)
2572
2582
  .send({ name: "Created Fallback" })
2573
2583
  .expect(409)];
2574
2584
  case 2:
package/dist/auth.d.ts CHANGED
@@ -22,8 +22,8 @@ export interface UserModel extends Model<User> {
22
22
  export interface GenerateTokensOptions {
23
23
  sessionId?: string;
24
24
  }
25
- export declare function authenticateMiddleware(anonymous?: boolean): (req: express.Request, res: express.Response, next: express.NextFunction) => any;
26
- export declare function signupUser(userModel: UserModel, email: string, password: string, body?: Record<string, unknown>): Promise<any>;
25
+ export declare const authenticateMiddleware: (anonymous?: boolean) => (req: express.Request, res: express.Response, next: express.NextFunction) => any;
26
+ export declare const signupUser: (userModel: UserModel, email: string, password: string, body?: Record<string, unknown>) => Promise<any>;
27
27
  /**
28
28
  * Generates both an access token (JWT) and a refresh token for a given user.
29
29
  *
@@ -50,6 +50,6 @@ export declare const generateTokens: (user: unknown, authOptions?: AuthOptions,
50
50
  sessionId: string;
51
51
  token: string;
52
52
  }>;
53
- export declare function setupAuth(app: express.Application, userModel: UserModel): void;
54
- export declare function addAuthRoutes(app: express.Application, userModel: UserModel, authOptions?: AuthOptions): void;
55
- export declare function addMeRoutes(app: express.Application, userModel: UserModel, _authOptions?: AuthOptions): void;
53
+ export declare const setupAuth: (app: express.Application, userModel: UserModel) => void;
54
+ export declare const addAuthRoutes: (app: express.Application, userModel: UserModel, authOptions?: AuthOptions) => void;
55
+ export declare const addMeRoutes: (app: express.Application, userModel: UserModel, _authOptions?: AuthOptions) => void;
package/dist/auth.js CHANGED
@@ -86,12 +86,7 @@ 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
- exports.generateTokens = void 0;
90
- exports.authenticateMiddleware = authenticateMiddleware;
91
- exports.signupUser = signupUser;
92
- exports.setupAuth = setupAuth;
93
- exports.addAuthRoutes = addAuthRoutes;
94
- exports.addMeRoutes = addMeRoutes;
89
+ exports.addMeRoutes = exports.addAuthRoutes = exports.setupAuth = exports.generateTokens = exports.signupUser = exports.authenticateMiddleware = void 0;
95
90
  var node_crypto_1 = require("node:crypto");
96
91
  var express_1 = __importDefault(require("express"));
97
92
  var jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
@@ -103,7 +98,7 @@ var passport_local_1 = require("passport-local");
103
98
  var errors_1 = require("./errors");
104
99
  var logger_1 = require("./logger");
105
100
  var requestContext_1 = require("./requestContext");
106
- function authenticateMiddleware(anonymous) {
101
+ var authenticateMiddleware = function (anonymous) {
107
102
  if (anonymous === void 0) { anonymous = false; }
108
103
  var strategies = ["jwt"];
109
104
  if (anonymous) {
@@ -120,45 +115,45 @@ function authenticateMiddleware(anonymous) {
120
115
  }
121
116
  return passportAuth(req, res, next);
122
117
  };
123
- }
124
- function signupUser(userModel, email, password, body) {
125
- return __awaiter(this, void 0, void 0, function () {
126
- var _a, _email, _password, bodyRest, user, error_1, error_2, message;
127
- return __generator(this, function (_b) {
128
- switch (_b.label) {
129
- case 0:
130
- _a = body !== null && body !== void 0 ? body : {}, _email = _a.email, _password = _a.password, bodyRest = __rest(_a, ["email", "password"]);
131
- _b.label = 1;
132
- case 1:
133
- _b.trys.push([1, 8, , 9]);
134
- return [4 /*yield*/, userModel.register(__assign({ email: email }, bodyRest), password)];
135
- case 2:
136
- user = _b.sent();
137
- if (!user.postCreate) return [3 /*break*/, 6];
138
- _b.label = 3;
139
- case 3:
140
- _b.trys.push([3, 5, , 6]);
141
- return [4 /*yield*/, user.postCreate(bodyRest)];
142
- case 4:
143
- _b.sent();
144
- return [3 /*break*/, 6];
145
- case 5:
146
- error_1 = _b.sent();
147
- logger_1.logger.error("Error in user.postCreate: ".concat(error_1));
148
- throw error_1;
149
- case 6: return [4 /*yield*/, user.save()];
150
- case 7:
151
- _b.sent();
152
- return [2 /*return*/, user];
153
- case 8:
154
- error_2 = _b.sent();
155
- message = (0, errors_1.errorMessage)(error_2);
156
- throw new errors_1.APIError({ title: message });
157
- case 9: return [2 /*return*/];
158
- }
159
- });
118
+ };
119
+ exports.authenticateMiddleware = authenticateMiddleware;
120
+ var signupUser = function (userModel, email, password, body) { return __awaiter(void 0, void 0, void 0, function () {
121
+ var _a, _email, _password, bodyRest, user, error_1, error_2, message;
122
+ return __generator(this, function (_b) {
123
+ switch (_b.label) {
124
+ case 0:
125
+ _a = body !== null && body !== void 0 ? body : {}, _email = _a.email, _password = _a.password, bodyRest = __rest(_a, ["email", "password"]);
126
+ _b.label = 1;
127
+ case 1:
128
+ _b.trys.push([1, 8, , 9]);
129
+ return [4 /*yield*/, userModel.register(__assign({ email: email }, bodyRest), password)];
130
+ case 2:
131
+ user = _b.sent();
132
+ if (!user.postCreate) return [3 /*break*/, 6];
133
+ _b.label = 3;
134
+ case 3:
135
+ _b.trys.push([3, 5, , 6]);
136
+ return [4 /*yield*/, user.postCreate(bodyRest)];
137
+ case 4:
138
+ _b.sent();
139
+ return [3 /*break*/, 6];
140
+ case 5:
141
+ error_1 = _b.sent();
142
+ logger_1.logger.error("Error in user.postCreate: ".concat(error_1));
143
+ throw error_1;
144
+ case 6: return [4 /*yield*/, user.save()];
145
+ case 7:
146
+ _b.sent();
147
+ return [2 /*return*/, user];
148
+ case 8:
149
+ error_2 = _b.sent();
150
+ message = (0, errors_1.errorMessage)(error_2);
151
+ throw new errors_1.APIError({ title: message });
152
+ case 9: return [2 /*return*/];
153
+ }
160
154
  });
161
- }
155
+ }); };
156
+ exports.signupUser = signupUser;
162
157
  /**
163
158
  * Generates both an access token (JWT) and a refresh token for a given user.
164
159
  *
@@ -188,7 +183,7 @@ var generateTokens = function (user_1, authOptions_1) {
188
183
  return __generator(this, function (_b) {
189
184
  tokenSecretOrKey = process.env.TOKEN_SECRET;
190
185
  if (!tokenSecretOrKey) {
191
- throw new Error("TOKEN_SECRET must be set in env.");
186
+ throw new errors_1.APIError({ status: 500, title: "TOKEN_SECRET must be set in env." });
192
187
  }
193
188
  tokenUser = user;
194
189
  if (!(tokenUser === null || tokenUser === void 0 ? void 0 : tokenUser._id)) {
@@ -253,15 +248,14 @@ var generateTokens = function (user_1, authOptions_1) {
253
248
  };
254
249
  exports.generateTokens = generateTokens;
255
250
  // TODO allow customization
256
- function setupAuth(app, userModel) {
257
- var _this = this;
251
+ var setupAuth = function (app, userModel) {
258
252
  passport_1.default.use(new passport_anonymous_1.Strategy());
259
253
  passport_1.default.use(userModel.createStrategy());
260
254
  passport_1.default.use("signup", new passport_local_1.Strategy({
261
255
  passReqToCallback: true,
262
256
  passwordField: "password",
263
257
  usernameField: "email",
264
- }, function (req, email, password, done) { return __awaiter(_this, void 0, void 0, function () {
258
+ }, function (req, email, password, done) { return __awaiter(void 0, void 0, void 0, function () {
265
259
  var _a, _b, error_3;
266
260
  return __generator(this, function (_c) {
267
261
  switch (_c.label) {
@@ -269,7 +263,7 @@ function setupAuth(app, userModel) {
269
263
  _c.trys.push([0, 2, , 3]);
270
264
  _a = done;
271
265
  _b = [undefined];
272
- return [4 /*yield*/, signupUser(userModel, email, password, req.body)];
266
+ return [4 /*yield*/, (0, exports.signupUser)(userModel, email, password, req.body)];
273
267
  case 1:
274
268
  _a.apply(void 0, _b.concat([_c.sent()]));
275
269
  return [3 /*break*/, 3];
@@ -281,7 +275,7 @@ function setupAuth(app, userModel) {
281
275
  });
282
276
  }); }));
283
277
  if (!userModel.createStrategy) {
284
- throw new Error("setupAuth userModel must have .createStrategy()");
278
+ throw new errors_1.APIError({ status: 500, title: "setupAuth userModel must have .createStrategy()" });
285
279
  }
286
280
  var customTokenExtractor = function (req) {
287
281
  var _a, _b, _c;
@@ -300,14 +294,14 @@ function setupAuth(app, userModel) {
300
294
  }
301
295
  var secretOrKey = process.env.TOKEN_SECRET;
302
296
  if (!secretOrKey) {
303
- throw new Error("TOKEN_SECRET must be set in env.");
297
+ throw new errors_1.APIError({ status: 500, title: "TOKEN_SECRET must be set in env." });
304
298
  }
305
299
  var jwtOpts = {
306
300
  issuer: process.env.TOKEN_ISSUER,
307
301
  jwtFromRequest: customTokenExtractor,
308
302
  secretOrKey: secretOrKey,
309
303
  };
310
- passport_1.default.use("jwt", new passport_jwt_1.Strategy(jwtOpts, function (jwtPayload, done) { return __awaiter(_this, void 0, void 0, function () {
304
+ passport_1.default.use("jwt", new passport_jwt_1.Strategy(jwtOpts, function (jwtPayload, done) { return __awaiter(void 0, void 0, void 0, function () {
311
305
  var user, error_4;
312
306
  return __generator(this, function (_a) {
313
307
  switch (_a.label) {
@@ -346,82 +340,79 @@ function setupAuth(app, userModel) {
346
340
  }
347
341
  // Adds req.user to the request. This may wind up duplicating requests with passport,
348
342
  // but passport doesn't give us req.user early enough.
349
- function decodeJWTMiddleware(req, res, next) {
350
- return __awaiter(this, void 0, void 0, function () {
351
- var token, decoded, userText, expiredAt, message, details, sessionId, user, error_5;
352
- var _a, _b, _c, _d;
353
- return __generator(this, function (_e) {
354
- switch (_e.label) {
355
- case 0:
356
- if (!process.env.TOKEN_SECRET) {
357
- return [2 /*return*/, next()];
358
- }
359
- // Allow requests with a "Secret" prefix to pass through since this is a string value,
360
- // not a jwt that needs to be decoded
361
- if (((_b = (_a = req === null || req === void 0 ? void 0 : req.headers) === null || _a === void 0 ? void 0 : _a.authorization) === null || _b === void 0 ? void 0 : _b.split(" ")[0]) === "Secret") {
362
- return [2 /*return*/, next()];
363
- }
364
- token = customTokenExtractor(req);
365
- // For some reason, our app will happily put null into the authorization header when logging
366
- // out then back in.
367
- if (!token || token === "null" || token === "undefined") {
368
- return [2 /*return*/, next()];
369
- }
370
- try {
371
- decoded = jsonwebtoken_1.default.verify(token, process.env.TOKEN_SECRET, {
372
- issuer: process.env.TOKEN_ISSUER,
373
- });
374
- }
375
- catch (error) {
376
- userText = ((_c = req.user) === null || _c === void 0 ? void 0 : _c._id) ? " for user ".concat(req.user._id, " ") : "";
377
- expiredAt = error && typeof error === "object" && "expiredAt" in error
378
- ? error.expiredAt
379
- : undefined;
380
- message = (0, errors_1.errorMessage)(error);
381
- details = "[jwt] Error decoding token".concat(userText, ": ").concat(error, ", expired at ").concat(expiredAt, ", current time: ").concat(Date.now());
382
- logger_1.logger.debug(details);
383
- return [2 /*return*/, res.status(401).json({ details: details, message: message })];
384
- }
385
- if (!(decoded === null || decoded === void 0 ? void 0 : decoded.id)) return [3 /*break*/, 4];
386
- sessionId = (0, requestContext_1.getSessionIdFromJwtPayload)(decoded);
387
- req.authTokenPayload = decoded;
388
- if (sessionId) {
389
- req.sessionId = sessionId;
390
- (0, requestContext_1.setRequestContext)({ sessionId: sessionId });
391
- }
392
- _e.label = 1;
393
- case 1:
394
- _e.trys.push([1, 3, , 4]);
395
- return [4 /*yield*/, userModel.findById(decoded.id)];
396
- case 2:
397
- user = _e.sent();
398
- req.user = user;
399
- (0, requestContext_1.updateRequestContextFromRequest)(req, res);
400
- if ((_d = req.user) === null || _d === void 0 ? void 0 : _d.disabled) {
401
- logger_1.logger.warn("[jwt] User ".concat(req.user.id, " is disabled"));
402
- return [2 /*return*/, res.status(401).json({ status: 401, title: "User is disabled" })];
403
- }
404
- return [3 /*break*/, 4];
405
- case 3:
406
- error_5 = _e.sent();
407
- logger_1.logger.warn("[jwt] Error finding user from id: ".concat(error_5));
408
- return [3 /*break*/, 4];
409
- case 4: return [2 /*return*/, next()];
410
- }
411
- });
343
+ var decodeJWTMiddleware = function (req, res, next) { return __awaiter(void 0, void 0, void 0, function () {
344
+ var token, decoded, userText, expiredAt, message, details, sessionId, user, error_5;
345
+ var _a, _b, _c, _d;
346
+ return __generator(this, function (_e) {
347
+ switch (_e.label) {
348
+ case 0:
349
+ if (!process.env.TOKEN_SECRET) {
350
+ return [2 /*return*/, next()];
351
+ }
352
+ // Allow requests with a "Secret" prefix to pass through since this is a string value,
353
+ // not a jwt that needs to be decoded
354
+ if (((_b = (_a = req === null || req === void 0 ? void 0 : req.headers) === null || _a === void 0 ? void 0 : _a.authorization) === null || _b === void 0 ? void 0 : _b.split(" ")[0]) === "Secret") {
355
+ return [2 /*return*/, next()];
356
+ }
357
+ token = customTokenExtractor(req);
358
+ // For some reason, our app will happily put null into the authorization header when logging
359
+ // out then back in.
360
+ if (!token || token === "null" || token === "undefined") {
361
+ return [2 /*return*/, next()];
362
+ }
363
+ try {
364
+ decoded = jsonwebtoken_1.default.verify(token, process.env.TOKEN_SECRET, {
365
+ issuer: process.env.TOKEN_ISSUER,
366
+ });
367
+ }
368
+ catch (error) {
369
+ userText = ((_c = req.user) === null || _c === void 0 ? void 0 : _c._id) ? " for user ".concat(req.user._id, " ") : "";
370
+ expiredAt = error && typeof error === "object" && "expiredAt" in error
371
+ ? error.expiredAt
372
+ : undefined;
373
+ message = (0, errors_1.errorMessage)(error);
374
+ details = "[jwt] Error decoding token".concat(userText, ": ").concat(error, ", expired at ").concat(expiredAt, ", current time: ").concat(Date.now());
375
+ logger_1.logger.debug(details);
376
+ return [2 /*return*/, res.status(401).json({ details: details, message: message })];
377
+ }
378
+ if (!(decoded === null || decoded === void 0 ? void 0 : decoded.id)) return [3 /*break*/, 4];
379
+ sessionId = (0, requestContext_1.getSessionIdFromJwtPayload)(decoded);
380
+ req.authTokenPayload = decoded;
381
+ if (sessionId) {
382
+ req.sessionId = sessionId;
383
+ (0, requestContext_1.setRequestContext)({ sessionId: sessionId });
384
+ }
385
+ _e.label = 1;
386
+ case 1:
387
+ _e.trys.push([1, 3, , 4]);
388
+ return [4 /*yield*/, userModel.findById(decoded.id)];
389
+ case 2:
390
+ user = _e.sent();
391
+ req.user = user;
392
+ (0, requestContext_1.updateRequestContextFromRequest)(req, res);
393
+ if ((_d = req.user) === null || _d === void 0 ? void 0 : _d.disabled) {
394
+ logger_1.logger.warn("[jwt] User ".concat(req.user.id, " is disabled"));
395
+ return [2 /*return*/, res.status(401).json({ status: 401, title: "User is disabled" })];
396
+ }
397
+ return [3 /*break*/, 4];
398
+ case 3:
399
+ error_5 = _e.sent();
400
+ logger_1.logger.warn("[jwt] Error finding user from id: ".concat(error_5));
401
+ return [3 /*break*/, 4];
402
+ case 4: return [2 /*return*/, next()];
403
+ }
412
404
  });
413
- }
405
+ }); };
414
406
  app.use(decodeJWTMiddleware);
415
407
  // biome-ignore lint/suspicious/noExplicitAny: express 5 type for urlencoded doesn't match RequestHandler
416
408
  app.use(express_1.default.urlencoded({ extended: false }));
417
- }
418
- function addAuthRoutes(app, userModel, authOptions) {
419
- var _this = this;
409
+ };
410
+ exports.setupAuth = setupAuth;
411
+ var addAuthRoutes = function (app, userModel, authOptions) {
420
412
  var router = express_1.default.Router();
421
- router.post("/login", function (req, res, next) { return __awaiter(_this, void 0, void 0, function () {
422
- var _this = this;
413
+ router.post("/login", function (req, res, next) { return __awaiter(void 0, void 0, void 0, function () {
423
414
  return __generator(this, function (_a) {
424
- passport_1.default.authenticate("local", { session: false }, function (err, user, info) { return __awaiter(_this, void 0, void 0, function () {
415
+ passport_1.default.authenticate("local", { session: false }, function (err, user, info) { return __awaiter(void 0, void 0, void 0, function () {
425
416
  var tokens;
426
417
  return __generator(this, function (_a) {
427
418
  switch (_a.label) {
@@ -453,7 +444,7 @@ function addAuthRoutes(app, userModel, authOptions) {
453
444
  return [2 /*return*/];
454
445
  });
455
446
  }); });
456
- router.post("/refresh_token", function (req, res) { return __awaiter(_this, void 0, void 0, function () {
447
+ router.post("/refresh_token", function (req, res) { return __awaiter(void 0, void 0, void 0, function () {
457
448
  var refreshTokenSecretOrKey, decoded, message, user, sessionId, tokens;
458
449
  var _a, _b, _c, _d;
459
450
  return __generator(this, function (_e) {
@@ -503,7 +494,7 @@ function addAuthRoutes(app, userModel, authOptions) {
503
494
  }); });
504
495
  var signupDisabled = process.env.SIGNUP_DISABLED === "true";
505
496
  if (!signupDisabled) {
506
- router.post("/signup", passport_1.default.authenticate("signup", { failWithError: true, session: false }), function (req, res) { return __awaiter(_this, void 0, void 0, function () {
497
+ router.post("/signup", passport_1.default.authenticate("signup", { failWithError: true, session: false }), function (req, res) { return __awaiter(void 0, void 0, void 0, function () {
507
498
  var tokens;
508
499
  var _a, _b;
509
500
  return __generator(this, function (_c) {
@@ -527,11 +518,11 @@ function addAuthRoutes(app, userModel, authOptions) {
527
518
  }
528
519
  app.set("etag", false);
529
520
  app.use("/auth", router);
530
- }
531
- function addMeRoutes(app, userModel, _authOptions) {
532
- var _this = this;
521
+ };
522
+ exports.addAuthRoutes = addAuthRoutes;
523
+ var addMeRoutes = function (app, userModel, _authOptions) {
533
524
  var router = express_1.default.Router();
534
- router.get("/me", authenticateMiddleware(), function (req, res) { return __awaiter(_this, void 0, void 0, function () {
525
+ router.get("/me", (0, exports.authenticateMiddleware)(), function (req, res) { return __awaiter(void 0, void 0, void 0, function () {
535
526
  var data, dataObject;
536
527
  var _a;
537
528
  return __generator(this, function (_b) {
@@ -554,7 +545,7 @@ function addMeRoutes(app, userModel, _authOptions) {
554
545
  }
555
546
  });
556
547
  }); });
557
- router.patch("/me", authenticateMiddleware(), function (req, res) { return __awaiter(_this, void 0, void 0, function () {
548
+ router.patch("/me", (0, exports.authenticateMiddleware)(), function (req, res) { return __awaiter(void 0, void 0, void 0, function () {
558
549
  var doc, dataObject, error_6, message;
559
550
  var _a;
560
551
  return __generator(this, function (_b) {
@@ -590,4 +581,5 @@ function addMeRoutes(app, userModel, _authOptions) {
590
581
  app.set("etag", false);
591
582
  app.use("/auth", router);
592
583
  app.use(errors_1.apiErrorMiddleware);
593
- }
584
+ };
585
+ exports.addMeRoutes = addMeRoutes;
@@ -1039,7 +1039,6 @@ var tests_1 = require("./tests");
1039
1039
  case 1:
1040
1040
  express = _a.sent();
1041
1041
  originalListen = express.default.application.listen;
1042
- // biome-ignore lint/suspicious/noExplicitAny: mocking Express internals requires type escape
1043
1042
  express.default.application.listen = (0, bun_test_1.mock)(function () {
1044
1043
  var args = [];
1045
1044
  for (var _i = 0; _i < arguments.length; _i++) {
package/dist/openApi.d.ts CHANGED
@@ -53,9 +53,9 @@ export declare const defaultOpenApiErrorResponses: {
53
53
  description: string;
54
54
  };
55
55
  };
56
- export declare function getOpenApiMiddleware<T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>): express.RequestHandler;
57
- export declare function listOpenApiMiddleware<T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>): express.RequestHandler;
58
- export declare function createOpenApiMiddleware<T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>): express.RequestHandler;
59
- export declare function patchOpenApiMiddleware<T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>): express.RequestHandler;
60
- export declare function deleteOpenApiMiddleware<T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>): express.RequestHandler;
61
- export declare function readOpenApiMiddleware<T>(options: Partial<ModelRouterOptions<T>>, properties: Record<string, unknown>, required: string[], queryParameters: Array<Record<string, unknown>>): express.RequestHandler;
56
+ export declare const getOpenApiMiddleware: <T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>) => express.RequestHandler;
57
+ export declare const listOpenApiMiddleware: <T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>) => express.RequestHandler;
58
+ export declare const createOpenApiMiddleware: <T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>) => express.RequestHandler;
59
+ export declare const patchOpenApiMiddleware: <T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>) => express.RequestHandler;
60
+ export declare const deleteOpenApiMiddleware: <T>(model: Model<T>, options: Partial<ModelRouterOptions<T>>) => express.RequestHandler;
61
+ export declare const readOpenApiMiddleware: <T>(options: Partial<ModelRouterOptions<T>>, properties: Record<string, unknown>, required: string[], queryParameters: Array<Record<string, unknown>>) => express.RequestHandler;
package/dist/openApi.js CHANGED
@@ -39,13 +39,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
39
39
  return (mod && mod.__esModule) ? mod : { "default": mod };
40
40
  };
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
- exports.defaultOpenApiErrorResponses = exports.apiErrorContent = void 0;
43
- exports.getOpenApiMiddleware = getOpenApiMiddleware;
44
- exports.listOpenApiMiddleware = listOpenApiMiddleware;
45
- exports.createOpenApiMiddleware = createOpenApiMiddleware;
46
- exports.patchOpenApiMiddleware = patchOpenApiMiddleware;
47
- exports.deleteOpenApiMiddleware = deleteOpenApiMiddleware;
48
- exports.readOpenApiMiddleware = readOpenApiMiddleware;
42
+ exports.readOpenApiMiddleware = exports.deleteOpenApiMiddleware = exports.patchOpenApiMiddleware = exports.createOpenApiMiddleware = exports.listOpenApiMiddleware = exports.getOpenApiMiddleware = exports.defaultOpenApiErrorResponses = exports.apiErrorContent = void 0;
49
43
  var flatten_1 = __importDefault(require("lodash/flatten"));
50
44
  var merge_1 = __importDefault(require("lodash/merge"));
51
45
  var mongoose_to_swagger_1 = __importDefault(require("mongoose-to-swagger"));
@@ -83,7 +77,7 @@ exports.defaultOpenApiErrorResponses = {
83
77
  },
84
78
  };
85
79
  // We repeat this constantly, so we make it a component so we only have to define it once.
86
- function createAPIErrorComponent(openApi) {
80
+ var createAPIErrorComponent = function (openApi) {
87
81
  // Create a schema component called APIError
88
82
  openApi === null || openApi === void 0 ? void 0 : openApi.component("schemas", "APIError", {
89
83
  properties: {
@@ -144,8 +138,8 @@ function createAPIErrorComponent(openApi) {
144
138
  },
145
139
  type: "object",
146
140
  });
147
- }
148
- function getOpenApiMiddleware(model, options) {
141
+ };
142
+ var getOpenApiMiddleware = function (model, options) {
149
143
  var _c, _d, _e, _f, _g;
150
144
  createAPIErrorComponent(options.openApi);
151
145
  if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
@@ -175,8 +169,9 @@ function getOpenApiMiddleware(model, options) {
175
169
  } }, exports.defaultOpenApiErrorResponses),
176
170
  tags: [model.collection.collectionName],
177
171
  }, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.get) !== null && _g !== void 0 ? _g : {}));
178
- }
179
- function listOpenApiMiddleware(model, options) {
172
+ };
173
+ exports.getOpenApiMiddleware = getOpenApiMiddleware;
174
+ var listOpenApiMiddleware = function (model, options) {
180
175
  var _c, _d, _e, _f, _g, _h;
181
176
  if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
182
177
  return noop;
@@ -316,8 +311,9 @@ function listOpenApiMiddleware(model, options) {
316
311
  } }, exports.defaultOpenApiErrorResponses),
317
312
  tags: [model.collection.collectionName],
318
313
  }, (_h = (_g = options.openApiOverwrite) === null || _g === void 0 ? void 0 : _g.list) !== null && _h !== void 0 ? _h : {}));
319
- }
320
- function createOpenApiMiddleware(model, options) {
314
+ };
315
+ exports.listOpenApiMiddleware = listOpenApiMiddleware;
316
+ var createOpenApiMiddleware = function (model, options) {
321
317
  var _c, _d, _e, _f, _g;
322
318
  if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
323
319
  return noop;
@@ -355,8 +351,9 @@ function createOpenApiMiddleware(model, options) {
355
351
  } }, exports.defaultOpenApiErrorResponses),
356
352
  tags: [model.collection.collectionName],
357
353
  }, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.create) !== null && _g !== void 0 ? _g : {}));
358
- }
359
- function patchOpenApiMiddleware(model, options) {
354
+ };
355
+ exports.createOpenApiMiddleware = createOpenApiMiddleware;
356
+ var patchOpenApiMiddleware = function (model, options) {
360
357
  var _c, _d, _e, _f, _g;
361
358
  if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
362
359
  return noop;
@@ -394,8 +391,9 @@ function patchOpenApiMiddleware(model, options) {
394
391
  } }, exports.defaultOpenApiErrorResponses),
395
392
  tags: [model.collection.collectionName],
396
393
  }, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.update) !== null && _g !== void 0 ? _g : {}));
397
- }
398
- function deleteOpenApiMiddleware(model, options) {
394
+ };
395
+ exports.patchOpenApiMiddleware = patchOpenApiMiddleware;
396
+ var deleteOpenApiMiddleware = function (model, options) {
399
397
  var _c, _d, _e, _f, _g;
400
398
  if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
401
399
  return noop;
@@ -409,10 +407,11 @@ function deleteOpenApiMiddleware(model, options) {
409
407
  } }, exports.defaultOpenApiErrorResponses),
410
408
  tags: [model.collection.collectionName],
411
409
  }, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.delete) !== null && _g !== void 0 ? _g : {}));
412
- }
410
+ };
411
+ exports.deleteOpenApiMiddleware = deleteOpenApiMiddleware;
413
412
  // This is a generic OpenAPI wrapper for a read that returns any object described by `properties`.
414
413
  // Useful for endpoints that don't directly map to a model.
415
- function readOpenApiMiddleware(options, properties, required, queryParameters) {
414
+ var readOpenApiMiddleware = function (options, properties, required, queryParameters) {
416
415
  var _c, _d, _e, _f, _g;
417
416
  if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
418
417
  // Just log this once rather than for each middleware.
@@ -438,4 +437,5 @@ function readOpenApiMiddleware(options, properties, required, queryParameters) {
438
437
  } }, exports.defaultOpenApiErrorResponses),
439
438
  tags: [],
440
439
  }, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.get) !== null && _g !== void 0 ? _g : {}));
441
- }
440
+ };
441
+ exports.readOpenApiMiddleware = readOpenApiMiddleware;
@@ -328,6 +328,29 @@ var tests_1 = require("./tests");
328
328
  (0, bun_test_1.expect)(detail.properties.displayAmount.type).toBe("any");
329
329
  });
330
330
  });
331
+ (0, bun_test_1.describe)("getOpenApiSpecForModel populate with existing properties", function () {
332
+ (0, bun_test_1.it)("merges populated properties into a path that already has properties", function () {
333
+ var result = (0, populate_1.getOpenApiSpecForModel)(tests_1.FoodModel, {
334
+ populatePaths: [{ path: "likesIds.userId" }],
335
+ });
336
+ // likesIds is an array subschema with its own properties already;
337
+ // populating userId should merge the user properties into the existing structure.
338
+ (0, bun_test_1.expect)(result.properties.likesIds).toBeDefined();
339
+ var likesIds = result.properties.likesIds;
340
+ var items = likesIds.items;
341
+ (0, bun_test_1.expect)(items.properties.userId).toBeDefined();
342
+ });
343
+ (0, bun_test_1.it)("creates intermediate path structure when navigating to nested populate", function () {
344
+ // eatenBy is defined as [{ ref: "User", type: ObjectId }] - an array of refs.
345
+ // When we populate eatenBy, the openApiPath resolves through items.
346
+ var result = (0, populate_1.getOpenApiSpecForModel)(tests_1.FoodModel, {
347
+ populatePaths: [{ path: "eatenBy" }],
348
+ });
349
+ (0, bun_test_1.expect)(result.properties.eatenBy).toBeDefined();
350
+ var eatenBy = result.properties.eatenBy;
351
+ (0, bun_test_1.expect)(eatenBy.items).toBeDefined();
352
+ });
353
+ });
331
354
  (0, bun_test_1.describe)("filterKeys (via getOpenApiSpecForModel populatePaths)", function () {
332
355
  (0, bun_test_1.it)("filters populated fields using dot-notation keys", function () {
333
356
  var result = (0, populate_1.getOpenApiSpecForModel)(tests_1.FoodModel, {