@terreno/api 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +170 -0
  3. package/biome.jsonc +22 -0
  4. package/bunfig.toml +4 -0
  5. package/dist/api.d.ts +227 -0
  6. package/dist/api.js +1024 -0
  7. package/dist/api.test.d.ts +1 -0
  8. package/dist/api.test.js +2143 -0
  9. package/dist/auth.d.ts +50 -0
  10. package/dist/auth.js +512 -0
  11. package/dist/auth.test.d.ts +1 -0
  12. package/dist/auth.test.js +778 -0
  13. package/dist/errors.d.ts +75 -0
  14. package/dist/errors.js +216 -0
  15. package/dist/example.d.ts +1 -0
  16. package/dist/example.js +118 -0
  17. package/dist/expressServer.d.ts +35 -0
  18. package/dist/expressServer.js +436 -0
  19. package/dist/index.d.ts +14 -0
  20. package/dist/index.js +30 -0
  21. package/dist/logger.d.ts +23 -0
  22. package/dist/logger.js +249 -0
  23. package/dist/middleware.d.ts +10 -0
  24. package/dist/middleware.js +52 -0
  25. package/dist/notifiers/googleChatNotifier.d.ts +5 -0
  26. package/dist/notifiers/googleChatNotifier.js +130 -0
  27. package/dist/notifiers/googleChatNotifier.test.d.ts +1 -0
  28. package/dist/notifiers/googleChatNotifier.test.js +260 -0
  29. package/dist/notifiers/index.d.ts +3 -0
  30. package/dist/notifiers/index.js +19 -0
  31. package/dist/notifiers/slackNotifier.d.ts +5 -0
  32. package/dist/notifiers/slackNotifier.js +130 -0
  33. package/dist/notifiers/slackNotifier.test.d.ts +1 -0
  34. package/dist/notifiers/slackNotifier.test.js +259 -0
  35. package/dist/notifiers/zoomNotifier.d.ts +34 -0
  36. package/dist/notifiers/zoomNotifier.js +181 -0
  37. package/dist/notifiers/zoomNotifier.test.d.ts +1 -0
  38. package/dist/notifiers/zoomNotifier.test.js +370 -0
  39. package/dist/openApi.d.ts +60 -0
  40. package/dist/openApi.js +441 -0
  41. package/dist/openApi.test.d.ts +1 -0
  42. package/dist/openApi.test.js +445 -0
  43. package/dist/openApiBuilder.d.ts +419 -0
  44. package/dist/openApiBuilder.js +424 -0
  45. package/dist/openApiBuilder.test.d.ts +1 -0
  46. package/dist/openApiBuilder.test.js +509 -0
  47. package/dist/openApiEtag.d.ts +7 -0
  48. package/dist/openApiEtag.js +38 -0
  49. package/dist/permissions.d.ts +26 -0
  50. package/dist/permissions.js +331 -0
  51. package/dist/permissions.test.d.ts +1 -0
  52. package/dist/permissions.test.js +413 -0
  53. package/dist/plugins.d.ts +67 -0
  54. package/dist/plugins.js +315 -0
  55. package/dist/plugins.test.d.ts +1 -0
  56. package/dist/plugins.test.js +639 -0
  57. package/dist/populate.d.ts +14 -0
  58. package/dist/populate.js +315 -0
  59. package/dist/populate.test.d.ts +1 -0
  60. package/dist/populate.test.js +133 -0
  61. package/dist/response.d.ts +0 -0
  62. package/dist/response.js +1 -0
  63. package/dist/tests/bunSetup.d.ts +1 -0
  64. package/dist/tests/bunSetup.js +297 -0
  65. package/dist/tests/index.d.ts +1 -0
  66. package/dist/tests/index.js +17 -0
  67. package/dist/tests.d.ts +99 -0
  68. package/dist/tests.js +273 -0
  69. package/dist/transformers.d.ts +25 -0
  70. package/dist/transformers.js +217 -0
  71. package/dist/transformers.test.d.ts +1 -0
  72. package/dist/transformers.test.js +370 -0
  73. package/dist/utils.d.ts +11 -0
  74. package/dist/utils.js +143 -0
  75. package/dist/utils.test.d.ts +1 -0
  76. package/dist/utils.test.js +14 -0
  77. package/index.ts +1 -0
  78. package/package.json +88 -0
  79. package/src/__snapshots__/openApi.test.ts.snap +4814 -0
  80. package/src/__snapshots__/openApiBuilder.test.ts.snap +1485 -0
  81. package/src/api.test.ts +1661 -0
  82. package/src/api.ts +1036 -0
  83. package/src/auth.test.ts +550 -0
  84. package/src/auth.ts +408 -0
  85. package/src/errors.ts +225 -0
  86. package/src/example.ts +99 -0
  87. package/src/express.d.ts +5 -0
  88. package/src/expressServer.ts +387 -0
  89. package/src/index.ts +14 -0
  90. package/src/logger.ts +190 -0
  91. package/src/middleware.ts +18 -0
  92. package/src/notifiers/googleChatNotifier.test.ts +114 -0
  93. package/src/notifiers/googleChatNotifier.ts +47 -0
  94. package/src/notifiers/index.ts +3 -0
  95. package/src/notifiers/slackNotifier.test.ts +113 -0
  96. package/src/notifiers/slackNotifier.ts +55 -0
  97. package/src/notifiers/zoomNotifier.test.ts +207 -0
  98. package/src/notifiers/zoomNotifier.ts +111 -0
  99. package/src/openApi.test.ts +331 -0
  100. package/src/openApi.ts +494 -0
  101. package/src/openApiBuilder.test.ts +442 -0
  102. package/src/openApiBuilder.ts +636 -0
  103. package/src/openApiEtag.ts +40 -0
  104. package/src/permissions.test.ts +219 -0
  105. package/src/permissions.ts +228 -0
  106. package/src/plugins.test.ts +390 -0
  107. package/src/plugins.ts +289 -0
  108. package/src/populate.test.ts +65 -0
  109. package/src/populate.ts +258 -0
  110. package/src/response.ts +0 -0
  111. package/src/tests/bunSetup.ts +234 -0
  112. package/src/tests/index.ts +1 -0
  113. package/src/tests.ts +218 -0
  114. package/src/transformers.test.ts +202 -0
  115. package/src/transformers.ts +170 -0
  116. package/src/utils.test.ts +14 -0
  117. package/src/utils.ts +47 -0
  118. package/tsconfig.json +60 -0
  119. package/types.d.ts +17 -0
