@terreno/api 0.9.3 → 0.11.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 +5 -2
- package/bunfig.unit.toml +3 -0
- package/dist/auth.test.js +257 -0
- package/dist/consentApp.test.js +245 -0
- package/dist/expressServer.js +3 -9
- package/dist/expressServer.test.js +4 -7
- package/dist/githubAuth.test.js +380 -0
- package/dist/logger.test.d.ts +1 -0
- package/dist/logger.test.js +143 -0
- package/dist/notifiers/googleChatNotifier.test.js +37 -0
- package/dist/openApi.js +2 -2
- package/dist/openApi.test.js +125 -0
- package/dist/openApiBuilder.d.ts +1 -0
- package/dist/openApiBuilder.js +13 -2
- package/dist/openApiBuilder.test.js +66 -0
- package/dist/openApiEtag.test.js +8 -0
- package/dist/openApiValidator.test.js +309 -0
- package/dist/permissions.middleware.test.d.ts +1 -0
- package/dist/permissions.middleware.test.js +341 -0
- package/dist/plugins.d.ts +8 -8
- package/dist/plugins.js +38 -32
- package/dist/populate.test.js +99 -0
- package/dist/syncConsents.js +2 -2
- package/dist/syncConsents.test.js +273 -0
- package/dist/tests/bunSetup.js +27 -22
- package/dist/tests.d.ts +3 -3
- package/dist/tests.js +78 -82
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +7 -7
- package/package.json +2 -1
- package/src/__snapshots__/openApi.test.ts.snap +48 -0
- package/src/auth.test.ts +147 -0
- package/src/consentApp.test.ts +162 -0
- package/src/expressServer.test.ts +4 -11
- package/src/expressServer.ts +4 -8
- package/src/githubAuth.test.ts +307 -1
- package/src/logger.test.ts +149 -0
- package/src/notifiers/googleChatNotifier.test.ts +24 -0
- package/src/openApi.test.ts +157 -1
- package/src/openApi.ts +6 -2
- package/src/openApiBuilder.test.ts +81 -0
- package/src/openApiBuilder.ts +17 -2
- package/src/openApiEtag.test.ts +11 -0
- package/src/openApiValidator.test.ts +410 -0
- package/src/permissions.middleware.test.ts +197 -0
- package/src/plugins.ts +32 -23
- package/src/populate.test.ts +78 -2
- package/src/syncConsents.test.ts +145 -0
- package/src/syncConsents.ts +1 -1
- package/src/tests/bunSetup.ts +14 -8
- package/src/tests.ts +8 -8
- package/src/utils.ts +4 -4
|
@@ -0,0 +1,341 @@
|
|
|
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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
47
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
48
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
49
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
50
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
51
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
52
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
56
|
+
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);
|
|
57
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
58
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
59
|
+
function step(op) {
|
|
60
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
61
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
62
|
+
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;
|
|
63
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
64
|
+
switch (op[0]) {
|
|
65
|
+
case 0: case 1: t = op; break;
|
|
66
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
67
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
68
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
69
|
+
default:
|
|
70
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
71
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
72
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
73
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
74
|
+
if (t[2]) _.ops.pop();
|
|
75
|
+
_.trys.pop(); continue;
|
|
76
|
+
}
|
|
77
|
+
op = body.call(thisArg, _);
|
|
78
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
79
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
83
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
84
|
+
if (!m) return o;
|
|
85
|
+
var i = m.call(o), r, ar = [], e;
|
|
86
|
+
try {
|
|
87
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
88
|
+
}
|
|
89
|
+
catch (error) { e = { error: error }; }
|
|
90
|
+
finally {
|
|
91
|
+
try {
|
|
92
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
93
|
+
}
|
|
94
|
+
finally { if (e) throw e.error; }
|
|
95
|
+
}
|
|
96
|
+
return ar;
|
|
97
|
+
};
|
|
98
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
99
|
+
var bun_test_1 = require("bun:test");
|
|
100
|
+
var Sentry = __importStar(require("@sentry/bun"));
|
|
101
|
+
var errors_1 = require("./errors");
|
|
102
|
+
var permissions_1 = require("./permissions");
|
|
103
|
+
(0, bun_test_1.describe)("permissionMiddleware", function () {
|
|
104
|
+
var allPermissions = {
|
|
105
|
+
create: [permissions_1.Permissions.IsAny],
|
|
106
|
+
delete: [permissions_1.Permissions.IsAny],
|
|
107
|
+
list: [permissions_1.Permissions.IsAny],
|
|
108
|
+
read: [permissions_1.Permissions.IsAny],
|
|
109
|
+
update: [permissions_1.Permissions.IsAny],
|
|
110
|
+
};
|
|
111
|
+
var buildReq = function (overrides) {
|
|
112
|
+
if (overrides === void 0) { overrides = {}; }
|
|
113
|
+
return __assign({ method: "GET", params: {}, user: { id: "user-1" } }, overrides);
|
|
114
|
+
};
|
|
115
|
+
(0, bun_test_1.it)("calls next immediately for OPTIONS requests", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
116
|
+
var model, middleware, next;
|
|
117
|
+
return __generator(this, function (_a) {
|
|
118
|
+
switch (_a.label) {
|
|
119
|
+
case 0:
|
|
120
|
+
model = {
|
|
121
|
+
collection: { findOne: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
122
|
+
return [2 /*return*/, null];
|
|
123
|
+
}); }); }) },
|
|
124
|
+
findById: (0, bun_test_1.mock)(function () { return ({ exec: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
125
|
+
return [2 /*return*/, null];
|
|
126
|
+
}); }); }) }); }),
|
|
127
|
+
modelName: "MockModel",
|
|
128
|
+
};
|
|
129
|
+
middleware = (0, permissions_1.permissionMiddleware)(model, { permissions: allPermissions });
|
|
130
|
+
next = (0, bun_test_1.mock)(function () { });
|
|
131
|
+
return [4 /*yield*/, middleware(buildReq({ method: "OPTIONS" }), {}, next)];
|
|
132
|
+
case 1:
|
|
133
|
+
_a.sent();
|
|
134
|
+
(0, bun_test_1.expect)(next).toHaveBeenCalledTimes(1);
|
|
135
|
+
(0, bun_test_1.expect)(next.mock.calls[0]).toEqual([]);
|
|
136
|
+
(0, bun_test_1.expect)(model.findById).toHaveBeenCalledTimes(0);
|
|
137
|
+
return [2 /*return*/];
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}); });
|
|
141
|
+
(0, bun_test_1.it)("returns APIError for unsupported HTTP methods", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
142
|
+
var model, middleware, next, _a, error;
|
|
143
|
+
return __generator(this, function (_b) {
|
|
144
|
+
switch (_b.label) {
|
|
145
|
+
case 0:
|
|
146
|
+
model = {
|
|
147
|
+
collection: { findOne: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
148
|
+
return [2 /*return*/, null];
|
|
149
|
+
}); }); }) },
|
|
150
|
+
findById: (0, bun_test_1.mock)(function () { return ({ exec: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
151
|
+
return [2 /*return*/, null];
|
|
152
|
+
}); }); }) }); }),
|
|
153
|
+
modelName: "MockModel",
|
|
154
|
+
};
|
|
155
|
+
middleware = (0, permissions_1.permissionMiddleware)(model, { permissions: allPermissions });
|
|
156
|
+
next = (0, bun_test_1.mock)(function () { });
|
|
157
|
+
return [4 /*yield*/, middleware(buildReq({ method: "TRACE" }), {}, next)];
|
|
158
|
+
case 1:
|
|
159
|
+
_b.sent();
|
|
160
|
+
(0, bun_test_1.expect)(next).toHaveBeenCalledTimes(1);
|
|
161
|
+
_a = __read(next.mock.calls[0], 1), error = _a[0];
|
|
162
|
+
(0, bun_test_1.expect)(error).toBeInstanceOf(errors_1.APIError);
|
|
163
|
+
(0, bun_test_1.expect)(error.status).toBe(405);
|
|
164
|
+
(0, bun_test_1.expect)(error.title).toContain("Method TRACE not allowed");
|
|
165
|
+
return [2 /*return*/];
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}); });
|
|
169
|
+
(0, bun_test_1.it)("wraps query execution failures in a 500 APIError", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
170
|
+
var exec, model, middleware, next, _a, error;
|
|
171
|
+
return __generator(this, function (_b) {
|
|
172
|
+
switch (_b.label) {
|
|
173
|
+
case 0:
|
|
174
|
+
exec = (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
175
|
+
return __generator(this, function (_a) {
|
|
176
|
+
throw new Error("query failed");
|
|
177
|
+
});
|
|
178
|
+
}); });
|
|
179
|
+
model = {
|
|
180
|
+
collection: { findOne: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
181
|
+
return [2 /*return*/, null];
|
|
182
|
+
}); }); }) },
|
|
183
|
+
findById: (0, bun_test_1.mock)(function () { return ({ exec: exec }); }),
|
|
184
|
+
modelName: "MockModel",
|
|
185
|
+
};
|
|
186
|
+
middleware = (0, permissions_1.permissionMiddleware)(model, { permissions: allPermissions });
|
|
187
|
+
next = (0, bun_test_1.mock)(function () { });
|
|
188
|
+
return [4 /*yield*/, middleware(buildReq({ method: "GET", params: { id: "507f1f77bcf86cd799439011" } }), {}, next)];
|
|
189
|
+
case 1:
|
|
190
|
+
_b.sent();
|
|
191
|
+
(0, bun_test_1.expect)(exec).toHaveBeenCalledTimes(1);
|
|
192
|
+
_a = __read(next.mock.calls[0], 1), error = _a[0];
|
|
193
|
+
(0, bun_test_1.expect)(error).toBeInstanceOf(errors_1.APIError);
|
|
194
|
+
(0, bun_test_1.expect)(error.status).toBe(500);
|
|
195
|
+
(0, bun_test_1.expect)(error.title).toContain("GET failed on 507f1f77bcf86cd799439011");
|
|
196
|
+
return [2 /*return*/];
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}); });
|
|
200
|
+
(0, bun_test_1.it)("captures sentry message when document does not exist", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
201
|
+
var captureMessageSpy, model, middleware, next, _a, error;
|
|
202
|
+
return __generator(this, function (_b) {
|
|
203
|
+
switch (_b.label) {
|
|
204
|
+
case 0:
|
|
205
|
+
captureMessageSpy = (0, bun_test_1.spyOn)(Sentry, "captureMessage");
|
|
206
|
+
model = {
|
|
207
|
+
collection: { findOne: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
208
|
+
return [2 /*return*/, null];
|
|
209
|
+
}); }); }) },
|
|
210
|
+
findById: (0, bun_test_1.mock)(function () { return ({ exec: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
211
|
+
return [2 /*return*/, null];
|
|
212
|
+
}); }); }) }); }),
|
|
213
|
+
modelName: "MockModel",
|
|
214
|
+
};
|
|
215
|
+
middleware = (0, permissions_1.permissionMiddleware)(model, { permissions: allPermissions });
|
|
216
|
+
next = (0, bun_test_1.mock)(function () { });
|
|
217
|
+
return [4 /*yield*/, middleware(buildReq({ method: "GET", params: { id: "507f1f77bcf86cd799439011" } }), {}, next)];
|
|
218
|
+
case 1:
|
|
219
|
+
_b.sent();
|
|
220
|
+
(0, bun_test_1.expect)(captureMessageSpy).toHaveBeenCalledWith("Document 507f1f77bcf86cd799439011 not found for model MockModel");
|
|
221
|
+
_a = __read(next.mock.calls[0], 1), error = _a[0];
|
|
222
|
+
(0, bun_test_1.expect)(error).toBeInstanceOf(errors_1.APIError);
|
|
223
|
+
(0, bun_test_1.expect)(error.status).toBe(404);
|
|
224
|
+
(0, bun_test_1.expect)(error.meta).toBeUndefined();
|
|
225
|
+
captureMessageSpy.mockRestore();
|
|
226
|
+
return [2 /*return*/];
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}); });
|
|
230
|
+
(0, bun_test_1.it)("returns hidden reason metadata when document is deleted", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
231
|
+
var model, middleware, next, _a, error;
|
|
232
|
+
return __generator(this, function (_b) {
|
|
233
|
+
switch (_b.label) {
|
|
234
|
+
case 0:
|
|
235
|
+
model = {
|
|
236
|
+
collection: { findOne: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
237
|
+
return [2 /*return*/, ({ deleted: true })];
|
|
238
|
+
}); }); }) },
|
|
239
|
+
findById: (0, bun_test_1.mock)(function () { return ({ exec: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
240
|
+
return [2 /*return*/, null];
|
|
241
|
+
}); }); }) }); }),
|
|
242
|
+
modelName: "MockModel",
|
|
243
|
+
};
|
|
244
|
+
middleware = (0, permissions_1.permissionMiddleware)(model, { permissions: allPermissions });
|
|
245
|
+
next = (0, bun_test_1.mock)(function () { });
|
|
246
|
+
return [4 /*yield*/, middleware(buildReq({ method: "GET", params: { id: "507f1f77bcf86cd799439011" } }), {}, next)];
|
|
247
|
+
case 1:
|
|
248
|
+
_b.sent();
|
|
249
|
+
_a = __read(next.mock.calls[0], 1), error = _a[0];
|
|
250
|
+
(0, bun_test_1.expect)(error).toBeInstanceOf(errors_1.APIError);
|
|
251
|
+
(0, bun_test_1.expect)(error.status).toBe(404);
|
|
252
|
+
(0, bun_test_1.expect)(error.meta).toEqual({ deleted: "true" });
|
|
253
|
+
(0, bun_test_1.expect)(error.disableExternalErrorTracking).toBe(true);
|
|
254
|
+
return [2 /*return*/];
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}); });
|
|
258
|
+
(0, bun_test_1.it)("returns hidden reason metadata when document is disabled", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
259
|
+
var model, middleware, next, _a, error;
|
|
260
|
+
return __generator(this, function (_b) {
|
|
261
|
+
switch (_b.label) {
|
|
262
|
+
case 0:
|
|
263
|
+
model = {
|
|
264
|
+
collection: { findOne: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
265
|
+
return [2 /*return*/, ({ disabled: true })];
|
|
266
|
+
}); }); }) },
|
|
267
|
+
findById: (0, bun_test_1.mock)(function () { return ({ exec: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
268
|
+
return [2 /*return*/, null];
|
|
269
|
+
}); }); }) }); }),
|
|
270
|
+
modelName: "MockModel",
|
|
271
|
+
};
|
|
272
|
+
middleware = (0, permissions_1.permissionMiddleware)(model, { permissions: allPermissions });
|
|
273
|
+
next = (0, bun_test_1.mock)(function () { });
|
|
274
|
+
return [4 /*yield*/, middleware(buildReq({ method: "GET", params: { id: "507f1f77bcf86cd799439011" } }), {}, next)];
|
|
275
|
+
case 1:
|
|
276
|
+
_b.sent();
|
|
277
|
+
_a = __read(next.mock.calls[0], 1), error = _a[0];
|
|
278
|
+
(0, bun_test_1.expect)(error).toBeInstanceOf(errors_1.APIError);
|
|
279
|
+
(0, bun_test_1.expect)(error.status).toBe(404);
|
|
280
|
+
(0, bun_test_1.expect)(error.meta).toEqual({ disabled: "true" });
|
|
281
|
+
(0, bun_test_1.expect)(error.disableExternalErrorTracking).toBe(true);
|
|
282
|
+
return [2 /*return*/];
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}); });
|
|
286
|
+
(0, bun_test_1.it)("returns hidden reason metadata when document is archived", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
287
|
+
var model, middleware, next, _a, error;
|
|
288
|
+
return __generator(this, function (_b) {
|
|
289
|
+
switch (_b.label) {
|
|
290
|
+
case 0:
|
|
291
|
+
model = {
|
|
292
|
+
collection: { findOne: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
293
|
+
return [2 /*return*/, ({ archived: true })];
|
|
294
|
+
}); }); }) },
|
|
295
|
+
findById: (0, bun_test_1.mock)(function () { return ({ exec: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
296
|
+
return [2 /*return*/, null];
|
|
297
|
+
}); }); }) }); }),
|
|
298
|
+
modelName: "MockModel",
|
|
299
|
+
};
|
|
300
|
+
middleware = (0, permissions_1.permissionMiddleware)(model, { permissions: allPermissions });
|
|
301
|
+
next = (0, bun_test_1.mock)(function () { });
|
|
302
|
+
return [4 /*yield*/, middleware(buildReq({ method: "GET", params: { id: "507f1f77bcf86cd799439011" } }), {}, next)];
|
|
303
|
+
case 1:
|
|
304
|
+
_b.sent();
|
|
305
|
+
_a = __read(next.mock.calls[0], 1), error = _a[0];
|
|
306
|
+
(0, bun_test_1.expect)(error).toBeInstanceOf(errors_1.APIError);
|
|
307
|
+
(0, bun_test_1.expect)(error.status).toBe(404);
|
|
308
|
+
(0, bun_test_1.expect)(error.meta).toEqual({ archived: "true" });
|
|
309
|
+
(0, bun_test_1.expect)(error.disableExternalErrorTracking).toBe(true);
|
|
310
|
+
return [2 /*return*/];
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}); });
|
|
314
|
+
(0, bun_test_1.it)("returns plain not found when hidden document has no reason", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
315
|
+
var model, middleware, next, _a, error;
|
|
316
|
+
return __generator(this, function (_b) {
|
|
317
|
+
switch (_b.label) {
|
|
318
|
+
case 0:
|
|
319
|
+
model = {
|
|
320
|
+
collection: { findOne: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
321
|
+
return [2 /*return*/, ({ foo: "bar" })];
|
|
322
|
+
}); }); }) },
|
|
323
|
+
findById: (0, bun_test_1.mock)(function () { return ({ exec: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
324
|
+
return [2 /*return*/, null];
|
|
325
|
+
}); }); }) }); }),
|
|
326
|
+
modelName: "MockModel",
|
|
327
|
+
};
|
|
328
|
+
middleware = (0, permissions_1.permissionMiddleware)(model, { permissions: allPermissions });
|
|
329
|
+
next = (0, bun_test_1.mock)(function () { });
|
|
330
|
+
return [4 /*yield*/, middleware(buildReq({ method: "GET", params: { id: "507f1f77bcf86cd799439011" } }), {}, next)];
|
|
331
|
+
case 1:
|
|
332
|
+
_b.sent();
|
|
333
|
+
_a = __read(next.mock.calls[0], 1), error = _a[0];
|
|
334
|
+
(0, bun_test_1.expect)(error).toBeInstanceOf(errors_1.APIError);
|
|
335
|
+
(0, bun_test_1.expect)(error.status).toBe(404);
|
|
336
|
+
(0, bun_test_1.expect)(error.meta).toBeUndefined();
|
|
337
|
+
return [2 /*return*/];
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}); });
|
|
341
|
+
});
|
package/dist/plugins.d.ts
CHANGED
|
@@ -4,13 +4,13 @@ export interface BaseUser {
|
|
|
4
4
|
admin: boolean;
|
|
5
5
|
email: string;
|
|
6
6
|
}
|
|
7
|
-
export declare
|
|
7
|
+
export declare const baseUserPlugin: (schema: Schema<any, any, any, any>) => void;
|
|
8
8
|
/** For models with the isDeletedPlugin, extend this interface to add the appropriate fields. */
|
|
9
9
|
export interface IsDeleted {
|
|
10
10
|
deleted: boolean;
|
|
11
11
|
}
|
|
12
|
-
export declare
|
|
13
|
-
export declare
|
|
12
|
+
export declare const isDeletedPlugin: (schema: Schema<any, any, any, any>, defaultValue?: boolean) => void;
|
|
13
|
+
export declare const isDisabledPlugin: (schema: Schema<any, any, any, any>, defaultValue?: boolean) => void;
|
|
14
14
|
export interface CreatedDeleted {
|
|
15
15
|
updated: {
|
|
16
16
|
type: Date;
|
|
@@ -21,8 +21,8 @@ export interface CreatedDeleted {
|
|
|
21
21
|
required: true;
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
export declare
|
|
25
|
-
export declare
|
|
24
|
+
export declare const createdUpdatedPlugin: (schema: Schema<any, any, any, any>) => void;
|
|
25
|
+
export declare const firebaseJWTPlugin: (schema: Schema) => void;
|
|
26
26
|
/**
|
|
27
27
|
* This adds a static method `Model.findOneOrNone` to the schema. This should replace `Model.findOne` in most instances.
|
|
28
28
|
* `Model.findOne` should only be used with a unique index, but that's not apparent from the docs. Otherwise you can wind
|
|
@@ -30,7 +30,7 @@ export declare function firebaseJWTPlugin(schema: Schema): void;
|
|
|
30
30
|
* document, or throws an exception if multiple are found.
|
|
31
31
|
* @param schema Mongoose Schema
|
|
32
32
|
*/
|
|
33
|
-
export declare
|
|
33
|
+
export declare const findOneOrNone: <T>(schema: Schema<T>) => void;
|
|
34
34
|
/**
|
|
35
35
|
* This adds a static method `Model.findExactlyOne` to the schema. This or findOneOrNone should replace `Model.findOne`
|
|
36
36
|
* in most instances.
|
|
@@ -39,14 +39,14 @@ export declare function findOneOrNone<T>(schema: Schema<T>): void;
|
|
|
39
39
|
* multiple or none are found.
|
|
40
40
|
* @param schema Mongoose Schema
|
|
41
41
|
*/
|
|
42
|
-
export declare
|
|
42
|
+
export declare const findExactlyOne: <T>(schema: Schema<T>) => void;
|
|
43
43
|
/**
|
|
44
44
|
* This adds a static method `Model.upsert` to the schema. This method will either update an existing document
|
|
45
45
|
* that matches the conditions or create a new document if none exists. It throws an error if multiple documents
|
|
46
46
|
* match the conditions to prevent ambiguous updates.
|
|
47
47
|
* @param schema Mongoose Schema
|
|
48
48
|
*/
|
|
49
|
-
export declare
|
|
49
|
+
export declare const upsertPlugin: <T>(schema: Schema<any, any, any, any>) => void;
|
|
50
50
|
/** For models with the upsertPlugin, extend this interface to add the upsert static method. */
|
|
51
51
|
export interface HasUpsert<T> {
|
|
52
52
|
upsert(conditions: Record<string, any>, update: Record<string, any>): Promise<T>;
|
package/dist/plugins.js
CHANGED
|
@@ -95,23 +95,18 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
95
95
|
}
|
|
96
96
|
};
|
|
97
97
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
98
|
-
exports.DateOnly = void 0;
|
|
99
|
-
exports.baseUserPlugin = baseUserPlugin;
|
|
100
|
-
exports.isDeletedPlugin = isDeletedPlugin;
|
|
101
|
-
exports.isDisabledPlugin = isDisabledPlugin;
|
|
102
|
-
exports.createdUpdatedPlugin = createdUpdatedPlugin;
|
|
103
|
-
exports.firebaseJWTPlugin = firebaseJWTPlugin;
|
|
104
|
-
exports.findOneOrNone = findOneOrNone;
|
|
105
|
-
exports.findExactlyOne = findExactlyOne;
|
|
106
|
-
exports.upsertPlugin = upsertPlugin;
|
|
98
|
+
exports.DateOnly = exports.upsertPlugin = exports.findExactlyOne = exports.findOneOrNone = exports.firebaseJWTPlugin = exports.createdUpdatedPlugin = exports.isDisabledPlugin = exports.isDeletedPlugin = exports.baseUserPlugin = void 0;
|
|
107
99
|
var luxon_1 = require("luxon");
|
|
108
100
|
var mongoose_1 = __importStar(require("mongoose"));
|
|
109
101
|
var errors_1 = require("./errors");
|
|
110
|
-
function
|
|
111
|
-
schema.add({
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
102
|
+
var baseUserPlugin = function (schema) {
|
|
103
|
+
schema.add({
|
|
104
|
+
admin: { default: false, description: "Whether the user has admin privileges", type: Boolean },
|
|
105
|
+
});
|
|
106
|
+
schema.add({ email: { description: "The user's email address", index: true, type: String } });
|
|
107
|
+
};
|
|
108
|
+
exports.baseUserPlugin = baseUserPlugin;
|
|
109
|
+
var isDeletedPlugin = function (schema, defaultValue) {
|
|
115
110
|
if (defaultValue === void 0) { defaultValue = false; }
|
|
116
111
|
schema.add({
|
|
117
112
|
deleted: {
|
|
@@ -122,20 +117,21 @@ function isDeletedPlugin(schema, defaultValue) {
|
|
|
122
117
|
type: Boolean,
|
|
123
118
|
},
|
|
124
119
|
});
|
|
125
|
-
function
|
|
120
|
+
var applyDeleteFilter = function (q) {
|
|
126
121
|
var query = q.getQuery();
|
|
127
122
|
if (query && query.deleted === undefined) {
|
|
128
123
|
void q.where({ deleted: { $ne: true } });
|
|
129
124
|
}
|
|
130
|
-
}
|
|
125
|
+
};
|
|
131
126
|
schema.pre("find", function () {
|
|
132
127
|
applyDeleteFilter(this);
|
|
133
128
|
});
|
|
134
129
|
schema.pre("findOne", function () {
|
|
135
130
|
applyDeleteFilter(this);
|
|
136
131
|
});
|
|
137
|
-
}
|
|
138
|
-
|
|
132
|
+
};
|
|
133
|
+
exports.isDeletedPlugin = isDeletedPlugin;
|
|
134
|
+
var isDisabledPlugin = function (schema, defaultValue) {
|
|
139
135
|
if (defaultValue === void 0) { defaultValue = false; }
|
|
140
136
|
schema.add({
|
|
141
137
|
disabled: {
|
|
@@ -145,10 +141,13 @@ function isDisabledPlugin(schema, defaultValue) {
|
|
|
145
141
|
type: Boolean,
|
|
146
142
|
},
|
|
147
143
|
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
schema.add({
|
|
144
|
+
};
|
|
145
|
+
exports.isDisabledPlugin = isDisabledPlugin;
|
|
146
|
+
var createdUpdatedPlugin = function (schema) {
|
|
147
|
+
schema.add({
|
|
148
|
+
updated: { description: "When this document was last updated", index: true, type: Date },
|
|
149
|
+
});
|
|
150
|
+
schema.add({ created: { description: "When this document was created", index: true, type: Date } });
|
|
152
151
|
schema.pre("save", function () {
|
|
153
152
|
if (this.disableCreatedUpdatedPlugin === true) {
|
|
154
153
|
return;
|
|
@@ -163,10 +162,14 @@ function createdUpdatedPlugin(schema) {
|
|
|
163
162
|
schema.pre(/save|updateOne|insertMany/, function () {
|
|
164
163
|
void this.updateOne({}, { $set: { updated: new Date() } });
|
|
165
164
|
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
};
|
|
166
|
+
exports.createdUpdatedPlugin = createdUpdatedPlugin;
|
|
167
|
+
var firebaseJWTPlugin = function (schema) {
|
|
168
|
+
schema.add({
|
|
169
|
+
firebaseId: { description: "The user's Firebase authentication ID", index: true, type: String },
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
exports.firebaseJWTPlugin = firebaseJWTPlugin;
|
|
170
173
|
/**
|
|
171
174
|
* This adds a static method `Model.findOneOrNone` to the schema. This should replace `Model.findOne` in most instances.
|
|
172
175
|
* `Model.findOne` should only be used with a unique index, but that's not apparent from the docs. Otherwise you can wind
|
|
@@ -174,7 +177,7 @@ function firebaseJWTPlugin(schema) {
|
|
|
174
177
|
* document, or throws an exception if multiple are found.
|
|
175
178
|
* @param schema Mongoose Schema
|
|
176
179
|
*/
|
|
177
|
-
function
|
|
180
|
+
var findOneOrNone = function (schema) {
|
|
178
181
|
schema.statics.findOneOrNone = function (query, errorArgs) {
|
|
179
182
|
return __awaiter(this, void 0, void 0, function () {
|
|
180
183
|
var results;
|
|
@@ -194,7 +197,8 @@ function findOneOrNone(schema) {
|
|
|
194
197
|
});
|
|
195
198
|
});
|
|
196
199
|
};
|
|
197
|
-
}
|
|
200
|
+
};
|
|
201
|
+
exports.findOneOrNone = findOneOrNone;
|
|
198
202
|
/**
|
|
199
203
|
* This adds a static method `Model.findExactlyOne` to the schema. This or findOneOrNone should replace `Model.findOne`
|
|
200
204
|
* in most instances.
|
|
@@ -203,7 +207,7 @@ function findOneOrNone(schema) {
|
|
|
203
207
|
* multiple or none are found.
|
|
204
208
|
* @param schema Mongoose Schema
|
|
205
209
|
*/
|
|
206
|
-
function
|
|
210
|
+
var findExactlyOne = function (schema) {
|
|
207
211
|
schema.statics.findExactlyOne = function (query, errorArgs) {
|
|
208
212
|
return __awaiter(this, void 0, void 0, function () {
|
|
209
213
|
var results;
|
|
@@ -223,14 +227,15 @@ function findExactlyOne(schema) {
|
|
|
223
227
|
});
|
|
224
228
|
});
|
|
225
229
|
};
|
|
226
|
-
}
|
|
230
|
+
};
|
|
231
|
+
exports.findExactlyOne = findExactlyOne;
|
|
227
232
|
/**
|
|
228
233
|
* This adds a static method `Model.upsert` to the schema. This method will either update an existing document
|
|
229
234
|
* that matches the conditions or create a new document if none exists. It throws an error if multiple documents
|
|
230
235
|
* match the conditions to prevent ambiguous updates.
|
|
231
236
|
* @param schema Mongoose Schema
|
|
232
237
|
*/
|
|
233
|
-
function
|
|
238
|
+
var upsertPlugin = function (schema) {
|
|
234
239
|
schema.statics.upsert = function (conditions, update) {
|
|
235
240
|
return __awaiter(this, void 0, void 0, function () {
|
|
236
241
|
var docs, doc, combinedData, newDoc;
|
|
@@ -259,7 +264,8 @@ function upsertPlugin(schema) {
|
|
|
259
264
|
});
|
|
260
265
|
});
|
|
261
266
|
};
|
|
262
|
-
}
|
|
267
|
+
};
|
|
268
|
+
exports.upsertPlugin = upsertPlugin;
|
|
263
269
|
var DateOnly = /** @class */ (function (_super) {
|
|
264
270
|
__extends(DateOnly, _super);
|
|
265
271
|
function DateOnly(key, options) {
|
package/dist/populate.test.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
36
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
37
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -53,6 +86,7 @@ var __read = (this && this.__read) || function (o, n) {
|
|
|
53
86
|
};
|
|
54
87
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
88
|
var bun_test_1 = require("bun:test");
|
|
89
|
+
var mongoose_1 = __importStar(require("mongoose"));
|
|
56
90
|
var populate_1 = require("./populate");
|
|
57
91
|
var tests_1 = require("./tests");
|
|
58
92
|
(0, bun_test_1.describe)("populate functions", function () {
|
|
@@ -183,3 +217,68 @@ var tests_1 = require("./tests");
|
|
|
183
217
|
(0, bun_test_1.expect)(result.containers[1].items).toEqual(["item-3", "item-4"]);
|
|
184
218
|
});
|
|
185
219
|
});
|
|
220
|
+
(0, bun_test_1.describe)("fixMixedFields", function () {
|
|
221
|
+
(0, bun_test_1.it)("returns early when schema is missing", function () {
|
|
222
|
+
var properties = { foo: { type: "object" } };
|
|
223
|
+
(0, bun_test_1.expect)(function () { return (0, populate_1.fixMixedFields)(null, properties); }).not.toThrow();
|
|
224
|
+
});
|
|
225
|
+
(0, bun_test_1.it)("returns early when properties is missing", function () {
|
|
226
|
+
var schema = new mongoose_1.Schema({});
|
|
227
|
+
(0, bun_test_1.expect)(function () { return (0, populate_1.fixMixedFields)(schema, null); }).not.toThrow();
|
|
228
|
+
});
|
|
229
|
+
(0, bun_test_1.it)("replaces Mixed fields with only description", function () {
|
|
230
|
+
var schema = new mongoose_1.Schema({ data: { description: "any data", type: mongoose_1.Schema.Types.Mixed } });
|
|
231
|
+
var properties = { data: { description: "any data", type: "object" } };
|
|
232
|
+
(0, populate_1.fixMixedFields)(schema, properties);
|
|
233
|
+
(0, bun_test_1.expect)(properties.data).toEqual({ description: "any data" });
|
|
234
|
+
});
|
|
235
|
+
(0, bun_test_1.it)("recurses into arrays of sub-documents", function () {
|
|
236
|
+
var subSchema = new mongoose_1.Schema({ meta: { type: mongoose_1.Schema.Types.Mixed } });
|
|
237
|
+
var schema = new mongoose_1.Schema({ items: [subSchema] });
|
|
238
|
+
var properties = {
|
|
239
|
+
items: {
|
|
240
|
+
items: {
|
|
241
|
+
properties: {
|
|
242
|
+
meta: { type: "object" },
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
type: "array",
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
(0, populate_1.fixMixedFields)(schema, properties);
|
|
249
|
+
(0, bun_test_1.expect)(properties.items.items.properties.meta).toEqual({ description: undefined });
|
|
250
|
+
});
|
|
251
|
+
(0, bun_test_1.it)("skips unknown paths", function () {
|
|
252
|
+
var schema = new mongoose_1.Schema({ foo: String });
|
|
253
|
+
var properties = { unknownKey: { type: "string" } };
|
|
254
|
+
(0, bun_test_1.expect)(function () { return (0, populate_1.fixMixedFields)(schema, properties); }).not.toThrow();
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
(0, bun_test_1.describe)("getOpenApiSpecForModel edge cases", function () {
|
|
258
|
+
(0, bun_test_1.it)("returns model properties without populatePaths", function () {
|
|
259
|
+
var result = (0, populate_1.getOpenApiSpecForModel)(tests_1.UserModel);
|
|
260
|
+
(0, bun_test_1.expect)(result.properties).toBeDefined();
|
|
261
|
+
});
|
|
262
|
+
(0, bun_test_1.it)("returns with extraModelProperties merged", function () {
|
|
263
|
+
var result = (0, populate_1.getOpenApiSpecForModel)(tests_1.UserModel, {
|
|
264
|
+
extraModelProperties: { customField: { type: "string" } },
|
|
265
|
+
});
|
|
266
|
+
(0, bun_test_1.expect)(result.properties.customField).toEqual({ type: "string" });
|
|
267
|
+
});
|
|
268
|
+
(0, bun_test_1.it)("skips populate paths without ref", function () {
|
|
269
|
+
// Create a schema with a non-referenced ObjectId field
|
|
270
|
+
var testSchema = new mongoose_1.Schema({ name: String, simpleId: mongoose_1.Schema.Types.ObjectId });
|
|
271
|
+
var TestModelNoRef = mongoose_1.default.models.TestModelNoRef || mongoose_1.default.model("TestModelNoRef", testSchema);
|
|
272
|
+
var result = (0, populate_1.getOpenApiSpecForModel)(TestModelNoRef, {
|
|
273
|
+
populatePaths: [{ path: "simpleId" }],
|
|
274
|
+
});
|
|
275
|
+
// Should not throw, simpleId stays as-is
|
|
276
|
+
(0, bun_test_1.expect)(result.properties).toBeDefined();
|
|
277
|
+
});
|
|
278
|
+
(0, bun_test_1.it)("populates with fields allowlist", function () {
|
|
279
|
+
var result = (0, populate_1.getOpenApiSpecForModel)(tests_1.FoodModel, {
|
|
280
|
+
populatePaths: [{ fields: ["name"], path: "ownerId" }],
|
|
281
|
+
});
|
|
282
|
+
(0, bun_test_1.expect)(result.properties).toBeDefined();
|
|
283
|
+
});
|
|
284
|
+
});
|