@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,639 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ 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);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ 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;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __read = (this && this.__read) || function (o, n) {
39
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
40
+ if (!m) return o;
41
+ var i = m.call(o), r, ar = [], e;
42
+ try {
43
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
44
+ }
45
+ catch (error) { e = { error: error }; }
46
+ finally {
47
+ try {
48
+ if (r && !r.done && (m = i["return"])) m.call(i);
49
+ }
50
+ finally { if (e) throw e.error; }
51
+ }
52
+ return ar;
53
+ };
54
+ var __importDefault = (this && this.__importDefault) || function (mod) {
55
+ return (mod && mod.__esModule) ? mod : { "default": mod };
56
+ };
57
+ Object.defineProperty(exports, "__esModule", { value: true });
58
+ var bun_test_1 = require("bun:test");
59
+ var mongoose_1 = require("mongoose");
60
+ var supertest_1 = __importDefault(require("supertest"));
61
+ var api_1 = require("./api");
62
+ var auth_1 = require("./auth");
63
+ var permissions_1 = require("./permissions");
64
+ var plugins_1 = require("./plugins");
65
+ var tests_1 = require("./tests");
66
+ var stuffSchema = new mongoose_1.Schema({
67
+ date: plugins_1.DateOnly,
68
+ name: String,
69
+ ownerId: String,
70
+ });
71
+ stuffSchema.plugin(plugins_1.isDeletedPlugin);
72
+ stuffSchema.plugin(plugins_1.findOneOrNone);
73
+ stuffSchema.plugin(plugins_1.findExactlyOne);
74
+ stuffSchema.plugin(plugins_1.upsertPlugin);
75
+ stuffSchema.plugin(plugins_1.createdUpdatedPlugin);
76
+ var StuffModel = (0, mongoose_1.model)("Stuff", stuffSchema);
77
+ (0, bun_test_1.describe)("createdUpdate", function () {
78
+ (0, bun_test_1.it)("sets created and updated on save", function () { return __awaiter(void 0, void 0, void 0, function () {
79
+ var stuff;
80
+ var _a;
81
+ return __generator(this, function (_b) {
82
+ switch (_b.label) {
83
+ case 0:
84
+ (0, bun_test_1.setSystemTime)(new Date("2022-12-17T03:24:00.000Z"));
85
+ return [4 /*yield*/, StuffModel.create({ name: "Things", ownerId: "123" })];
86
+ case 1:
87
+ stuff = _b.sent();
88
+ (0, bun_test_1.expect)(stuff.created).not.toBeNull();
89
+ (0, bun_test_1.expect)(stuff.updated).not.toBeNull();
90
+ (0, bun_test_1.expect)(stuff.created.toISOString()).toBe("2022-12-17T03:24:00.000Z");
91
+ (0, bun_test_1.expect)((_a = stuff.updated) === null || _a === void 0 ? void 0 : _a.toISOString()).toBe("2022-12-17T03:24:00.000Z");
92
+ stuff.name = "Thangs";
93
+ // Advance time by 10 seconds
94
+ (0, bun_test_1.setSystemTime)(new Date("2022-12-17T03:24:10.000Z"));
95
+ return [4 /*yield*/, stuff.save()];
96
+ case 2:
97
+ _b.sent();
98
+ (0, bun_test_1.expect)(stuff.created.toISOString()).toBe("2022-12-17T03:24:00.000Z");
99
+ (0, bun_test_1.expect)(stuff.updated && stuff.updated > stuff.created).toBe(true);
100
+ (0, bun_test_1.setSystemTime)();
101
+ return [2 /*return*/];
102
+ }
103
+ });
104
+ }); });
105
+ });
106
+ (0, bun_test_1.describe)("isDeleted", function () {
107
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
108
+ return __generator(this, function (_a) {
109
+ switch (_a.label) {
110
+ case 0: return [4 /*yield*/, StuffModel.deleteMany({})];
111
+ case 1:
112
+ _a.sent();
113
+ return [4 /*yield*/, Promise.all([
114
+ StuffModel.create({
115
+ deleted: true,
116
+ name: "Things",
117
+ ownerId: "123",
118
+ }),
119
+ StuffModel.create({
120
+ name: "StuffNThings",
121
+ ownerId: "123",
122
+ }),
123
+ ])];
124
+ case 2:
125
+ _a.sent();
126
+ return [2 /*return*/];
127
+ }
128
+ });
129
+ }); });
130
+ (0, bun_test_1.it)('filters out deleted documents from "find"', function () { return __awaiter(void 0, void 0, void 0, function () {
131
+ var stuff;
132
+ return __generator(this, function (_a) {
133
+ switch (_a.label) {
134
+ case 0: return [4 /*yield*/, StuffModel.find({})];
135
+ case 1:
136
+ stuff = _a.sent();
137
+ (0, bun_test_1.expect)(stuff).toHaveLength(1);
138
+ (0, bun_test_1.expect)(stuff[0].name).toBe("StuffNThings");
139
+ return [4 /*yield*/, StuffModel.find({ deleted: true })];
140
+ case 2:
141
+ // Providing deleted in query should return deleted documents:
142
+ stuff = _a.sent();
143
+ (0, bun_test_1.expect)(stuff).toHaveLength(1);
144
+ (0, bun_test_1.expect)(stuff[0].name).toBe("Things");
145
+ return [2 /*return*/];
146
+ }
147
+ });
148
+ }); });
149
+ (0, bun_test_1.it)('filters out deleted documents from "findOne"', function () { return __awaiter(void 0, void 0, void 0, function () {
150
+ var stuff;
151
+ return __generator(this, function (_a) {
152
+ switch (_a.label) {
153
+ case 0: return [4 /*yield*/, StuffModel.findOne({})];
154
+ case 1:
155
+ stuff = _a.sent();
156
+ (0, bun_test_1.expect)(stuff === null || stuff === void 0 ? void 0 : stuff.name).toBe("StuffNThings");
157
+ return [4 /*yield*/, StuffModel.findOne({ deleted: true })];
158
+ case 2:
159
+ // Providing deleted in query should return deleted document:
160
+ stuff = _a.sent();
161
+ (0, bun_test_1.expect)(stuff === null || stuff === void 0 ? void 0 : stuff.name).toBe("Things");
162
+ return [2 /*return*/];
163
+ }
164
+ });
165
+ }); });
166
+ });
167
+ (0, bun_test_1.describe)("findOneOrNone", function () {
168
+ var things;
169
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
170
+ var _a;
171
+ return __generator(this, function (_b) {
172
+ switch (_b.label) {
173
+ case 0: return [4 /*yield*/, StuffModel.deleteMany({})];
174
+ case 1:
175
+ _b.sent();
176
+ return [4 /*yield*/, (0, tests_1.setupDb)()];
177
+ case 2:
178
+ _b.sent();
179
+ return [4 /*yield*/, Promise.all([
180
+ StuffModel.create({
181
+ name: "Things",
182
+ ownerId: "123",
183
+ }),
184
+ StuffModel.create({
185
+ name: "StuffNThings",
186
+ ownerId: "123",
187
+ }),
188
+ ])];
189
+ case 3:
190
+ _a = __read.apply(void 0, [_b.sent(), 1]), things = _a[0];
191
+ return [2 /*return*/];
192
+ }
193
+ });
194
+ }); });
195
+ (0, bun_test_1.it)("returns null with no matches.", function () { return __awaiter(void 0, void 0, void 0, function () {
196
+ var result;
197
+ return __generator(this, function (_a) {
198
+ switch (_a.label) {
199
+ case 0: return [4 /*yield*/, StuffModel.findOneOrNone({ name: "OtherStuff" })];
200
+ case 1:
201
+ result = _a.sent();
202
+ (0, bun_test_1.expect)(result).toBeNull();
203
+ return [2 /*return*/];
204
+ }
205
+ });
206
+ }); });
207
+ (0, bun_test_1.it)("returns a single match", function () { return __awaiter(void 0, void 0, void 0, function () {
208
+ var result;
209
+ return __generator(this, function (_a) {
210
+ switch (_a.label) {
211
+ case 0: return [4 /*yield*/, StuffModel.findOneOrNone({ name: "Things" })];
212
+ case 1:
213
+ result = _a.sent();
214
+ (0, bun_test_1.expect)(result).not.toBeNull();
215
+ (0, bun_test_1.expect)(result === null || result === void 0 ? void 0 : result._id.toString()).toBe(things._id.toString());
216
+ return [2 /*return*/];
217
+ }
218
+ });
219
+ }); });
220
+ (0, bun_test_1.it)("throws error with two matches.", function () { return __awaiter(void 0, void 0, void 0, function () {
221
+ var fn;
222
+ return __generator(this, function (_a) {
223
+ switch (_a.label) {
224
+ case 0:
225
+ fn = function () { return StuffModel.findOneOrNone({ ownerId: "123" }); };
226
+ return [4 /*yield*/, (0, bun_test_1.expect)(fn()).rejects.toThrow(/Stuff\.findOne query returned multiple documents/)];
227
+ case 1:
228
+ _a.sent();
229
+ return [2 /*return*/];
230
+ }
231
+ });
232
+ }); });
233
+ (0, bun_test_1.it)("throws custom error with two matches.", function () { return __awaiter(void 0, void 0, void 0, function () {
234
+ var fn, error_1;
235
+ return __generator(this, function (_a) {
236
+ switch (_a.label) {
237
+ case 0:
238
+ fn = function () { return StuffModel.findOneOrNone({ ownerId: "123" }, { status: 400, title: "Oh no!" }); };
239
+ _a.label = 1;
240
+ case 1:
241
+ _a.trys.push([1, 3, , 4]);
242
+ return [4 /*yield*/, fn()];
243
+ case 2:
244
+ _a.sent();
245
+ // If the promise doesn't reject, the test should fail
246
+ throw new Error("Expected promise to reject");
247
+ case 3:
248
+ error_1 = _a.sent();
249
+ // Check if the error has title and status properties
250
+ (0, bun_test_1.expect)(error_1.title).toBe("Oh no!");
251
+ (0, bun_test_1.expect)(error_1.status).toBe(400);
252
+ (0, bun_test_1.expect)(error_1.detail).toBe('query: {"ownerId":"123"}');
253
+ return [3 /*break*/, 4];
254
+ case 4: return [2 /*return*/];
255
+ }
256
+ });
257
+ }); });
258
+ });
259
+ (0, bun_test_1.describe)("findExactlyOne", function () {
260
+ var things;
261
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
262
+ var _a;
263
+ return __generator(this, function (_b) {
264
+ switch (_b.label) {
265
+ case 0: return [4 /*yield*/, StuffModel.deleteMany({})];
266
+ case 1:
267
+ _b.sent();
268
+ return [4 /*yield*/, (0, tests_1.setupDb)()];
269
+ case 2:
270
+ _b.sent();
271
+ return [4 /*yield*/, Promise.all([
272
+ StuffModel.create({
273
+ name: "Things",
274
+ ownerId: "123",
275
+ }),
276
+ StuffModel.create({
277
+ name: "StuffNThings",
278
+ ownerId: "123",
279
+ }),
280
+ ])];
281
+ case 3:
282
+ _a = __read.apply(void 0, [_b.sent(), 1]), things = _a[0];
283
+ return [2 /*return*/];
284
+ }
285
+ });
286
+ }); });
287
+ (0, bun_test_1.it)("throws error with no matches.", function () { return __awaiter(void 0, void 0, void 0, function () {
288
+ var fn;
289
+ return __generator(this, function (_a) {
290
+ switch (_a.label) {
291
+ case 0:
292
+ fn = function () { return StuffModel.findExactlyOne({ name: "OtherStuff" }); };
293
+ return [4 /*yield*/, (0, bun_test_1.expect)(fn()).rejects.toThrow(/Stuff\.findExactlyOne query returned no documents/)];
294
+ case 1:
295
+ _a.sent();
296
+ return [2 /*return*/];
297
+ }
298
+ });
299
+ }); });
300
+ (0, bun_test_1.it)("returns a single match", function () { return __awaiter(void 0, void 0, void 0, function () {
301
+ var result;
302
+ return __generator(this, function (_a) {
303
+ switch (_a.label) {
304
+ case 0: return [4 /*yield*/, StuffModel.findExactlyOne({ name: "Things" })];
305
+ case 1:
306
+ result = _a.sent();
307
+ (0, bun_test_1.expect)(result._id.toString()).toBe(things._id.toString());
308
+ return [2 /*return*/];
309
+ }
310
+ });
311
+ }); });
312
+ (0, bun_test_1.it)("throws error with two matches.", function () { return __awaiter(void 0, void 0, void 0, function () {
313
+ var fn;
314
+ return __generator(this, function (_a) {
315
+ switch (_a.label) {
316
+ case 0:
317
+ fn = function () { return StuffModel.findExactlyOne({ ownerId: "123" }); };
318
+ return [4 /*yield*/, (0, bun_test_1.expect)(fn()).rejects.toThrow(/Stuff\.findExactlyOne query returned multiple documents/)];
319
+ case 1:
320
+ _a.sent();
321
+ return [2 /*return*/];
322
+ }
323
+ });
324
+ }); });
325
+ (0, bun_test_1.it)("throws custom error with two matches.", function () { return __awaiter(void 0, void 0, void 0, function () {
326
+ var fn, error_2;
327
+ return __generator(this, function (_a) {
328
+ switch (_a.label) {
329
+ case 0:
330
+ fn = function () { return StuffModel.findExactlyOne({ ownerId: "123" }, { status: 400, title: "Oh no!" }); };
331
+ _a.label = 1;
332
+ case 1:
333
+ _a.trys.push([1, 3, , 4]);
334
+ return [4 /*yield*/, fn()];
335
+ case 2:
336
+ _a.sent();
337
+ // If the promise doesn't reject, the test should fail
338
+ throw new Error("Expected promise to reject");
339
+ case 3:
340
+ error_2 = _a.sent();
341
+ // Check if the error has title and status properties
342
+ (0, bun_test_1.expect)(error_2.title).toBe("Oh no!");
343
+ (0, bun_test_1.expect)(error_2.status).toBe(400);
344
+ (0, bun_test_1.expect)(error_2.detail).toBe('query: {"ownerId":"123"}');
345
+ return [3 /*break*/, 4];
346
+ case 4: return [2 /*return*/];
347
+ }
348
+ });
349
+ }); });
350
+ });
351
+ (0, bun_test_1.describe)("upsertPlugin", function () {
352
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
353
+ return __generator(this, function (_a) {
354
+ switch (_a.label) {
355
+ case 0: return [4 /*yield*/, StuffModel.deleteMany({})];
356
+ case 1:
357
+ _a.sent();
358
+ return [4 /*yield*/, (0, tests_1.setupDb)()];
359
+ case 2:
360
+ _a.sent();
361
+ return [2 /*return*/];
362
+ }
363
+ });
364
+ }); });
365
+ (0, bun_test_1.it)("creates a new document when none exists", function () { return __awaiter(void 0, void 0, void 0, function () {
366
+ var result, found;
367
+ return __generator(this, function (_a) {
368
+ switch (_a.label) {
369
+ case 0: return [4 /*yield*/, StuffModel.upsert({ name: "NewThing" }, { ownerId: "456" })];
370
+ case 1:
371
+ result = _a.sent();
372
+ (0, bun_test_1.expect)(result.name).toBe("NewThing");
373
+ (0, bun_test_1.expect)(result.ownerId).toBe("456");
374
+ return [4 /*yield*/, StuffModel.findOne({ name: "NewThing" })];
375
+ case 2:
376
+ found = _a.sent();
377
+ (0, bun_test_1.expect)(found).not.toBeNull();
378
+ (0, bun_test_1.expect)(found === null || found === void 0 ? void 0 : found.ownerId).toBe("456");
379
+ return [2 /*return*/];
380
+ }
381
+ });
382
+ }); });
383
+ (0, bun_test_1.it)("updates existing document when one exists", function () { return __awaiter(void 0, void 0, void 0, function () {
384
+ var initial, result, allDocs;
385
+ return __generator(this, function (_a) {
386
+ switch (_a.label) {
387
+ case 0: return [4 /*yield*/, StuffModel.create({
388
+ name: "ExistingThing",
389
+ ownerId: "123",
390
+ })];
391
+ case 1:
392
+ initial = _a.sent();
393
+ return [4 /*yield*/, StuffModel.upsert({ name: "ExistingThing" }, { ownerId: "789" })];
394
+ case 2:
395
+ result = _a.sent();
396
+ (0, bun_test_1.expect)(result._id.toString()).toBe(initial._id.toString());
397
+ (0, bun_test_1.expect)(result.ownerId).toBe("789");
398
+ return [4 /*yield*/, StuffModel.find({ name: "ExistingThing" })];
399
+ case 3:
400
+ allDocs = _a.sent();
401
+ (0, bun_test_1.expect)(allDocs).toHaveLength(1);
402
+ (0, bun_test_1.expect)(allDocs[0].ownerId).toBe("789");
403
+ return [2 /*return*/];
404
+ }
405
+ });
406
+ }); });
407
+ (0, bun_test_1.it)("throws error when multiple documents match conditions", function () { return __awaiter(void 0, void 0, void 0, function () {
408
+ var fn;
409
+ return __generator(this, function (_a) {
410
+ switch (_a.label) {
411
+ case 0: return [4 /*yield*/, Promise.all([
412
+ StuffModel.create({ name: "Thing1", ownerId: "123" }),
413
+ StuffModel.create({ name: "Thing2", ownerId: "123" }),
414
+ ])];
415
+ case 1:
416
+ _a.sent();
417
+ fn = function () { return StuffModel.upsert({ ownerId: "123" }, { name: "Updated" }); };
418
+ return [4 /*yield*/, (0, bun_test_1.expect)(fn()).rejects.toThrow(/Stuff\.upsert find query returned multiple documents/)];
419
+ case 2:
420
+ _a.sent();
421
+ return [2 /*return*/];
422
+ }
423
+ });
424
+ }); });
425
+ (0, bun_test_1.it)("combines conditions and update data for new documents", function () { return __awaiter(void 0, void 0, void 0, function () {
426
+ var result;
427
+ return __generator(this, function (_a) {
428
+ switch (_a.label) {
429
+ case 0: return [4 /*yield*/, StuffModel.upsert({ name: "TestCondition" }, { ownerId: "999" })];
430
+ case 1:
431
+ result = _a.sent();
432
+ (0, bun_test_1.expect)(result.name).toBe("TestCondition");
433
+ (0, bun_test_1.expect)(result.ownerId).toBe("999");
434
+ return [2 /*return*/];
435
+ }
436
+ });
437
+ }); });
438
+ });
439
+ (0, bun_test_1.describe)("TypeScript return types", function () {
440
+ var _things;
441
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
442
+ var _a;
443
+ return __generator(this, function (_b) {
444
+ switch (_b.label) {
445
+ case 0: return [4 /*yield*/, StuffModel.deleteMany({})];
446
+ case 1:
447
+ _b.sent();
448
+ return [4 /*yield*/, (0, tests_1.setupDb)()];
449
+ case 2:
450
+ _b.sent();
451
+ return [4 /*yield*/, Promise.all([
452
+ StuffModel.create({
453
+ date: new Date("2023-01-01"),
454
+ name: "Things",
455
+ ownerId: "123",
456
+ }),
457
+ StuffModel.create({
458
+ date: new Date("2023-01-02"),
459
+ name: "StuffNThings",
460
+ ownerId: "123",
461
+ }),
462
+ ])];
463
+ case 3:
464
+ _a = __read.apply(void 0, [_b.sent(), 1]), _things = _a[0];
465
+ return [2 /*return*/];
466
+ }
467
+ });
468
+ }); });
469
+ (0, bun_test_1.it)("findOneOrNone returns properly typed document or null", function () { return __awaiter(void 0, void 0, void 0, function () {
470
+ var result;
471
+ return __generator(this, function (_a) {
472
+ switch (_a.label) {
473
+ case 0: return [4 /*yield*/, StuffModel.findOneOrNone({ name: "Things" })];
474
+ case 1:
475
+ result = _a.sent();
476
+ if (result) {
477
+ (0, bun_test_1.expect)(typeof result._id.toString()).toBe("string");
478
+ (0, bun_test_1.expect)(typeof result.name).toBe("string");
479
+ (0, bun_test_1.expect)(typeof result.ownerId).toBe("string");
480
+ (0, bun_test_1.expect)(result.date).toBeInstanceOf(Date);
481
+ }
482
+ else {
483
+ (0, bun_test_1.expect)(result).toBeNull();
484
+ }
485
+ return [2 /*return*/];
486
+ }
487
+ });
488
+ }); });
489
+ (0, bun_test_1.it)("findExactlyOne returns properly typed document", function () { return __awaiter(void 0, void 0, void 0, function () {
490
+ var result;
491
+ return __generator(this, function (_a) {
492
+ switch (_a.label) {
493
+ case 0: return [4 /*yield*/, StuffModel.findExactlyOne({ name: "Things" })];
494
+ case 1:
495
+ result = _a.sent();
496
+ (0, bun_test_1.expect)(typeof result._id.toString()).toBe("string");
497
+ (0, bun_test_1.expect)(typeof result.name).toBe("string");
498
+ (0, bun_test_1.expect)(typeof result.ownerId).toBe("string");
499
+ (0, bun_test_1.expect)(result.date).toBeInstanceOf(Date);
500
+ return [2 /*return*/];
501
+ }
502
+ });
503
+ }); });
504
+ });
505
+ (0, bun_test_1.describe)("DateOnly", function () {
506
+ (0, bun_test_1.it)("throws error with invalid date", function () { return __awaiter(void 0, void 0, void 0, function () {
507
+ var error_3;
508
+ return __generator(this, function (_a) {
509
+ switch (_a.label) {
510
+ case 0:
511
+ _a.trys.push([0, 2, , 3]);
512
+ return [4 /*yield*/, StuffModel.create({
513
+ date: "foo",
514
+ name: "Things",
515
+ ownerId: "123",
516
+ })];
517
+ case 1:
518
+ _a.sent();
519
+ return [3 /*break*/, 3];
520
+ case 2:
521
+ error_3 = _a.sent();
522
+ (0, bun_test_1.expect)(error_3.message).toMatch(/Cast to DateOnly failed/);
523
+ return [2 /*return*/];
524
+ case 3: throw new Error("Expected error was not thrown");
525
+ }
526
+ });
527
+ }); });
528
+ (0, bun_test_1.it)("adjusts date to date only", function () { return __awaiter(void 0, void 0, void 0, function () {
529
+ var res;
530
+ return __generator(this, function (_a) {
531
+ switch (_a.label) {
532
+ case 0: return [4 /*yield*/, StuffModel.create({
533
+ date: "2005-10-10T17:17:17.017Z",
534
+ name: "Things",
535
+ ownerId: "123",
536
+ })];
537
+ case 1:
538
+ res = _a.sent();
539
+ (0, bun_test_1.expect)(res.date.toISOString()).toBe("2005-10-10T00:00:00.000Z");
540
+ return [2 /*return*/];
541
+ }
542
+ });
543
+ }); });
544
+ (0, bun_test_1.it)("filter on date only", function () { return __awaiter(void 0, void 0, void 0, function () {
545
+ var found;
546
+ return __generator(this, function (_a) {
547
+ switch (_a.label) {
548
+ case 0: return [4 /*yield*/, StuffModel.create({
549
+ date: "2000-10-10T17:17:17.017Z",
550
+ name: "Things",
551
+ ownerId: "123",
552
+ })];
553
+ case 1:
554
+ _a.sent();
555
+ return [4 /*yield*/, StuffModel.findOne({
556
+ date: {
557
+ $gte: "2000-01-01T00:00:00.000Z",
558
+ $lt: "2001-01-01T00:00:00.000Z",
559
+ },
560
+ })];
561
+ case 2:
562
+ found = _a.sent();
563
+ (0, bun_test_1.expect)(found === null || found === void 0 ? void 0 : found.date.toISOString()).toBe("2000-10-10T00:00:00.000Z");
564
+ return [4 /*yield*/, StuffModel.findOne({
565
+ date: {
566
+ $gte: "2000-01-01T12:12:12.000Z",
567
+ $lt: "2001-01-01T12:12:12.000Z",
568
+ },
569
+ })];
570
+ case 3:
571
+ found = _a.sent();
572
+ (0, bun_test_1.expect)(found === null || found === void 0 ? void 0 : found.date.toISOString()).toBe("2000-10-10T00:00:00.000Z");
573
+ return [2 /*return*/];
574
+ }
575
+ });
576
+ }); });
577
+ (0, bun_test_1.describe)("handle 404", function () {
578
+ var agent;
579
+ var app;
580
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
581
+ return __generator(this, function (_a) {
582
+ switch (_a.label) {
583
+ case 0: return [4 /*yield*/, (0, tests_1.setupDb)()];
584
+ case 1:
585
+ _a.sent();
586
+ app = (0, tests_1.getBaseServer)();
587
+ (0, auth_1.setupAuth)(app, tests_1.UserModel);
588
+ (0, auth_1.addAuthRoutes)(app, tests_1.UserModel);
589
+ app.use("/stuff", (0, api_1.modelRouter)(StuffModel, {
590
+ allowAnonymous: true,
591
+ permissions: {
592
+ create: [permissions_1.Permissions.IsAny],
593
+ delete: [permissions_1.Permissions.IsAny],
594
+ list: [permissions_1.Permissions.IsAny],
595
+ read: [permissions_1.Permissions.IsAny],
596
+ update: [permissions_1.Permissions.IsAny],
597
+ },
598
+ }));
599
+ (0, supertest_1.default)(app);
600
+ return [4 /*yield*/, (0, tests_1.authAsUser)(app, "notAdmin")];
601
+ case 2:
602
+ agent = _a.sent();
603
+ return [2 /*return*/];
604
+ }
605
+ });
606
+ }); });
607
+ (0, bun_test_1.it)("returns 404 with context for hidden document", function () { return __awaiter(void 0, void 0, void 0, function () {
608
+ var doc, res;
609
+ return __generator(this, function (_a) {
610
+ switch (_a.label) {
611
+ case 0: return [4 /*yield*/, StuffModel.create({ deleted: true, name: "test" })];
612
+ case 1:
613
+ doc = _a.sent();
614
+ return [4 /*yield*/, agent.get("/stuff/".concat(doc._id)).expect(404)];
615
+ case 2:
616
+ res = _a.sent();
617
+ (0, bun_test_1.expect)(res.body.title).toBe("Document ".concat(doc._id, " not found for model Stuff"));
618
+ (0, bun_test_1.expect)(res.body.meta).toEqual({ deleted: "true" });
619
+ return [2 /*return*/];
620
+ }
621
+ });
622
+ }); });
623
+ (0, bun_test_1.it)("returns 404 without meta for missing document", function () { return __awaiter(void 0, void 0, void 0, function () {
624
+ var nonExistentId, res;
625
+ return __generator(this, function (_a) {
626
+ switch (_a.label) {
627
+ case 0:
628
+ nonExistentId = "507f1f77bcf86cd799439011";
629
+ return [4 /*yield*/, agent.get("/stuff/".concat(nonExistentId)).expect(404)];
630
+ case 1:
631
+ res = _a.sent();
632
+ (0, bun_test_1.expect)(res.body.title).toBe("Document ".concat(nonExistentId, " not found for model Stuff"));
633
+ (0, bun_test_1.expect)(res.body.meta).toBeUndefined();
634
+ return [2 /*return*/];
635
+ }
636
+ });
637
+ }); });
638
+ });
639
+ });
@@ -0,0 +1,14 @@
1
+ import type { Document } from "mongoose";
2
+ export type PopulatePath = {
3
+ path: string;
4
+ openApiComponent?: any;
5
+ fields?: string[];
6
+ };
7
+ export declare function getOpenApiSpecForModel(model: any, { populatePaths, extraModelProperties, }?: {
8
+ populatePaths?: PopulatePath[];
9
+ extraModelProperties?: any;
10
+ }): {
11
+ properties: any;
12
+ required: string[];
13
+ };
14
+ export declare function unpopulate<T>(doc: Document<T>, path: string): Document<T>;