@terreno/api 0.21.0 → 0.22.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/bunfig.toml +1 -1
- package/dist/auth.test.js +408 -33
- package/dist/models/consentForm.js +2 -1
- package/dist/models/consentResponse.js +2 -1
- package/dist/models/versionConfig.js +2 -1
- package/dist/openApiBuilder.d.ts +18 -0
- package/dist/openApiBuilder.js +21 -0
- package/dist/openApiBuilder.test.js +16 -0
- package/dist/permissions.test.js +10 -43
- package/dist/populate.test.js +10 -42
- package/dist/syncConsents.test.js +2 -2
- package/dist/tests/bunSetup.js +33 -283
- package/dist/tests/createTestData.d.ts +9 -0
- package/dist/tests/createTestData.js +272 -0
- package/dist/tests/models.d.ts +71 -0
- package/dist/tests/models.js +134 -0
- package/dist/tests/mongoTestSetup.d.ts +7 -0
- package/dist/tests/mongoTestSetup.js +150 -0
- package/dist/tests/testEnv.d.ts +0 -0
- package/dist/tests/testEnv.js +6 -0
- package/dist/tests/testHelper.d.ts +22 -0
- package/dist/tests/testHelper.js +115 -0
- package/dist/tests/types.d.ts +29 -0
- package/dist/tests/types.js +2 -0
- package/dist/tests.d.ts +10 -78
- package/dist/tests.js +24 -264
- package/dist/transformers.test.js +14 -50
- package/package.json +18 -4
- package/src/__snapshots__/openApiBuilder.test.ts.snap +1 -0
- package/src/auth.test.ts +277 -29
- package/src/models/consentForm.ts +3 -4
- package/src/models/consentResponse.ts +6 -4
- package/src/models/versionConfig.ts +3 -4
- package/src/openApiBuilder.test.ts +9 -0
- package/src/openApiBuilder.ts +24 -0
- package/src/permissions.test.ts +8 -23
- package/src/populate.test.ts +7 -22
- package/src/syncConsents.test.ts +1 -1
- package/src/tests/bunSetup.ts +22 -249
- package/src/tests/createTestData.ts +176 -0
- package/src/tests/models.ts +164 -0
- package/src/tests/mongoTestSetup.ts +69 -0
- package/src/tests/testEnv.ts +4 -0
- package/src/tests/testHelper.ts +57 -0
- package/src/tests/types.ts +35 -0
- package/src/tests.ts +40 -244
- package/src/transformers.test.ts +11 -30
- package/tsconfig.typedoc.json +4 -0
- package/dist/tests/index.d.ts +0 -1
- package/dist/tests/index.js +0 -17
- package/src/tests/index.ts +0 -1
package/bunfig.toml
CHANGED
package/dist/auth.test.js
CHANGED
|
@@ -118,7 +118,6 @@ var decodeTokenPayload = function (token) {
|
|
|
118
118
|
var app;
|
|
119
119
|
var admin;
|
|
120
120
|
var contextEvents;
|
|
121
|
-
var notAdmin;
|
|
122
121
|
var agent;
|
|
123
122
|
(0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
124
123
|
function addRoutes(router) {
|
|
@@ -202,40 +201,18 @@ var decodeTokenPayload = function (token) {
|
|
|
202
201
|
}); },
|
|
203
202
|
}));
|
|
204
203
|
}
|
|
205
|
-
var
|
|
206
|
-
return __generator(this, function (
|
|
207
|
-
switch (
|
|
204
|
+
var testData;
|
|
205
|
+
return __generator(this, function (_a) {
|
|
206
|
+
switch (_a.label) {
|
|
208
207
|
case 0:
|
|
209
208
|
// Reset to real time - don't freeze time here as passport-local-mongoose
|
|
210
209
|
// lockout mechanism needs real time to progress
|
|
211
210
|
(0, bun_test_1.setSystemTime)();
|
|
212
|
-
return [4 /*yield*/, (0, tests_1.
|
|
211
|
+
return [4 /*yield*/, (0, tests_1.setupTestData)()];
|
|
213
212
|
case 1:
|
|
214
|
-
|
|
213
|
+
testData = _a.sent();
|
|
214
|
+
admin = testData.users.admin;
|
|
215
215
|
contextEvents = [];
|
|
216
|
-
return [4 /*yield*/, Promise.all([
|
|
217
|
-
tests_1.FoodModel.create({
|
|
218
|
-
calories: 1,
|
|
219
|
-
created: new Date(),
|
|
220
|
-
name: "Spinach",
|
|
221
|
-
ownerId: notAdmin._id,
|
|
222
|
-
}),
|
|
223
|
-
tests_1.FoodModel.create({
|
|
224
|
-
calories: 100,
|
|
225
|
-
created: Date.now() - 10,
|
|
226
|
-
hidden: true,
|
|
227
|
-
name: "Apple",
|
|
228
|
-
ownerId: admin._id,
|
|
229
|
-
}),
|
|
230
|
-
tests_1.FoodModel.create({
|
|
231
|
-
calories: 100,
|
|
232
|
-
created: Date.now() - 10,
|
|
233
|
-
name: "Carrots",
|
|
234
|
-
ownerId: admin._id,
|
|
235
|
-
}),
|
|
236
|
-
])];
|
|
237
|
-
case 2:
|
|
238
|
-
_b.sent();
|
|
239
216
|
app = new terrenoApp_1.TerrenoApp({
|
|
240
217
|
configureApp: addRoutes,
|
|
241
218
|
skipListen: true,
|
|
@@ -315,7 +292,7 @@ var decodeTokenPayload = function (token) {
|
|
|
315
292
|
return [4 /*yield*/, agent.get("/food").expect(200)];
|
|
316
293
|
case 7:
|
|
317
294
|
getRes = _b.sent();
|
|
318
|
-
(0, bun_test_1.expect)(getRes.body.data).toHaveLength(
|
|
295
|
+
(0, bun_test_1.expect)(getRes.body.data).toHaveLength(4);
|
|
319
296
|
(0, bun_test_1.expect)(getRes.body.data.find(function (f) { return f.name === "Peas"; })).toBeDefined();
|
|
320
297
|
return [4 /*yield*/, agent
|
|
321
298
|
.patch("/food/".concat(food._id))
|
|
@@ -547,7 +524,7 @@ var decodeTokenPayload = function (token) {
|
|
|
547
524
|
return [4 /*yield*/, agent.get("/food").expect(200)];
|
|
548
525
|
case 5:
|
|
549
526
|
getRes = _b.sent();
|
|
550
|
-
(0, bun_test_1.expect)(getRes.body.data).toHaveLength(
|
|
527
|
+
(0, bun_test_1.expect)(getRes.body.data).toHaveLength(4);
|
|
551
528
|
food = getRes.body.data.find(function (f) { return f.name === "Apple"; });
|
|
552
529
|
(0, bun_test_1.expect)(food).toBeDefined();
|
|
553
530
|
return [4 /*yield*/, agent
|
|
@@ -1155,7 +1132,7 @@ var decodeTokenPayload = function (token) {
|
|
|
1155
1132
|
switch (_a.label) {
|
|
1156
1133
|
case 0:
|
|
1157
1134
|
(0, bun_test_1.setSystemTime)();
|
|
1158
|
-
return [4 /*yield*/, (0, tests_1.
|
|
1135
|
+
return [4 /*yield*/, (0, tests_1.setupTestData)()];
|
|
1159
1136
|
case 1:
|
|
1160
1137
|
_a.sent();
|
|
1161
1138
|
app = new terrenoApp_1.TerrenoApp({
|
|
@@ -1265,7 +1242,7 @@ var decodeTokenPayload = function (token) {
|
|
|
1265
1242
|
switch (_a.label) {
|
|
1266
1243
|
case 0:
|
|
1267
1244
|
(0, bun_test_1.setSystemTime)();
|
|
1268
|
-
return [4 /*yield*/, (0, tests_1.
|
|
1245
|
+
return [4 /*yield*/, (0, tests_1.setupTestData)()];
|
|
1269
1246
|
case 1:
|
|
1270
1247
|
_a.sent();
|
|
1271
1248
|
app = new terrenoApp_1.TerrenoApp({
|
|
@@ -1326,4 +1303,402 @@ var decodeTokenPayload = function (token) {
|
|
|
1326
1303
|
}
|
|
1327
1304
|
});
|
|
1328
1305
|
}); });
|
|
1306
|
+
(0, bun_test_1.it)("PATCH /auth/me returns 404 when user is deleted after auth", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1307
|
+
var _a, _admin, notAdmin, jwtLib, notAdminId, token, res;
|
|
1308
|
+
return __generator(this, function (_b) {
|
|
1309
|
+
switch (_b.label) {
|
|
1310
|
+
case 0: return [4 /*yield*/, (0, tests_1.setupDb)()];
|
|
1311
|
+
case 1:
|
|
1312
|
+
_a = __read.apply(void 0, [_b.sent(), 2]), _admin = _a[0], notAdmin = _a[1];
|
|
1313
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("jsonwebtoken")); })];
|
|
1314
|
+
case 2:
|
|
1315
|
+
jwtLib = (_b.sent()).default;
|
|
1316
|
+
notAdminId = notAdmin._id;
|
|
1317
|
+
token = jwtLib.sign({ id: notAdminId.toString() }, process.env.TOKEN_SECRET, {
|
|
1318
|
+
issuer: process.env.TOKEN_ISSUER,
|
|
1319
|
+
});
|
|
1320
|
+
return [4 /*yield*/, tests_1.UserModel.deleteOne({ _id: notAdminId })];
|
|
1321
|
+
case 3:
|
|
1322
|
+
_b.sent();
|
|
1323
|
+
return [4 /*yield*/, agent
|
|
1324
|
+
.patch("/auth/me")
|
|
1325
|
+
.set("authorization", "Bearer ".concat(token))
|
|
1326
|
+
.send({ email: "x@x.com" })];
|
|
1327
|
+
case 4:
|
|
1328
|
+
res = _b.sent();
|
|
1329
|
+
(0, bun_test_1.expect)([401, 404]).toContain(res.status);
|
|
1330
|
+
return [2 /*return*/];
|
|
1331
|
+
}
|
|
1332
|
+
});
|
|
1333
|
+
}); });
|
|
1334
|
+
(0, bun_test_1.it)("PATCH /auth/me returns 403 on validation error", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1335
|
+
var _a, admin, jwtLib, adminId, token, res;
|
|
1336
|
+
return __generator(this, function (_b) {
|
|
1337
|
+
switch (_b.label) {
|
|
1338
|
+
case 0: return [4 /*yield*/, (0, tests_1.setupDb)()];
|
|
1339
|
+
case 1:
|
|
1340
|
+
_a = __read.apply(void 0, [_b.sent(), 1]), admin = _a[0];
|
|
1341
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("jsonwebtoken")); })];
|
|
1342
|
+
case 2:
|
|
1343
|
+
jwtLib = (_b.sent()).default;
|
|
1344
|
+
adminId = admin._id;
|
|
1345
|
+
token = jwtLib.sign({ id: adminId.toString() }, process.env.TOKEN_SECRET, {
|
|
1346
|
+
issuer: process.env.TOKEN_ISSUER,
|
|
1347
|
+
});
|
|
1348
|
+
return [4 /*yield*/, agent
|
|
1349
|
+
.patch("/auth/me")
|
|
1350
|
+
.set("authorization", "Bearer ".concat(token))
|
|
1351
|
+
.send({ admin: "not_a_boolean_value_but_will_be_cast" })];
|
|
1352
|
+
case 3:
|
|
1353
|
+
res = _b.sent();
|
|
1354
|
+
(0, bun_test_1.expect)([200, 403]).toContain(res.status);
|
|
1355
|
+
return [2 /*return*/];
|
|
1356
|
+
}
|
|
1357
|
+
});
|
|
1358
|
+
}); });
|
|
1359
|
+
});
|
|
1360
|
+
(0, bun_test_1.describe)("Secret prefix authorization bypass", function () {
|
|
1361
|
+
var app;
|
|
1362
|
+
var agent;
|
|
1363
|
+
(0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1364
|
+
return __generator(this, function (_a) {
|
|
1365
|
+
switch (_a.label) {
|
|
1366
|
+
case 0:
|
|
1367
|
+
(0, bun_test_1.setSystemTime)();
|
|
1368
|
+
return [4 /*yield*/, (0, tests_1.setupTestData)()];
|
|
1369
|
+
case 1:
|
|
1370
|
+
_a.sent();
|
|
1371
|
+
app = new terrenoApp_1.TerrenoApp({
|
|
1372
|
+
configureApp: function (router) {
|
|
1373
|
+
router.use("/food", (0, api_1.modelRouter)(tests_1.FoodModel, {
|
|
1374
|
+
allowAnonymous: true,
|
|
1375
|
+
permissions: {
|
|
1376
|
+
create: [],
|
|
1377
|
+
delete: [],
|
|
1378
|
+
list: [permissions_1.Permissions.IsAny],
|
|
1379
|
+
read: [permissions_1.Permissions.IsAny],
|
|
1380
|
+
update: [],
|
|
1381
|
+
},
|
|
1382
|
+
}));
|
|
1383
|
+
},
|
|
1384
|
+
skipListen: true,
|
|
1385
|
+
userModel: tests_1.UserModel,
|
|
1386
|
+
}).build();
|
|
1387
|
+
agent = supertest_1.default.agent(app);
|
|
1388
|
+
return [2 /*return*/];
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
}); });
|
|
1392
|
+
(0, bun_test_1.afterEach)(function () {
|
|
1393
|
+
(0, bun_test_1.setSystemTime)();
|
|
1394
|
+
});
|
|
1395
|
+
(0, bun_test_1.it)("passes through with Secret prefix authorization header without JWT decoding", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1396
|
+
var res;
|
|
1397
|
+
return __generator(this, function (_a) {
|
|
1398
|
+
switch (_a.label) {
|
|
1399
|
+
case 0: return [4 /*yield*/, agent.get("/food").set("authorization", "Secret my-secret-token").expect(200)];
|
|
1400
|
+
case 1:
|
|
1401
|
+
res = _a.sent();
|
|
1402
|
+
(0, bun_test_1.expect)(res.body.data).toBeDefined();
|
|
1403
|
+
return [2 /*return*/];
|
|
1404
|
+
}
|
|
1405
|
+
});
|
|
1406
|
+
}); });
|
|
1407
|
+
});
|
|
1408
|
+
(0, bun_test_1.describe)("generateTokens env integration", function () {
|
|
1409
|
+
var OLD_ENV = process.env;
|
|
1410
|
+
(0, bun_test_1.beforeEach)(function () {
|
|
1411
|
+
process.env = __assign({}, OLD_ENV);
|
|
1412
|
+
process.env.TOKEN_SECRET = "secret";
|
|
1413
|
+
process.env.REFRESH_TOKEN_SECRET = "refresh_secret";
|
|
1414
|
+
});
|
|
1415
|
+
(0, bun_test_1.afterEach)(function () {
|
|
1416
|
+
process.env = OLD_ENV;
|
|
1417
|
+
});
|
|
1418
|
+
(0, bun_test_1.it)("includes TOKEN_ISSUER in token when set", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1419
|
+
var result, decoded;
|
|
1420
|
+
return __generator(this, function (_a) {
|
|
1421
|
+
switch (_a.label) {
|
|
1422
|
+
case 0:
|
|
1423
|
+
process.env.TOKEN_ISSUER = "test-issuer";
|
|
1424
|
+
return [4 /*yield*/, (0, auth_1.generateTokens)({ _id: "user-123" })];
|
|
1425
|
+
case 1:
|
|
1426
|
+
result = _a.sent();
|
|
1427
|
+
decoded = decodeTokenPayload(result.token);
|
|
1428
|
+
(0, bun_test_1.expect)(decoded.iss).toBe("test-issuer");
|
|
1429
|
+
return [2 /*return*/];
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1432
|
+
}); });
|
|
1433
|
+
(0, bun_test_1.it)("generates a unique sessionId when none provided", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1434
|
+
var result1, result2;
|
|
1435
|
+
return __generator(this, function (_a) {
|
|
1436
|
+
switch (_a.label) {
|
|
1437
|
+
case 0: return [4 /*yield*/, (0, auth_1.generateTokens)({ _id: "user-123" })];
|
|
1438
|
+
case 1:
|
|
1439
|
+
result1 = _a.sent();
|
|
1440
|
+
return [4 /*yield*/, (0, auth_1.generateTokens)({ _id: "user-123" })];
|
|
1441
|
+
case 2:
|
|
1442
|
+
result2 = _a.sent();
|
|
1443
|
+
(0, bun_test_1.expect)(result1.sessionId).toBeDefined();
|
|
1444
|
+
(0, bun_test_1.expect)(result2.sessionId).toBeDefined();
|
|
1445
|
+
(0, bun_test_1.expect)(result1.sessionId).not.toBe(result2.sessionId);
|
|
1446
|
+
return [2 /*return*/];
|
|
1447
|
+
}
|
|
1448
|
+
});
|
|
1449
|
+
}); });
|
|
1450
|
+
(0, bun_test_1.it)("uses provided sessionId from options", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1451
|
+
var result, decoded;
|
|
1452
|
+
return __generator(this, function (_a) {
|
|
1453
|
+
switch (_a.label) {
|
|
1454
|
+
case 0: return [4 /*yield*/, (0, auth_1.generateTokens)({ _id: "user-123" }, undefined, {
|
|
1455
|
+
sessionId: "custom-session-id",
|
|
1456
|
+
})];
|
|
1457
|
+
case 1:
|
|
1458
|
+
result = _a.sent();
|
|
1459
|
+
decoded = decodeTokenPayload(result.token);
|
|
1460
|
+
(0, bun_test_1.expect)(decoded.sid).toBe("custom-session-id");
|
|
1461
|
+
(0, bun_test_1.expect)(result.sessionId).toBe("custom-session-id");
|
|
1462
|
+
return [2 /*return*/];
|
|
1463
|
+
}
|
|
1464
|
+
});
|
|
1465
|
+
}); });
|
|
1466
|
+
});
|
|
1467
|
+
(0, bun_test_1.describe)("refresh_token without REFRESH_TOKEN_SECRET", function () {
|
|
1468
|
+
var app;
|
|
1469
|
+
var agent;
|
|
1470
|
+
var OLD_ENV = process.env;
|
|
1471
|
+
(0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1472
|
+
return __generator(this, function (_a) {
|
|
1473
|
+
switch (_a.label) {
|
|
1474
|
+
case 0:
|
|
1475
|
+
(0, bun_test_1.setSystemTime)();
|
|
1476
|
+
process.env = __assign({}, OLD_ENV);
|
|
1477
|
+
return [4 /*yield*/, (0, tests_1.setupTestData)()];
|
|
1478
|
+
case 1:
|
|
1479
|
+
_a.sent();
|
|
1480
|
+
app = new terrenoApp_1.TerrenoApp({
|
|
1481
|
+
configureApp: function () { },
|
|
1482
|
+
skipListen: true,
|
|
1483
|
+
userModel: tests_1.UserModel,
|
|
1484
|
+
}).build();
|
|
1485
|
+
agent = supertest_1.default.agent(app);
|
|
1486
|
+
return [2 /*return*/];
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1489
|
+
}); });
|
|
1490
|
+
(0, bun_test_1.afterEach)(function () {
|
|
1491
|
+
(0, bun_test_1.setSystemTime)();
|
|
1492
|
+
process.env = OLD_ENV;
|
|
1493
|
+
});
|
|
1494
|
+
(0, bun_test_1.it)("returns 401 when REFRESH_TOKEN_SECRET is not set", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1495
|
+
var res;
|
|
1496
|
+
return __generator(this, function (_a) {
|
|
1497
|
+
switch (_a.label) {
|
|
1498
|
+
case 0:
|
|
1499
|
+
process.env.REFRESH_TOKEN_SECRET = "";
|
|
1500
|
+
return [4 /*yield*/, agent
|
|
1501
|
+
.post("/auth/refresh_token")
|
|
1502
|
+
.send({ refreshToken: "some-token" })
|
|
1503
|
+
.expect(401)];
|
|
1504
|
+
case 1:
|
|
1505
|
+
res = _a.sent();
|
|
1506
|
+
(0, bun_test_1.expect)(res.body.message).toContain("No REFRESH_TOKEN_SECRET set");
|
|
1507
|
+
return [2 /*return*/];
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
}); });
|
|
1511
|
+
});
|
|
1512
|
+
(0, bun_test_1.describe)("generateTokens with custom TOKEN_EXPIRES_IN", function () {
|
|
1513
|
+
var OLD_ENV = process.env;
|
|
1514
|
+
(0, bun_test_1.beforeEach)(function () {
|
|
1515
|
+
process.env = __assign({}, OLD_ENV);
|
|
1516
|
+
process.env.TOKEN_SECRET = "secret";
|
|
1517
|
+
process.env.REFRESH_TOKEN_SECRET = "refresh_secret";
|
|
1518
|
+
});
|
|
1519
|
+
(0, bun_test_1.afterEach)(function () {
|
|
1520
|
+
process.env = OLD_ENV;
|
|
1521
|
+
});
|
|
1522
|
+
(0, bun_test_1.it)("uses TOKEN_EXPIRES_IN when set to a valid duration", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1523
|
+
var result, decoded, diffSeconds;
|
|
1524
|
+
return __generator(this, function (_a) {
|
|
1525
|
+
switch (_a.label) {
|
|
1526
|
+
case 0:
|
|
1527
|
+
process.env.TOKEN_EXPIRES_IN = "1h";
|
|
1528
|
+
return [4 /*yield*/, (0, auth_1.generateTokens)({ _id: "user-123" })];
|
|
1529
|
+
case 1:
|
|
1530
|
+
result = _a.sent();
|
|
1531
|
+
(0, bun_test_1.expect)(result.token).toBeDefined();
|
|
1532
|
+
decoded = decodeTokenPayload(result.token);
|
|
1533
|
+
diffSeconds = decoded.exp - decoded.iat;
|
|
1534
|
+
// 1h = 3600s
|
|
1535
|
+
(0, bun_test_1.expect)(diffSeconds).toBe(3600);
|
|
1536
|
+
return [2 /*return*/];
|
|
1537
|
+
}
|
|
1538
|
+
});
|
|
1539
|
+
}); });
|
|
1540
|
+
(0, bun_test_1.it)("uses REFRESH_TOKEN_EXPIRES_IN when set to a valid duration", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1541
|
+
var result, decoded, diffSeconds;
|
|
1542
|
+
return __generator(this, function (_a) {
|
|
1543
|
+
switch (_a.label) {
|
|
1544
|
+
case 0:
|
|
1545
|
+
process.env.REFRESH_TOKEN_EXPIRES_IN = "7d";
|
|
1546
|
+
return [4 /*yield*/, (0, auth_1.generateTokens)({ _id: "user-123" })];
|
|
1547
|
+
case 1:
|
|
1548
|
+
result = _a.sent();
|
|
1549
|
+
(0, bun_test_1.expect)(result.refreshToken).toBeDefined();
|
|
1550
|
+
decoded = decodeTokenPayload(result.refreshToken);
|
|
1551
|
+
diffSeconds = decoded.exp - decoded.iat;
|
|
1552
|
+
// 7d = 604800s
|
|
1553
|
+
(0, bun_test_1.expect)(diffSeconds).toBe(604800);
|
|
1554
|
+
return [2 /*return*/];
|
|
1555
|
+
}
|
|
1556
|
+
});
|
|
1557
|
+
}); });
|
|
1558
|
+
});
|
|
1559
|
+
(0, bun_test_1.describe)("JWT cookie extraction and /me routes edge cases", function () {
|
|
1560
|
+
var app;
|
|
1561
|
+
var agent;
|
|
1562
|
+
var OLD_ENV = process.env;
|
|
1563
|
+
(0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1564
|
+
return __generator(this, function (_a) {
|
|
1565
|
+
switch (_a.label) {
|
|
1566
|
+
case 0:
|
|
1567
|
+
(0, bun_test_1.setSystemTime)();
|
|
1568
|
+
process.env = __assign({}, OLD_ENV);
|
|
1569
|
+
return [4 /*yield*/, (0, tests_1.setupTestData)()];
|
|
1570
|
+
case 1:
|
|
1571
|
+
_a.sent();
|
|
1572
|
+
app = new terrenoApp_1.TerrenoApp({
|
|
1573
|
+
configureApp: function () { },
|
|
1574
|
+
skipListen: true,
|
|
1575
|
+
userModel: tests_1.UserModel,
|
|
1576
|
+
}).build();
|
|
1577
|
+
agent = supertest_1.default.agent(app);
|
|
1578
|
+
return [2 /*return*/];
|
|
1579
|
+
}
|
|
1580
|
+
});
|
|
1581
|
+
}); });
|
|
1582
|
+
(0, bun_test_1.afterEach)(function () {
|
|
1583
|
+
(0, bun_test_1.setSystemTime)();
|
|
1584
|
+
process.env = OLD_ENV;
|
|
1585
|
+
});
|
|
1586
|
+
(0, bun_test_1.it)("returns 401 for /me when no user is authenticated", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1587
|
+
var res;
|
|
1588
|
+
return __generator(this, function (_a) {
|
|
1589
|
+
switch (_a.label) {
|
|
1590
|
+
case 0: return [4 /*yield*/, agent.get("/auth/me").expect(401)];
|
|
1591
|
+
case 1:
|
|
1592
|
+
res = _a.sent();
|
|
1593
|
+
(0, bun_test_1.expect)(res.status).toBe(401);
|
|
1594
|
+
return [2 /*return*/];
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1597
|
+
}); });
|
|
1598
|
+
(0, bun_test_1.it)("returns 401 for PATCH /me when no user is authenticated", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1599
|
+
var res;
|
|
1600
|
+
return __generator(this, function (_a) {
|
|
1601
|
+
switch (_a.label) {
|
|
1602
|
+
case 0: return [4 /*yield*/, agent.patch("/auth/me").send({ name: "Updated" }).expect(401)];
|
|
1603
|
+
case 1:
|
|
1604
|
+
res = _a.sent();
|
|
1605
|
+
(0, bun_test_1.expect)(res.status).toBe(401);
|
|
1606
|
+
return [2 /*return*/];
|
|
1607
|
+
}
|
|
1608
|
+
});
|
|
1609
|
+
}); });
|
|
1610
|
+
(0, bun_test_1.it)("returns 404 for /me when user is deleted from database", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1611
|
+
var loginRes, _a, token, userId, freshAgent, res;
|
|
1612
|
+
return __generator(this, function (_b) {
|
|
1613
|
+
switch (_b.label) {
|
|
1614
|
+
case 0: return [4 /*yield*/, agent
|
|
1615
|
+
.post("/auth/login")
|
|
1616
|
+
.send({ email: "notAdmin@example.com", password: "password" })
|
|
1617
|
+
.expect(200)];
|
|
1618
|
+
case 1:
|
|
1619
|
+
loginRes = _b.sent();
|
|
1620
|
+
_a = loginRes.body.data, token = _a.token, userId = _a.userId;
|
|
1621
|
+
// Delete the user from DB
|
|
1622
|
+
return [4 /*yield*/, tests_1.UserModel.deleteOne({ _id: userId })];
|
|
1623
|
+
case 2:
|
|
1624
|
+
// Delete the user from DB
|
|
1625
|
+
_b.sent();
|
|
1626
|
+
freshAgent = supertest_1.default.agent(app);
|
|
1627
|
+
return [4 /*yield*/, freshAgent.get("/auth/me").set("authorization", "Bearer ".concat(token))];
|
|
1628
|
+
case 3:
|
|
1629
|
+
res = _b.sent();
|
|
1630
|
+
// Without the user, the JWT verify succeeds but findById returns null
|
|
1631
|
+
(0, bun_test_1.expect)([401, 404]).toContain(res.status);
|
|
1632
|
+
return [2 /*return*/];
|
|
1633
|
+
}
|
|
1634
|
+
});
|
|
1635
|
+
}); });
|
|
1636
|
+
});
|
|
1637
|
+
(0, bun_test_1.describe)("login error and disabled user paths", function () {
|
|
1638
|
+
var app;
|
|
1639
|
+
var agent;
|
|
1640
|
+
(0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1641
|
+
return __generator(this, function (_a) {
|
|
1642
|
+
switch (_a.label) {
|
|
1643
|
+
case 0:
|
|
1644
|
+
(0, bun_test_1.setSystemTime)();
|
|
1645
|
+
return [4 /*yield*/, (0, tests_1.setupTestData)()];
|
|
1646
|
+
case 1:
|
|
1647
|
+
_a.sent();
|
|
1648
|
+
app = new terrenoApp_1.TerrenoApp({
|
|
1649
|
+
configureApp: function () { },
|
|
1650
|
+
skipListen: true,
|
|
1651
|
+
userModel: tests_1.UserModel,
|
|
1652
|
+
}).build();
|
|
1653
|
+
agent = supertest_1.default.agent(app);
|
|
1654
|
+
return [2 /*return*/];
|
|
1655
|
+
}
|
|
1656
|
+
});
|
|
1657
|
+
}); });
|
|
1658
|
+
(0, bun_test_1.afterEach)(function () {
|
|
1659
|
+
(0, bun_test_1.setSystemTime)();
|
|
1660
|
+
});
|
|
1661
|
+
(0, bun_test_1.it)("returns 401 with message for invalid credentials (no user found)", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1662
|
+
var res;
|
|
1663
|
+
return __generator(this, function (_a) {
|
|
1664
|
+
switch (_a.label) {
|
|
1665
|
+
case 0: return [4 /*yield*/, agent
|
|
1666
|
+
.post("/auth/login")
|
|
1667
|
+
.send({ email: "nonexistent@example.com", password: "wrong" })
|
|
1668
|
+
.expect(401)];
|
|
1669
|
+
case 1:
|
|
1670
|
+
res = _a.sent();
|
|
1671
|
+
(0, bun_test_1.expect)(res.body.message).toBeDefined();
|
|
1672
|
+
return [2 /*return*/];
|
|
1673
|
+
}
|
|
1674
|
+
});
|
|
1675
|
+
}); });
|
|
1676
|
+
(0, bun_test_1.it)("returns 401 when disabled user tries to access protected route", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1677
|
+
var loginRes, _a, token, userId, freshAgent, res;
|
|
1678
|
+
return __generator(this, function (_b) {
|
|
1679
|
+
switch (_b.label) {
|
|
1680
|
+
case 0: return [4 /*yield*/, agent
|
|
1681
|
+
.post("/auth/login")
|
|
1682
|
+
.send({ email: "notAdmin@example.com", password: "password" })
|
|
1683
|
+
.expect(200)];
|
|
1684
|
+
case 1:
|
|
1685
|
+
loginRes = _b.sent();
|
|
1686
|
+
_a = loginRes.body.data, token = _a.token, userId = _a.userId;
|
|
1687
|
+
// Disable the user
|
|
1688
|
+
return [4 /*yield*/, tests_1.UserModel.findByIdAndUpdate(userId, { disabled: true })];
|
|
1689
|
+
case 2:
|
|
1690
|
+
// Disable the user
|
|
1691
|
+
_b.sent();
|
|
1692
|
+
freshAgent = supertest_1.default.agent(app);
|
|
1693
|
+
return [4 /*yield*/, freshAgent
|
|
1694
|
+
.get("/auth/me")
|
|
1695
|
+
.set("authorization", "Bearer ".concat(token))
|
|
1696
|
+
.expect(401)];
|
|
1697
|
+
case 3:
|
|
1698
|
+
res = _b.sent();
|
|
1699
|
+
(0, bun_test_1.expect)(res.body.title).toContain("disabled");
|
|
1700
|
+
return [2 /*return*/];
|
|
1701
|
+
}
|
|
1702
|
+
});
|
|
1703
|
+
}); });
|
|
1329
1704
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
|
+
var _a;
|
|
5
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
7
|
exports.ConsentForm = void 0;
|
|
7
8
|
var mongoose_1 = __importDefault(require("mongoose"));
|
|
@@ -120,4 +121,4 @@ consentFormSchema.plugin(plugins_1.createdUpdatedPlugin);
|
|
|
120
121
|
consentFormSchema.plugin(plugins_1.isDeletedPlugin);
|
|
121
122
|
consentFormSchema.plugin(plugins_1.findOneOrNone);
|
|
122
123
|
consentFormSchema.plugin(plugins_1.findExactlyOne);
|
|
123
|
-
exports.ConsentForm = mongoose_1.default.model("ConsentForm", consentFormSchema);
|
|
124
|
+
exports.ConsentForm = (_a = mongoose_1.default.models.ConsentForm) !== null && _a !== void 0 ? _a : mongoose_1.default.model("ConsentForm", consentFormSchema);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
|
+
var _a;
|
|
5
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
7
|
exports.ConsentResponse = void 0;
|
|
7
8
|
var mongoose_1 = __importDefault(require("mongoose"));
|
|
@@ -70,4 +71,4 @@ consentResponseSchema.plugin(plugins_1.createdUpdatedPlugin);
|
|
|
70
71
|
consentResponseSchema.plugin(plugins_1.isDeletedPlugin);
|
|
71
72
|
consentResponseSchema.plugin(plugins_1.findOneOrNone);
|
|
72
73
|
consentResponseSchema.plugin(plugins_1.findExactlyOne);
|
|
73
|
-
exports.ConsentResponse = mongoose_1.default.model("ConsentResponse", consentResponseSchema);
|
|
74
|
+
exports.ConsentResponse = (_a = mongoose_1.default.models.ConsentResponse) !== null && _a !== void 0 ? _a : mongoose_1.default.model("ConsentResponse", consentResponseSchema);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
|
+
var _a;
|
|
5
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
7
|
exports.VersionConfig = void 0;
|
|
7
8
|
var mongoose_1 = __importDefault(require("mongoose"));
|
|
@@ -71,4 +72,4 @@ versionConfigSchema.plugin(plugins_1.createdUpdatedPlugin);
|
|
|
71
72
|
versionConfigSchema.plugin(plugins_1.isDeletedPlugin);
|
|
72
73
|
versionConfigSchema.plugin(plugins_1.findOneOrNone);
|
|
73
74
|
versionConfigSchema.plugin(plugins_1.findExactlyOne);
|
|
74
|
-
exports.VersionConfig = mongoose_1.default.model("VersionConfig", versionConfigSchema);
|
|
75
|
+
exports.VersionConfig = (_a = mongoose_1.default.models.VersionConfig) !== null && _a !== void 0 ? _a : mongoose_1.default.model("VersionConfig", versionConfigSchema);
|
package/dist/openApiBuilder.d.ts
CHANGED
|
@@ -272,6 +272,24 @@ export declare class OpenApiMiddlewareBuilder {
|
|
|
272
272
|
* ```
|
|
273
273
|
*/
|
|
274
274
|
withSummary(summary: string): this;
|
|
275
|
+
/**
|
|
276
|
+
* Sets an explicit `operationId` for the OpenAPI operation.
|
|
277
|
+
*
|
|
278
|
+
* The `operationId` is a unique string used to identify an operation. Client and SDK
|
|
279
|
+
* generators (e.g. RTK Query codegen) derive generated function and hook names from it,
|
|
280
|
+
* so setting it keeps generated names stable and readable for routes whose URL path would
|
|
281
|
+
* otherwise produce unwieldy names (e.g. deeply nested routes). It must be unique across
|
|
282
|
+
* the whole OpenAPI document.
|
|
283
|
+
*
|
|
284
|
+
* @param operationId - Unique operation identifier (e.g. "getUserStats")
|
|
285
|
+
* @returns The builder instance for chaining
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```typescript
|
|
289
|
+
* builder.withOperationId("getUserStats");
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
withOperationId(operationId: string): this;
|
|
275
293
|
/**
|
|
276
294
|
* Sets the description for the OpenAPI operation.
|
|
277
295
|
*
|
package/dist/openApiBuilder.js
CHANGED
|
@@ -121,6 +121,27 @@ var OpenApiMiddlewareBuilder = /** @class */ (function () {
|
|
|
121
121
|
this.config.summary = summary;
|
|
122
122
|
return this;
|
|
123
123
|
};
|
|
124
|
+
/**
|
|
125
|
+
* Sets an explicit `operationId` for the OpenAPI operation.
|
|
126
|
+
*
|
|
127
|
+
* The `operationId` is a unique string used to identify an operation. Client and SDK
|
|
128
|
+
* generators (e.g. RTK Query codegen) derive generated function and hook names from it,
|
|
129
|
+
* so setting it keeps generated names stable and readable for routes whose URL path would
|
|
130
|
+
* otherwise produce unwieldy names (e.g. deeply nested routes). It must be unique across
|
|
131
|
+
* the whole OpenAPI document.
|
|
132
|
+
*
|
|
133
|
+
* @param operationId - Unique operation identifier (e.g. "getUserStats")
|
|
134
|
+
* @returns The builder instance for chaining
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* builder.withOperationId("getUserStats");
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
OpenApiMiddlewareBuilder.prototype.withOperationId = function (operationId) {
|
|
142
|
+
this.config.operationId = operationId;
|
|
143
|
+
return this;
|
|
144
|
+
};
|
|
124
145
|
/**
|
|
125
146
|
* Sets the description for the OpenAPI operation.
|
|
126
147
|
*
|
|
@@ -64,6 +64,7 @@ function addRoutesWithBuilder(router, options) {
|
|
|
64
64
|
var statsMiddleware = (0, openApiBuilder_1.createOpenApiBuilder)(options !== null && options !== void 0 ? options : {})
|
|
65
65
|
.withTags(["Stats"])
|
|
66
66
|
.withSummary("Get food statistics")
|
|
67
|
+
.withOperationId("getFoodStats")
|
|
67
68
|
.withDescription("Returns aggregated statistics about food items")
|
|
68
69
|
.withQueryParameter("category", { type: "string" }, {
|
|
69
70
|
description: "Filter by food category",
|
|
@@ -220,6 +221,21 @@ function addRoutesWithBuilder(router, options) {
|
|
|
220
221
|
}
|
|
221
222
|
});
|
|
222
223
|
}); });
|
|
224
|
+
(0, bun_test_1.it)("includes the explicit operationId in OpenAPI spec", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
225
|
+
var res, statsPath;
|
|
226
|
+
return __generator(this, function (_a) {
|
|
227
|
+
switch (_a.label) {
|
|
228
|
+
case 0:
|
|
229
|
+
server = (0, supertest_1.default)(app);
|
|
230
|
+
return [4 /*yield*/, server.get("/openapi.json").expect(200)];
|
|
231
|
+
case 1:
|
|
232
|
+
res = _a.sent();
|
|
233
|
+
statsPath = res.body.paths["/food/stats"];
|
|
234
|
+
(0, bun_test_1.expect)(statsPath.get.operationId).toBe("getFoodStats");
|
|
235
|
+
return [2 /*return*/];
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}); });
|
|
223
239
|
(0, bun_test_1.it)("includes request body schema in OpenAPI spec", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
224
240
|
var res, reportsPath, requestBody, schema;
|
|
225
241
|
return __generator(this, function (_a) {
|