@@ -0,0 +1,778 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __read = (this && this.__read) || function (o, n) {
50
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
51
+ if (!m) return o;
52
+ var i = m.call(o), r, ar = [], e;
53
+ try {
54
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
55
+ }
56
+ catch (error) { e = { error: error }; }
57
+ finally {
58
+ try {
59
+ if (r && !r.done && (m = i["return"])) m.call(i);
60
+ }
61
+ finally { if (e) throw e.error; }
62
+ }
63
+ return ar;
64
+ };
65
+ var __importDefault = (this && this.__importDefault) || function (mod) {
66
+ return (mod && mod.__esModule) ? mod : { "default": mod };
67
+ };
68
+ Object.defineProperty(exports, "__esModule", { value: true });
69
+ var bun_test_1 = require("bun:test");
70
+ var supertest_1 = __importDefault(require("supertest"));
71
+ var api_1 = require("./api");
72
+ var auth_1 = require("./auth");
73
+ var expressServer_1 = require("./expressServer");
74
+ var permissions_1 = require("./permissions");
75
+ var tests_1 = require("./tests");
76
+ var transformers_1 = require("./transformers");
77
+ var utils_1 = require("./utils");
78
+ (0, bun_test_1.describe)("auth tests", function () {
79
+ var app;
80
+ var admin;
81
+ var notAdmin;
82
+ var agent;
83
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
84
+ function addRoutes(router) {
85
+ router.use("/food", (0, api_1.modelRouter)(tests_1.FoodModel, {
86
+ allowAnonymous: true,
87
+ permissions: {
88
+ create: [permissions_1.Permissions.IsAuthenticated],
89
+ delete: [permissions_1.Permissions.IsAuthenticated],
90
+ list: [permissions_1.Permissions.IsAny],
91
+ read: [permissions_1.Permissions.IsAny],
92
+ update: [permissions_1.Permissions.IsAuthenticated],
93
+ },
94
+ queryFilter: function (user) {
95
+ if (!(user === null || user === void 0 ? void 0 : user.admin)) {
96
+ return { hidden: { $ne: true } };
97
+ }
98
+ return {};
99
+ },
100
+ transformer: (0, transformers_1.AdminOwnerTransformer)({
101
+ adminReadFields: ["name", "calories", "created", "ownerId"],
102
+ adminWriteFields: ["name", "calories", "created", "ownerId"],
103
+ anonReadFields: ["name"],
104
+ anonWriteFields: [],
105
+ authReadFields: ["name", "calories", "created"],
106
+ authWriteFields: ["name", "calories"],
107
+ ownerReadFields: ["name", "calories", "created", "ownerId"],
108
+ ownerWriteFields: ["name", "calories", "created"],
109
+ }),
110
+ }));
111
+ }
112
+ var _a;
113
+ return __generator(this, function (_b) {
114
+ switch (_b.label) {
115
+ case 0:
116
+ // Reset to real time - don't freeze time here as passport-local-mongoose
117
+ // lockout mechanism needs real time to progress
118
+ (0, bun_test_1.setSystemTime)();
119
+ return [4 /*yield*/, (0, tests_1.setupDb)()];
120
+ case 1:
121
+ _a = __read.apply(void 0, [_b.sent(), 2]), admin = _a[0], notAdmin = _a[1];
122
+ return [4 /*yield*/, Promise.all([
123
+ tests_1.FoodModel.create({
124
+ calories: 1,
125
+ created: new Date(),
126
+ name: "Spinach",
127
+ ownerId: notAdmin._id,
128
+ }),
129
+ tests_1.FoodModel.create({
130
+ calories: 100,
131
+ created: Date.now() - 10,
132
+ hidden: true,
133
+ name: "Apple",
134
+ ownerId: admin._id,
135
+ }),
136
+ tests_1.FoodModel.create({
137
+ calories: 100,
138
+ created: Date.now() - 10,
139
+ name: "Carrots",
140
+ ownerId: admin._id,
141
+ }),
142
+ ])];
143
+ case 2:
144
+ _b.sent();
145
+ app = (0, expressServer_1.setupServer)({
146
+ addRoutes: addRoutes,
147
+ skipListen: true,
148
+ userModel: tests_1.UserModel,
149
+ });
150
+ agent = supertest_1.default.agent(app);
151
+ return [2 /*return*/];
152
+ }
153
+ });
154
+ }); });
155
+ (0, bun_test_1.afterEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
156
+ return __generator(this, function (_a) {
157
+ (0, bun_test_1.setSystemTime)();
158
+ return [2 /*return*/];
159
+ });
160
+ }); });
161
+ (0, bun_test_1.it)("completes token signup e2e", function () { return __awaiter(void 0, void 0, void 0, function () {
162
+ var res, _a, userId, token, refreshToken, food, meRes, mePatchRes, getRes, updateRes;
163
+ return __generator(this, function (_b) {
164
+ switch (_b.label) {
165
+ case 0: return [4 /*yield*/, agent
166
+ .post("/auth/signup")
167
+ .send({ email: "new@example.com", password: "123" })
168
+ .expect(200)];
169
+ case 1:
170
+ res = _b.sent();
171
+ _a = res.body.data, userId = _a.userId, token = _a.token, refreshToken = _a.refreshToken;
172
+ (0, bun_test_1.expect)(userId).toBeDefined();
173
+ (0, bun_test_1.expect)(token).toBeDefined();
174
+ (0, bun_test_1.expect)(refreshToken).toBeDefined();
175
+ return [4 /*yield*/, agent
176
+ .post("/auth/login")
177
+ .send({ email: "new@example.com", password: "123" })
178
+ .expect(200)];
179
+ case 2:
180
+ res = _b.sent();
181
+ return [4 /*yield*/, agent.set("authorization", "Bearer ".concat(res.body.data.token))];
182
+ case 3:
183
+ _b.sent();
184
+ userId = res.body.data.userId;
185
+ token = res.body.data.token;
186
+ (0, bun_test_1.expect)(userId).toBeDefined();
187
+ (0, bun_test_1.expect)(token).toBeDefined();
188
+ (0, bun_test_1.expect)(refreshToken).toBeDefined();
189
+ return [4 /*yield*/, tests_1.FoodModel.create({
190
+ calories: 1,
191
+ created: new Date(),
192
+ name: "Peas",
193
+ ownerId: userId,
194
+ })];
195
+ case 4:
196
+ food = _b.sent();
197
+ return [4 /*yield*/, agent.get("/auth/me").expect(200)];
198
+ case 5:
199
+ meRes = _b.sent();
200
+ (0, bun_test_1.expect)(meRes.body.data._id).toBeDefined();
201
+ (0, bun_test_1.expect)(meRes.body.data.id).toBeDefined();
202
+ (0, bun_test_1.expect)(meRes.body.data.hash).toBeUndefined();
203
+ (0, bun_test_1.expect)(meRes.body.data.email).toBe("new@example.com");
204
+ (0, bun_test_1.expect)(meRes.body.data.updated).toBeDefined();
205
+ (0, bun_test_1.expect)(meRes.body.data.created).toBeDefined();
206
+ (0, bun_test_1.expect)(meRes.body.data.admin).toBe(false);
207
+ return [4 /*yield*/, agent
208
+ .patch("/auth/me")
209
+ .send({ email: "new2@example.com" })
210
+ .set("authorization", "Bearer ".concat(token))
211
+ .expect(200)];
212
+ case 6:
213
+ mePatchRes = _b.sent();
214
+ (0, bun_test_1.expect)(mePatchRes.body.data._id).toBeDefined();
215
+ (0, bun_test_1.expect)(mePatchRes.body.data.id).toBeDefined();
216
+ (0, bun_test_1.expect)(mePatchRes.body.data.hash).toBeUndefined();
217
+ (0, bun_test_1.expect)(mePatchRes.body.data.email).toBe("new2@example.com");
218
+ (0, bun_test_1.expect)(mePatchRes.body.data.updated).toBeDefined();
219
+ (0, bun_test_1.expect)(mePatchRes.body.data.created).toBeDefined();
220
+ (0, bun_test_1.expect)(mePatchRes.body.data.admin).toBe(false);
221
+ return [4 /*yield*/, agent.get("/food").expect(200)];
222
+ case 7:
223
+ getRes = _b.sent();
224
+ (0, bun_test_1.expect)(getRes.body.data).toHaveLength(3);
225
+ (0, bun_test_1.expect)(getRes.body.data.find(function (f) { return f.name === "Peas"; })).toBeDefined();
226
+ return [4 /*yield*/, agent
227
+ .patch("/food/".concat(food._id))
228
+ .send({ name: "PeasAndCarrots" })
229
+ .expect(200)];
230
+ case 8:
231
+ updateRes = _b.sent();
232
+ (0, bun_test_1.expect)(updateRes.body.data.name).toBe("PeasAndCarrots");
233
+ return [2 /*return*/];
234
+ }
235
+ });
236
+ }); });
237
+ (0, bun_test_1.it)("signup with extra data", function () { return __awaiter(void 0, void 0, void 0, function () {
238
+ var res, _a, userId, token, refreshToken, user;
239
+ return __generator(this, function (_b) {
240
+ switch (_b.label) {
241
+ case 0: return [4 /*yield*/, agent
242
+ .post("/auth/signup")
243
+ .send({ age: 25, email: "new@example.com", password: "123" })
244
+ .expect(200)];
245
+ case 1:
246
+ res = _b.sent();
247
+ _a = res.body.data, userId = _a.userId, token = _a.token, refreshToken = _a.refreshToken;
248
+ (0, bun_test_1.expect)(userId).toBeDefined();
249
+ (0, bun_test_1.expect)(token).toBeDefined();
250
+ (0, bun_test_1.expect)(refreshToken).toBeDefined();
251
+ return [4 /*yield*/, tests_1.UserModel.findOne({ email: "new@example.com" })];
252
+ case 2:
253
+ user = _b.sent();
254
+ (0, bun_test_1.expect)(user === null || user === void 0 ? void 0 : user.age).toBe(25);
255
+ return [2 /*return*/];
256
+ }
257
+ });
258
+ }); });
259
+ (0, bun_test_1.it)("login failure", function () { return __awaiter(void 0, void 0, void 0, function () {
260
+ var res;
261
+ return __generator(this, function (_a) {
262
+ switch (_a.label) {
263
+ case 0: return [4 /*yield*/, agent
264
+ .post("/auth/login")
265
+ .send({ email: "admin@example.com", password: "wrong" })
266
+ .expect(401)];
267
+ case 1:
268
+ res = _a.sent();
269
+ (0, bun_test_1.expect)(res.body).toEqual({
270
+ message: "Password or username is incorrect",
271
+ });
272
+ return [4 /*yield*/, agent
273
+ .post("/auth/login")
274
+ .send({ email: "nope@example.com", password: "wrong" })
275
+ .expect(401)];
276
+ case 2:
277
+ res = _a.sent();
278
+ // we don't really want to expose if a given email address has an account in our system or not
279
+ (0, bun_test_1.expect)(res.body).toEqual({
280
+ message: "Password or username is incorrect",
281
+ });
282
+ return [2 /*return*/];
283
+ }
284
+ });
285
+ }); });
286
+ (0, bun_test_1.it)("case insensitive email", function () { return __awaiter(void 0, void 0, void 0, function () {
287
+ var res;
288
+ return __generator(this, function (_a) {
289
+ switch (_a.label) {
290
+ case 0: return [4 /*yield*/, agent
291
+ .post("/auth/login")
292
+ .send({ email: "ADMIN@example.com", password: "securePassword" })
293
+ .expect(200)];
294
+ case 1:
295
+ res = _a.sent();
296
+ (0, bun_test_1.expect)(res.body.data.token).toBeDefined();
297
+ return [2 /*return*/];
298
+ }
299
+ });
300
+ }); });
301
+ (0, bun_test_1.it)("case insensitive email with emails with symbols", function () { return __awaiter(void 0, void 0, void 0, function () {
302
+ var res;
303
+ return __generator(this, function (_a) {
304
+ switch (_a.label) {
305
+ case 0: return [4 /*yield*/, agent
306
+ .post("/auth/login")
307
+ .send({ email: "ADMIN+other@example.com", password: "otherPassword" })
308
+ .expect(200)];
309
+ case 1:
310
+ res = _a.sent();
311
+ (0, bun_test_1.expect)(res.body.data.token).toBeDefined();
312
+ return [2 /*return*/];
313
+ }
314
+ });
315
+ }); });
316
+ (0, bun_test_1.it)("completes token login e2e", function () { return __awaiter(void 0, void 0, void 0, function () {
317
+ var res, _a, userId, token, meRes, mePatchRes, getRes, food, updateRes;
318
+ return __generator(this, function (_b) {
319
+ switch (_b.label) {
320
+ case 0: return [4 /*yield*/, agent
321
+ .post("/auth/login")
322
+ .send({ email: "admin@example.com", password: "securePassword" })
323
+ .expect(200)];
324
+ case 1:
325
+ res = _b.sent();
326
+ _a = res.body.data, userId = _a.userId, token = _a.token;
327
+ (0, bun_test_1.expect)(userId).toBeDefined();
328
+ (0, bun_test_1.expect)(token).toBeDefined();
329
+ return [4 /*yield*/, agent.set("authorization", "Bearer ".concat(res.body.data.token))];
330
+ case 2:
331
+ _b.sent();
332
+ return [4 /*yield*/, agent.get("/auth/me").expect(200)];
333
+ case 3:
334
+ meRes = _b.sent();
335
+ (0, bun_test_1.expect)(meRes.body.data._id).toBeDefined();
336
+ (0, bun_test_1.expect)(meRes.body.data.id).toBeDefined();
337
+ (0, bun_test_1.expect)(meRes.body.data.hash).toBeUndefined();
338
+ (0, bun_test_1.expect)(meRes.body.data.email).toBe("admin@example.com");
339
+ (0, bun_test_1.expect)(meRes.body.data.updated).toBeDefined();
340
+ (0, bun_test_1.expect)(meRes.body.data.created).toBeDefined();
341
+ (0, bun_test_1.expect)(meRes.body.data.admin).toBe(true);
342
+ return [4 /*yield*/, agent
343
+ .patch("/auth/me")
344
+ .send({ email: "admin2@example.com" })
345
+ .expect(200)];
346
+ case 4:
347
+ mePatchRes = _b.sent();
348
+ (0, bun_test_1.expect)(mePatchRes.body.data._id).toBeDefined();
349
+ (0, bun_test_1.expect)(mePatchRes.body.data.id).toBeDefined();
350
+ (0, bun_test_1.expect)(mePatchRes.body.data.hash).toBeUndefined();
351
+ (0, bun_test_1.expect)(mePatchRes.body.data.email).toBe("admin2@example.com");
352
+ (0, bun_test_1.expect)(mePatchRes.body.data.updated).toBeDefined();
353
+ (0, bun_test_1.expect)(mePatchRes.body.data.created).toBeDefined();
354
+ (0, bun_test_1.expect)(mePatchRes.body.data.admin).toBe(true);
355
+ return [4 /*yield*/, agent.get("/food").expect(200)];
356
+ case 5:
357
+ getRes = _b.sent();
358
+ (0, bun_test_1.expect)(getRes.body.data).toHaveLength(3);
359
+ food = getRes.body.data.find(function (f) { return f.name === "Apple"; });
360
+ (0, bun_test_1.expect)(food).toBeDefined();
361
+ return [4 /*yield*/, agent
362
+ .patch("/food/".concat(food.id))
363
+ .set("authorization", "Bearer ".concat(token))
364
+ .send({ name: "Apple Pie" })
365
+ .expect(200)];
366
+ case 6:
367
+ updateRes = _b.sent();
368
+ (0, bun_test_1.expect)(updateRes.body.data.name).toBe("Apple Pie");
369
+ return [2 /*return*/];
370
+ }
371
+ });
372
+ }); });
373
+ (0, bun_test_1.it)("login successfully and tokens expire", function () { return __awaiter(void 0, void 0, void 0, function () {
374
+ var res, _a, userId, token;
375
+ return __generator(this, function (_b) {
376
+ switch (_b.label) {
377
+ case 0: return [4 /*yield*/, agent
378
+ .post("/auth/login")
379
+ .send({ email: "admin@example.com", password: "securePassword" })
380
+ .expect(200)];
381
+ case 1:
382
+ res = _b.sent();
383
+ _a = res.body.data, userId = _a.userId, token = _a.token;
384
+ (0, bun_test_1.expect)(userId).toBeDefined();
385
+ (0, bun_test_1.expect)(token).toBeDefined();
386
+ return [4 /*yield*/, agent.set("authorization", "Bearer ".concat(res.body.data.token))];
387
+ case 2:
388
+ _b.sent();
389
+ return [4 /*yield*/, agent.get("/auth/me").expect(200)];
390
+ case 3:
391
+ _b.sent();
392
+ // Advance time to past token expiration
393
+ (0, bun_test_1.setSystemTime)(Date.now() + 1000 * 60 * 60 * 24 * 30);
394
+ return [4 /*yield*/, agent.get("/auth/me").expect(401)];
395
+ case 4:
396
+ _b.sent();
397
+ return [2 /*return*/];
398
+ }
399
+ });
400
+ }); });
401
+ (0, bun_test_1.it)("locks out after failed password attempts", function () { return __awaiter(void 0, void 0, void 0, function () {
402
+ var res, user;
403
+ return __generator(this, function (_a) {
404
+ switch (_a.label) {
405
+ case 0: return [4 /*yield*/, agent
406
+ .post("/auth/login")
407
+ .send({ email: "admin@example.com", password: "wrong" })
408
+ .expect(401)];
409
+ case 1:
410
+ res = _a.sent();
411
+ (0, bun_test_1.expect)(res.body).toEqual({
412
+ message: "Password or username is incorrect",
413
+ });
414
+ return [4 /*yield*/, tests_1.UserModel.findById(admin._id)];
415
+ case 2:
416
+ user = _a.sent();
417
+ (0, bun_test_1.expect)(user === null || user === void 0 ? void 0 : user.attempts).toBe(1);
418
+ return [4 /*yield*/, agent
419
+ .post("/auth/login")
420
+ .send({ email: "admin@example.com", password: "wrong" })
421
+ .expect(401)];
422
+ case 3:
423
+ res = _a.sent();
424
+ (0, bun_test_1.expect)(res.body).toEqual({
425
+ message: "Password or username is incorrect",
426
+ });
427
+ return [4 /*yield*/, tests_1.UserModel.findById(admin._id)];
428
+ case 4:
429
+ user = _a.sent();
430
+ (0, bun_test_1.expect)(user === null || user === void 0 ? void 0 : user.attempts).toBe(2);
431
+ return [4 /*yield*/, agent
432
+ .post("/auth/login")
433
+ .send({ email: "admin@example.com", password: "wrong" })
434
+ .expect(401)];
435
+ case 5:
436
+ res = _a.sent();
437
+ (0, bun_test_1.expect)(res.body).toEqual({
438
+ message: "Account locked due to too many failed login attempts",
439
+ });
440
+ return [4 /*yield*/, tests_1.UserModel.findById(admin._id)];
441
+ case 6:
442
+ user = _a.sent();
443
+ (0, bun_test_1.expect)(user === null || user === void 0 ? void 0 : user.attempts).toBe(3);
444
+ return [4 /*yield*/, agent
445
+ .post("/auth/login")
446
+ .send({ email: "admin@example.com", password: "securePassword" })
447
+ .expect(401)];
448
+ case 7:
449
+ // Logging in with correct password fails because account is locked
450
+ res = _a.sent();
451
+ (0, bun_test_1.expect)(res.body).toEqual({
452
+ message: "Account locked due to too many failed login attempts",
453
+ });
454
+ return [4 /*yield*/, tests_1.UserModel.findById(admin._id)];
455
+ case 8:
456
+ user = _a.sent();
457
+ // Not incremented
458
+ (0, bun_test_1.expect)(user === null || user === void 0 ? void 0 : user.attempts).toBe(3);
459
+ return [2 /*return*/];
460
+ }
461
+ });
462
+ }); });
463
+ (0, bun_test_1.it)("refresh token allows refresh of auth token", function () { return __awaiter(void 0, void 0, void 0, function () {
464
+ var initialLoginRes, initialToken, refreshRes, newToken, meRes;
465
+ return __generator(this, function (_a) {
466
+ switch (_a.label) {
467
+ case 0: return [4 /*yield*/, agent
468
+ .post("/auth/login")
469
+ .send({ email: "ADMIN@example.com", password: "securePassword" })
470
+ .expect(200)];
471
+ case 1:
472
+ initialLoginRes = _a.sent();
473
+ (0, bun_test_1.expect)(initialLoginRes.body.data.token).toBeDefined();
474
+ (0, bun_test_1.expect)(initialLoginRes.body.data.refreshToken).toBeDefined();
475
+ initialToken = initialLoginRes.body.data.token;
476
+ return [4 /*yield*/, agent.set("authorization", "Bearer ".concat(initialToken))];
477
+ case 2:
478
+ _a.sent();
479
+ return [4 /*yield*/, agent
480
+ .post("/auth/refresh_token")
481
+ .send({ refreshToken: initialLoginRes.body.data.refreshToken })
482
+ .expect(200)];
483
+ case 3:
484
+ refreshRes = _a.sent();
485
+ (0, bun_test_1.expect)(refreshRes.body.data.token).toBeDefined();
486
+ (0, bun_test_1.expect)(refreshRes.body.data.refreshToken).toBeDefined();
487
+ newToken = refreshRes.body.data.token;
488
+ // note that new token will most likely be the same as the old token because
489
+ // an HMAC signature will always be the same for a header + payload combination that is equal.
490
+ // make sure new token works
491
+ return [4 /*yield*/, agent.set("authorization", "Bearer ".concat(newToken))];
492
+ case 4:
493
+ // note that new token will most likely be the same as the old token because
494
+ // an HMAC signature will always be the same for a header + payload combination that is equal.
495
+ // make sure new token works
496
+ _a.sent();
497
+ return [4 /*yield*/, agent.get("/auth/me").expect(200)];
498
+ case 5:
499
+ meRes = _a.sent();
500
+ (0, bun_test_1.expect)(meRes.body.data._id).toBeDefined();
501
+ return [2 /*return*/];
502
+ }
503
+ });
504
+ }); });
505
+ (0, bun_test_1.it)("disabled user fails", function () { return __awaiter(void 0, void 0, void 0, function () {
506
+ var initialLoginRes, initialToken, meRes, failRes;
507
+ return __generator(this, function (_a) {
508
+ switch (_a.label) {
509
+ case 0: return [4 /*yield*/, agent
510
+ .post("/auth/login")
511
+ .send({ email: "ADMIN@example.com", password: "securePassword" })
512
+ .expect(200)];
513
+ case 1:
514
+ initialLoginRes = _a.sent();
515
+ (0, bun_test_1.expect)(initialLoginRes.body.data.token).toBeDefined();
516
+ (0, bun_test_1.expect)(initialLoginRes.body.data.refreshToken).toBeDefined();
517
+ initialToken = initialLoginRes.body.data.token;
518
+ return [4 /*yield*/, agent.set("authorization", "Bearer ".concat(initialToken))];
519
+ case 2:
520
+ _a.sent();
521
+ return [4 /*yield*/, agent.get("/auth/me").expect(200)];
522
+ case 3:
523
+ meRes = _a.sent();
524
+ (0, bun_test_1.expect)(meRes.body.data._id).toBeDefined();
525
+ admin.disabled = true;
526
+ return [4 /*yield*/, admin.save()];
527
+ case 4:
528
+ _a.sent();
529
+ return [4 /*yield*/, agent.get("/auth/me").expect(401)];
530
+ case 5:
531
+ failRes = _a.sent();
532
+ (0, bun_test_1.expect)(failRes.body).toEqual({ status: 401, title: "User is disabled" });
533
+ return [2 /*return*/];
534
+ }
535
+ });
536
+ }); });
537
+ (0, bun_test_1.it)("signup user with email that is already registered", function () { return __awaiter(void 0, void 0, void 0, function () {
538
+ var res2;
539
+ return __generator(this, function (_a) {
540
+ switch (_a.label) {
541
+ case 0: return [4 /*yield*/, agent
542
+ .post("/auth/signup")
543
+ .send({ age: 25, email: "new@example.com", password: "123" })
544
+ .expect(200)];
545
+ case 1:
546
+ _a.sent();
547
+ return [4 /*yield*/, agent
548
+ .post("/auth/signup")
549
+ .send({ age: 31, email: "new@example.com", password: "456" })
550
+ .expect(500)];
551
+ case 2:
552
+ res2 = _a.sent();
553
+ return [4 /*yield*/, (0, utils_1.timeout)(1000)];
554
+ case 3:
555
+ _a.sent();
556
+ (0, bun_test_1.expect)(res2.body.title).toBe("A user with the given username is already registered");
557
+ return [2 /*return*/];
558
+ }
559
+ });
560
+ }); });
561
+ });
562
+ (0, bun_test_1.describe)("custom auth options", function () {
563
+ var app;
564
+ var admin;
565
+ var notAdmin;
566
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
567
+ var _a;
568
+ return __generator(this, function (_b) {
569
+ switch (_b.label) {
570
+ case 0:
571
+ // Reset to real time - don't freeze time here as passport-local-mongoose
572
+ // lockout mechanism needs real time to progress
573
+ (0, bun_test_1.setSystemTime)();
574
+ return [4 /*yield*/, (0, tests_1.setupDb)()];
575
+ case 1:
576
+ _a = __read.apply(void 0, [_b.sent(), 2]), admin = _a[0], notAdmin = _a[1];
577
+ return [4 /*yield*/, Promise.all([
578
+ tests_1.FoodModel.create({
579
+ calories: 1,
580
+ created: new Date(),
581
+ name: "Spinach",
582
+ ownerId: notAdmin._id,
583
+ }),
584
+ tests_1.FoodModel.create({
585
+ calories: 100,
586
+ created: Date.now() - 10,
587
+ hidden: true,
588
+ name: "Apple",
589
+ ownerId: admin._id,
590
+ }),
591
+ tests_1.FoodModel.create({
592
+ calories: 100,
593
+ created: Date.now() - 10,
594
+ name: "Carrots",
595
+ ownerId: admin._id,
596
+ }),
597
+ ])];
598
+ case 2:
599
+ _b.sent();
600
+ app = (0, tests_1.getBaseServer)();
601
+ (0, auth_1.addAuthRoutes)(app, tests_1.UserModel, {
602
+ // custom refresh token logic based on admin or non admin
603
+ generateTokenExpiration: function (user) {
604
+ if (user === null || user === void 0 ? void 0 : user.admin) {
605
+ return "30d";
606
+ }
607
+ return "365d";
608
+ },
609
+ });
610
+ (0, auth_1.setupAuth)(app, tests_1.UserModel);
611
+ (0, auth_1.addMeRoutes)(app, tests_1.UserModel);
612
+ app.use("/food", (0, api_1.modelRouter)(tests_1.FoodModel, {
613
+ allowAnonymous: true,
614
+ permissions: {
615
+ create: [permissions_1.Permissions.IsAuthenticated],
616
+ delete: [permissions_1.Permissions.IsAuthenticated],
617
+ list: [permissions_1.Permissions.IsAny],
618
+ read: [permissions_1.Permissions.IsAny],
619
+ update: [permissions_1.Permissions.IsAuthenticated],
620
+ },
621
+ queryFilter: function (user) {
622
+ if (!(user === null || user === void 0 ? void 0 : user.admin)) {
623
+ return { hidden: { $ne: true } };
624
+ }
625
+ return {};
626
+ },
627
+ transformer: (0, transformers_1.AdminOwnerTransformer)({
628
+ adminReadFields: ["name", "calories", "created", "ownerId"],
629
+ adminWriteFields: ["name", "calories", "created", "ownerId"],
630
+ anonReadFields: ["name"],
631
+ anonWriteFields: [],
632
+ authReadFields: ["name", "calories", "created"],
633
+ authWriteFields: ["name", "calories"],
634
+ ownerReadFields: ["name", "calories", "created", "ownerId"],
635
+ ownerWriteFields: ["name", "calories", "created"],
636
+ }),
637
+ }));
638
+ return [2 /*return*/];
639
+ }
640
+ });
641
+ }); });
642
+ (0, bun_test_1.afterEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
643
+ return __generator(this, function (_a) {
644
+ (0, bun_test_1.setSystemTime)();
645
+ return [2 /*return*/];
646
+ });
647
+ }); });
648
+ (0, bun_test_1.it)("login successfully and tokens expire with custom token options", function () { return __awaiter(void 0, void 0, void 0, function () {
649
+ var adminAgent, res, notAdminAgent, res2;
650
+ return __generator(this, function (_a) {
651
+ switch (_a.label) {
652
+ case 0:
653
+ adminAgent = supertest_1.default.agent(app);
654
+ return [4 /*yield*/, adminAgent
655
+ .post("/auth/login")
656
+ .send({ email: "admin@example.com", password: "securePassword" })
657
+ .expect(200)];
658
+ case 1:
659
+ res = _a.sent();
660
+ (0, bun_test_1.expect)(res.body.data.userId).toBeDefined();
661
+ (0, bun_test_1.expect)(res.body.data.token).toBeDefined();
662
+ return [4 /*yield*/, adminAgent.set("authorization", "Bearer ".concat(res.body.data.token))];
663
+ case 2:
664
+ _a.sent();
665
+ notAdminAgent = supertest_1.default.agent(app);
666
+ return [4 /*yield*/, notAdminAgent
667
+ .post("/auth/login")
668
+ .send({ email: "notadmin@example.com", password: "password" })
669
+ .expect(200)];
670
+ case 3:
671
+ res2 = _a.sent();
672
+ (0, bun_test_1.expect)(res2.body.data.userId).toBeDefined();
673
+ (0, bun_test_1.expect)(res2.body.data.token).toBeDefined();
674
+ return [4 /*yield*/, notAdminAgent.set("authorization", "Bearer ".concat(res2.body.data.token))];
675
+ case 4:
676
+ _a.sent();
677
+ // and check that tokens are working for both users
678
+ return [4 /*yield*/, adminAgent.get("/auth/me").expect(200)];
679
+ case 5:
680
+ // and check that tokens are working for both users
681
+ _a.sent();
682
+ return [4 /*yield*/, notAdminAgent.get("/auth/me").expect(200)];
683
+ case 6:
684
+ _a.sent();
685
+ // Advance time by 30 days check that admin can no longer access with old token,
686
+ // and non-admin can due to custom times set as auth options
687
+ (0, bun_test_1.setSystemTime)(Date.now() + 1000 * 60 * 60 * 24 * 30);
688
+ return [4 /*yield*/, adminAgent.get("/auth/me").expect(401)];
689
+ case 7:
690
+ _a.sent();
691
+ return [4 /*yield*/, notAdminAgent.get("/auth/me").expect(200)];
692
+ case 8:
693
+ _a.sent();
694
+ // Advance time by an additional 335 days to pass the 365 day expiration for non-admin
695
+ (0, bun_test_1.setSystemTime)(Date.now() + 1000 * 60 * 60 * 24 * 365);
696
+ // ensure non-admin can no longer access
697
+ return [4 /*yield*/, notAdminAgent.get("/auth/me").expect(401)];
698
+ case 9:
699
+ // ensure non-admin can no longer access
700
+ _a.sent();
701
+ return [2 /*return*/];
702
+ }
703
+ });
704
+ }); });
705
+ });
706
+ (0, bun_test_1.describe)("generateTokens", function () {
707
+ var OLD_ENV = process.env;
708
+ (0, bun_test_1.beforeEach)(function () {
709
+ process.env = __assign({}, OLD_ENV);
710
+ process.env.TOKEN_SECRET = "secret";
711
+ process.env.REFRESH_TOKEN_SECRET = "refresh_secret";
712
+ });
713
+ (0, bun_test_1.afterEach)(function () {
714
+ process.env = OLD_ENV;
715
+ });
716
+ (0, bun_test_1.it)("generates a token and refresh token for a valid user", function () { return __awaiter(void 0, void 0, void 0, function () {
717
+ var user, _a, token, refreshToken, tokenParts;
718
+ return __generator(this, function (_b) {
719
+ switch (_b.label) {
720
+ case 0:
721
+ user = { _id: "12345" };
722
+ return [4 /*yield*/, (0, auth_1.generateTokens)(user)];
723
+ case 1:
724
+ _a = _b.sent(), token = _a.token, refreshToken = _a.refreshToken;
725
+ (0, bun_test_1.expect)(token).toBeDefined();
726
+ (0, bun_test_1.expect)(refreshToken).toBeDefined();
727
+ tokenParts = token === null || token === void 0 ? void 0 : token.split(".");
728
+ (0, bun_test_1.expect)(tokenParts === null || tokenParts === void 0 ? void 0 : tokenParts.length).toBe(3);
729
+ return [2 /*return*/];
730
+ }
731
+ });
732
+ }); });
733
+ (0, bun_test_1.it)("throws an error if TOKEN_SECRET is missing", function () { return __awaiter(void 0, void 0, void 0, function () {
734
+ var user;
735
+ return __generator(this, function (_a) {
736
+ switch (_a.label) {
737
+ case 0:
738
+ process.env.TOKEN_SECRET = undefined;
739
+ user = { _id: "12345" };
740
+ return [4 /*yield*/, (0, bun_test_1.expect)((0, auth_1.generateTokens)(user)).rejects.toThrow("TOKEN_SECRET must be set in env.")];
741
+ case 1:
742
+ _a.sent();
743
+ return [2 /*return*/];
744
+ }
745
+ });
746
+ }); });
747
+ (0, bun_test_1.it)("returns null tokens if user is missing", function () { return __awaiter(void 0, void 0, void 0, function () {
748
+ var result;
749
+ return __generator(this, function (_a) {
750
+ switch (_a.label) {
751
+ case 0: return [4 /*yield*/, (0, auth_1.generateTokens)(undefined)];
752
+ case 1:
753
+ result = _a.sent();
754
+ (0, bun_test_1.expect)(result).toEqual({ refreshToken: null, token: null });
755
+ return [2 /*return*/];
756
+ }
757
+ });
758
+ }); });
759
+ (0, bun_test_1.it)("respects custom expiration from authOptions", function () { return __awaiter(void 0, void 0, void 0, function () {
760
+ var user, authOptions, _a, token, refreshToken;
761
+ return __generator(this, function (_b) {
762
+ switch (_b.label) {
763
+ case 0:
764
+ user = { _id: "12345" };
765
+ authOptions = {
766
+ generateRefreshTokenExpiration: function () { return "7d"; },
767
+ generateTokenExpiration: function () { return "1h"; },
768
+ };
769
+ return [4 /*yield*/, (0, auth_1.generateTokens)(user, authOptions)];
770
+ case 1:
771
+ _a = _b.sent(), token = _a.token, refreshToken = _a.refreshToken;
772
+ (0, bun_test_1.expect)(token).toBeDefined();
773
+ (0, bun_test_1.expect)(refreshToken).toBeDefined();
774
+ return [2 /*return*/];
775
+ }
776
+ });
777
+ }); });
778
+ });