@terreno/api 0.20.2 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ai/guidelines/core.md +71 -0
- package/.ai/skills/mongoose-schema-safety/SKILL.md +143 -0
- package/README.md +54 -1
- package/bunfig.toml +1 -1
- package/dist/__tests__/versionCheckPlugin.test.js +29 -7
- package/dist/actions.openApi.test.js +13 -11
- package/dist/api.js +98 -11
- package/dist/api.query.test.js +31 -1
- package/dist/api.test.js +211 -0
- package/dist/auth.test.js +418 -43
- package/dist/betterAuth.d.ts +1 -1
- package/dist/consentApp.test.js +1 -0
- package/dist/example.js +4 -4
- package/dist/expressServer.d.ts +0 -22
- package/dist/expressServer.js +1 -125
- package/dist/expressServer.test.js +90 -91
- package/dist/githubAuth.test.js +22 -22
- package/dist/logger.d.ts +154 -0
- package/dist/logger.js +445 -26
- package/dist/logger.test.js +435 -0
- package/dist/middleware.d.ts +7 -0
- package/dist/middleware.js +58 -1
- package/dist/middleware.test.js +159 -0
- package/dist/models/consentForm.js +2 -1
- package/dist/models/consentResponse.js +2 -1
- package/dist/models/versionConfig.js +2 -1
- package/dist/openApi.test.js +10 -17
- package/dist/openApiBuilder.d.ts +18 -0
- package/dist/openApiBuilder.js +21 -0
- package/dist/openApiBuilder.test.js +34 -10
- package/dist/permissions.test.js +10 -43
- package/dist/populate.test.js +10 -42
- package/dist/realtime/changeStreamWatcher.d.ts +4 -4
- package/dist/realtime/changeStreamWatcher.js +2 -4
- package/dist/realtime/queryMatcher.d.ts +1 -1
- package/dist/realtime/queryMatcher.js +39 -14
- package/dist/realtime/types.d.ts +3 -3
- package/dist/requestContext.d.ts +61 -0
- package/dist/requestContext.js +74 -0
- package/dist/secretProviders.test.js +335 -0
- package/dist/syncConsents.test.js +2 -2
- package/dist/terrenoApp.d.ts +27 -15
- package/dist/terrenoApp.js +24 -14
- package/dist/terrenoApp.test.js +52 -0
- package/dist/tests/bunSetup.js +66 -262
- package/dist/tests/createTestData.d.ts +9 -0
- package/dist/tests/createTestData.js +272 -0
- package/dist/tests/models.d.ts +71 -0
- package/dist/tests/models.js +134 -0
- package/dist/tests/mongoTestSetup.d.ts +7 -0
- package/dist/tests/mongoTestSetup.js +150 -0
- package/dist/tests/testEnv.d.ts +0 -0
- package/dist/tests/testEnv.js +6 -0
- package/dist/tests/testHelper.d.ts +22 -0
- package/dist/tests/testHelper.js +115 -0
- package/dist/tests/types.d.ts +29 -0
- package/dist/tests/types.js +2 -0
- package/dist/tests.d.ts +10 -78
- package/dist/tests.js +24 -241
- package/dist/transformers.test.js +14 -50
- package/package.json +18 -4
- package/src/__snapshots__/openApiBuilder.test.ts.snap +1 -0
- package/src/__tests__/versionCheckPlugin.test.ts +43 -15
- package/src/actions.openApi.test.ts +12 -10
- package/src/api.query.test.ts +24 -1
- package/src/api.test.ts +169 -0
- package/src/api.ts +71 -0
- package/src/auth.test.ts +287 -39
- package/src/betterAuth.ts +1 -1
- package/src/consentApp.test.ts +1 -0
- package/src/example.ts +4 -4
- package/src/expressServer.test.ts +82 -85
- package/src/expressServer.ts +1 -213
- package/src/githubAuth.test.ts +22 -22
- package/src/logger.test.ts +466 -1
- package/src/logger.ts +477 -14
- package/src/middleware.test.ts +74 -2
- package/src/middleware.ts +57 -0
- package/src/models/consentForm.ts +3 -4
- package/src/models/consentResponse.ts +6 -4
- package/src/models/versionConfig.ts +3 -4
- package/src/openApi.test.ts +10 -17
- package/src/openApiBuilder.test.ts +27 -10
- package/src/openApiBuilder.ts +24 -0
- package/src/permissions.test.ts +8 -23
- package/src/populate.test.ts +7 -22
- package/src/realtime/changeStreamWatcher.ts +15 -10
- package/src/realtime/queryMatcher.ts +54 -27
- package/src/realtime/types.ts +4 -4
- package/src/requestContext.ts +86 -0
- package/src/secretProviders.test.ts +219 -1
- package/src/syncConsents.test.ts +1 -1
- package/src/terrenoApp.test.ts +38 -0
- package/src/terrenoApp.ts +37 -15
- package/src/tests/bunSetup.ts +22 -236
- package/src/tests/createTestData.ts +176 -0
- package/src/tests/models.ts +164 -0
- package/src/tests/mongoTestSetup.ts +69 -0
- package/src/tests/testEnv.ts +4 -0
- package/src/tests/testHelper.ts +57 -0
- package/src/tests/types.ts +35 -0
- package/src/tests.ts +40 -231
- package/src/transformers.test.ts +11 -30
- package/tsconfig.typedoc.json +4 -0
- package/dist/tests/index.d.ts +0 -1
- package/dist/tests/index.js +0 -17
- package/src/tests/index.ts +0 -1
package/dist/tests.js
CHANGED
|
@@ -1,37 +1,4 @@
|
|
|
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
|
-
})();
|
|
35
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -68,222 +35,38 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
68
35
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
69
36
|
}
|
|
70
37
|
};
|
|
71
|
-
var __read = (this && this.__read) || function (o, n) {
|
|
72
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
73
|
-
if (!m) return o;
|
|
74
|
-
var i = m.call(o), r, ar = [], e;
|
|
75
|
-
try {
|
|
76
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
77
|
-
}
|
|
78
|
-
catch (error) { e = { error: error }; }
|
|
79
|
-
finally {
|
|
80
|
-
try {
|
|
81
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
82
|
-
}
|
|
83
|
-
finally { if (e) throw e.error; }
|
|
84
|
-
}
|
|
85
|
-
return ar;
|
|
86
|
-
};
|
|
87
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
88
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
89
|
-
};
|
|
90
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
91
|
-
exports.
|
|
92
|
-
var
|
|
93
|
-
var mongoose_1 = __importStar(require("mongoose"));
|
|
94
|
-
var passport_local_mongoose_1 = __importDefault(require("passport-local-mongoose"));
|
|
95
|
-
var qs_1 = __importDefault(require("qs"));
|
|
96
|
-
var supertest_1 = __importDefault(require("supertest"));
|
|
97
|
-
var logger_1 = require("./logger");
|
|
39
|
+
exports.loadTestData = exports.authAsUser = exports.getBaseServer = exports.UserModel = exports.setupTestData = exports.setupTestCache = exports.setupDb = exports.SuperUserModel = exports.StaffUserModel = exports.RequiredModel = exports.loadTestDataFromCache = exports.FoodModel = exports.createTestData = void 0;
|
|
40
|
+
var test_1 = require("@terreno/test");
|
|
98
41
|
var openApiCompat_1 = require("./openApiCompat");
|
|
99
|
-
var
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
usernameField: "email",
|
|
114
|
-
});
|
|
115
|
-
// userSchema.plugin(tokenPlugin);
|
|
116
|
-
userSchema.plugin(plugins_1.createdUpdatedPlugin);
|
|
117
|
-
userSchema.plugin(plugins_1.isDisabledPlugin);
|
|
118
|
-
userSchema.methods.postCreate = function (body) {
|
|
119
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
120
|
-
return __generator(this, function (_a) {
|
|
121
|
-
this.age = body.age;
|
|
122
|
-
return [2 /*return*/, this.save()];
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
};
|
|
126
|
-
exports.UserModel = (0, mongoose_1.model)("User", userSchema);
|
|
127
|
-
var superUserSchema = new mongoose_1.Schema({
|
|
128
|
-
superTitle: { description: "The super user's title", required: true, type: String },
|
|
129
|
-
});
|
|
130
|
-
exports.SuperUserModel = exports.UserModel.discriminator("SuperUser", superUserSchema);
|
|
131
|
-
var staffUserSchema = new mongoose_1.Schema({
|
|
132
|
-
department: {
|
|
133
|
-
description: "The department the staff member belongs to",
|
|
134
|
-
required: true,
|
|
135
|
-
type: String,
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
exports.StaffUserModel = exports.UserModel.discriminator("Staff", staffUserSchema);
|
|
139
|
-
var foodCategorySchema = new mongoose_1.Schema({
|
|
140
|
-
name: { description: "The name of the food category", type: String },
|
|
141
|
-
show: { description: "Whether this category is visible", type: Boolean },
|
|
142
|
-
}, { timestamps: { createdAt: "created", updatedAt: "updated" } });
|
|
143
|
-
var likesSchema = new mongoose_1.Schema({
|
|
144
|
-
likes: { description: "Whether the user liked the item", type: Boolean },
|
|
145
|
-
userId: { description: "The user who liked the item", ref: "User", type: "ObjectId" },
|
|
146
|
-
});
|
|
147
|
-
var foodSchema = new mongoose_1.Schema({
|
|
148
|
-
calories: { description: "Number of calories in the food", type: Number },
|
|
149
|
-
categories: { description: "Categories this food belongs to", type: [foodCategorySchema] },
|
|
150
|
-
created: { description: "When this food was created", type: Date },
|
|
151
|
-
eatenBy: [
|
|
152
|
-
{
|
|
153
|
-
description: "Users who have eaten this food",
|
|
154
|
-
ref: "User",
|
|
155
|
-
required: true,
|
|
156
|
-
type: mongoose_1.Schema.Types.ObjectId,
|
|
157
|
-
},
|
|
158
|
-
],
|
|
159
|
-
// biome-ignore lint/suspicious/noExplicitAny: DateOnly is a custom SchemaType not recognized by Mongoose's built-in type definitions
|
|
160
|
-
expiration: { description: "Expiration date of the food", type: plugins_1.DateOnly },
|
|
161
|
-
hidden: {
|
|
162
|
-
default: false,
|
|
163
|
-
description: "Whether this food is hidden from listings",
|
|
164
|
-
type: Boolean,
|
|
165
|
-
},
|
|
166
|
-
lastEatenWith: {
|
|
167
|
-
description: "Map of user names to dates they last ate this food with",
|
|
168
|
-
of: Date,
|
|
169
|
-
type: Map,
|
|
170
|
-
},
|
|
171
|
-
likesIds: { description: "User likes for this food", required: true, type: [likesSchema] },
|
|
172
|
-
name: { description: "The name of the food", type: String },
|
|
173
|
-
ownerId: { description: "The user who owns this food entry", ref: "User", type: "ObjectId" },
|
|
174
|
-
source: {
|
|
175
|
-
dateAdded: { description: "When the source was added", type: String },
|
|
176
|
-
href: { description: "URL of the source", type: String },
|
|
177
|
-
name: { description: "Name of the source", type: String },
|
|
178
|
-
},
|
|
179
|
-
tags: { description: "Tags associated with this food", type: [String] },
|
|
180
|
-
}, { strict: "throw", toJSON: { virtuals: true }, toObject: { virtuals: true } });
|
|
181
|
-
foodSchema.virtual("description").get(function () {
|
|
182
|
-
return "".concat(this.name, " has ").concat(this.calories, " calories");
|
|
183
|
-
});
|
|
184
|
-
exports.FoodModel = (0, mongoose_1.model)("Food", foodSchema);
|
|
185
|
-
var requiredSchema = new mongoose_1.Schema({
|
|
186
|
-
about: { description: "Information about the item", type: String },
|
|
187
|
-
name: { description: "The name of the item", required: true, type: String },
|
|
188
|
-
});
|
|
189
|
-
exports.RequiredModel = (0, mongoose_1.model)("Required", requiredSchema);
|
|
42
|
+
var createTestData_1 = require("./tests/createTestData");
|
|
43
|
+
Object.defineProperty(exports, "createTestData", { enumerable: true, get: function () { return createTestData_1.createTestData; } });
|
|
44
|
+
var models_1 = require("./tests/models");
|
|
45
|
+
Object.defineProperty(exports, "FoodModel", { enumerable: true, get: function () { return models_1.FoodModel; } });
|
|
46
|
+
Object.defineProperty(exports, "RequiredModel", { enumerable: true, get: function () { return models_1.RequiredModel; } });
|
|
47
|
+
Object.defineProperty(exports, "StaffUserModel", { enumerable: true, get: function () { return models_1.StaffUserModel; } });
|
|
48
|
+
Object.defineProperty(exports, "SuperUserModel", { enumerable: true, get: function () { return models_1.SuperUserModel; } });
|
|
49
|
+
Object.defineProperty(exports, "UserModel", { enumerable: true, get: function () { return models_1.UserModel; } });
|
|
50
|
+
var mongoTestSetup_1 = require("./tests/mongoTestSetup");
|
|
51
|
+
Object.defineProperty(exports, "loadTestDataFromCache", { enumerable: true, get: function () { return mongoTestSetup_1.loadTestDataFromCache; } });
|
|
52
|
+
Object.defineProperty(exports, "setupTestCache", { enumerable: true, get: function () { return mongoTestSetup_1.setupTestCache; } });
|
|
53
|
+
var testHelper_1 = require("./tests/testHelper");
|
|
54
|
+
Object.defineProperty(exports, "setupDb", { enumerable: true, get: function () { return testHelper_1.setupDb; } });
|
|
55
|
+
Object.defineProperty(exports, "setupTestData", { enumerable: true, get: function () { return testHelper_1.setupTestData; } });
|
|
190
56
|
var getBaseServer = function () {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
// Express 5 defaults to 'simple' query parser (Node querystring) which doesn't
|
|
194
|
-
// support nested bracket notation like name[$regex]=Green. Use qs to match
|
|
195
|
-
// what setupServer() configures.
|
|
196
|
-
app.set("query parser", function (str) { return qs_1.default.parse(str, { arrayLimit: 200 }); });
|
|
197
|
-
// Record mount paths on layers for Express 5 → OpenAPI compat
|
|
198
|
-
(0, openApiCompat_1.patchAppUse)(app);
|
|
199
|
-
app.use(function (req, res, next) {
|
|
200
|
-
res.header("Access-Control-Allow-Origin", "*");
|
|
201
|
-
res.header("Access-Control-Allow-Headers", "*");
|
|
202
|
-
// intercepts OPTIONS method
|
|
203
|
-
if (req.method === "OPTIONS") {
|
|
204
|
-
res.send(200);
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
next();
|
|
208
|
-
}
|
|
57
|
+
return (0, test_1.getBaseServer)({
|
|
58
|
+
patchOpenApiCompat: openApiCompat_1.patchAppUse,
|
|
209
59
|
});
|
|
210
|
-
app.use(express_1.default.json());
|
|
211
|
-
return app;
|
|
212
60
|
};
|
|
213
61
|
exports.getBaseServer = getBaseServer;
|
|
214
62
|
var authAsUser = function (app, type) { return __awaiter(void 0, void 0, void 0, function () {
|
|
215
|
-
var email, password
|
|
63
|
+
var email, password;
|
|
216
64
|
return __generator(this, function (_a) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
password = type === "admin" ? "securePassword" : "password";
|
|
221
|
-
agent = supertest_1.default.agent(app);
|
|
222
|
-
return [4 /*yield*/, agent.post("/auth/login").send({ email: email, password: password }).expect(200)];
|
|
223
|
-
case 1:
|
|
224
|
-
res = _a.sent();
|
|
225
|
-
return [4 /*yield*/, agent.set("authorization", "Bearer ".concat(res.body.data.token))];
|
|
226
|
-
case 2:
|
|
227
|
-
_a.sent();
|
|
228
|
-
return [2 /*return*/, agent];
|
|
229
|
-
}
|
|
65
|
+
email = type === "admin" ? "admin@example.com" : "notAdmin@example.com";
|
|
66
|
+
password = type === "admin" ? "securePassword" : "password";
|
|
67
|
+
return [2 /*return*/, (0, test_1.authAsUser)(app, { email: email, password: password })];
|
|
230
68
|
});
|
|
231
69
|
}); };
|
|
232
70
|
exports.authAsUser = authAsUser;
|
|
233
|
-
var
|
|
234
|
-
|
|
235
|
-
return __generator(this, function (_b) {
|
|
236
|
-
switch (_b.label) {
|
|
237
|
-
case 0: return [4 /*yield*/, mongoose_1.default
|
|
238
|
-
.connect("mongodb://127.0.0.1/terreno?&connectTimeoutMS=360000")
|
|
239
|
-
.catch(logger_1.logger.catch)];
|
|
240
|
-
case 1:
|
|
241
|
-
_b.sent();
|
|
242
|
-
process.env.REFRESH_TOKEN_SECRET = "refresh_secret";
|
|
243
|
-
process.env.TOKEN_SECRET = "secret";
|
|
244
|
-
process.env.TOKEN_EXPIRES_IN = "30m";
|
|
245
|
-
process.env.TOKEN_ISSUER = "example.com";
|
|
246
|
-
process.env.SESSION_SECRET = "session";
|
|
247
|
-
// Broken out of the try/catch below so you can test the catch logger by shutting down mongo.
|
|
248
|
-
return [4 /*yield*/, Promise.all([exports.UserModel.deleteMany({}), exports.FoodModel.deleteMany({})]).catch(logger_1.logger.catch)];
|
|
249
|
-
case 2:
|
|
250
|
-
// Broken out of the try/catch below so you can test the catch logger by shutting down mongo.
|
|
251
|
-
_b.sent();
|
|
252
|
-
_b.label = 3;
|
|
253
|
-
case 3:
|
|
254
|
-
_b.trys.push([3, 11, , 12]);
|
|
255
|
-
return [4 /*yield*/, Promise.all([
|
|
256
|
-
exports.UserModel.create({ email: "notAdmin@example.com", name: "Not Admin" }),
|
|
257
|
-
exports.UserModel.create({ admin: true, email: "admin@example.com", name: "Admin" }),
|
|
258
|
-
exports.UserModel.create({ admin: true, email: "admin+other@example.com", name: "Admin Other" }),
|
|
259
|
-
])];
|
|
260
|
-
case 4:
|
|
261
|
-
_a = __read.apply(void 0, [_b.sent(), 3]), notAdmin = _a[0], admin = _a[1], adminOther = _a[2];
|
|
262
|
-
return [4 /*yield*/, notAdmin.setPassword("password")];
|
|
263
|
-
case 5:
|
|
264
|
-
_b.sent();
|
|
265
|
-
return [4 /*yield*/, notAdmin.save()];
|
|
266
|
-
case 6:
|
|
267
|
-
_b.sent();
|
|
268
|
-
return [4 /*yield*/, admin.setPassword("securePassword")];
|
|
269
|
-
case 7:
|
|
270
|
-
_b.sent();
|
|
271
|
-
return [4 /*yield*/, admin.save()];
|
|
272
|
-
case 8:
|
|
273
|
-
_b.sent();
|
|
274
|
-
return [4 /*yield*/, adminOther.setPassword("otherPassword")];
|
|
275
|
-
case 9:
|
|
276
|
-
_b.sent();
|
|
277
|
-
return [4 /*yield*/, adminOther.save()];
|
|
278
|
-
case 10:
|
|
279
|
-
_b.sent();
|
|
280
|
-
return [2 /*return*/, [admin, notAdmin, adminOther]];
|
|
281
|
-
case 11:
|
|
282
|
-
error_1 = _b.sent();
|
|
283
|
-
logger_1.logger.error("Error setting up DB", error_1);
|
|
284
|
-
throw error_1;
|
|
285
|
-
case 12: return [2 /*return*/];
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
}); };
|
|
289
|
-
exports.setupDb = setupDb;
|
|
71
|
+
var mongoTestSetup_2 = require("./tests/mongoTestSetup");
|
|
72
|
+
Object.defineProperty(exports, "loadTestData", { enumerable: true, get: function () { return mongoTestSetup_2.loadTestData; } });
|
|
@@ -46,22 +46,6 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
46
46
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
47
|
}
|
|
48
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
49
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
66
50
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
67
51
|
};
|
|
@@ -81,37 +65,16 @@ var transformers_1 = require("./transformers");
|
|
|
81
65
|
var server;
|
|
82
66
|
var app;
|
|
83
67
|
(0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
84
|
-
var
|
|
85
|
-
return __generator(this, function (
|
|
86
|
-
switch (
|
|
68
|
+
var testData;
|
|
69
|
+
return __generator(this, function (_a) {
|
|
70
|
+
switch (_a.label) {
|
|
87
71
|
case 0:
|
|
88
72
|
process.env.REFRESH_TOKEN_SECRET = "testsecret1234";
|
|
89
|
-
return [4 /*yield*/, (0, tests_1.
|
|
73
|
+
return [4 /*yield*/, (0, tests_1.setupTestData)()];
|
|
90
74
|
case 1:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
calories: 1,
|
|
95
|
-
created: new Date(),
|
|
96
|
-
name: "Spinach",
|
|
97
|
-
ownerId: notAdmin._id,
|
|
98
|
-
}),
|
|
99
|
-
tests_1.FoodModel.create({
|
|
100
|
-
calories: 100,
|
|
101
|
-
created: Date.now() - 10,
|
|
102
|
-
hidden: true,
|
|
103
|
-
name: "Apple",
|
|
104
|
-
ownerId: admin._id,
|
|
105
|
-
}),
|
|
106
|
-
tests_1.FoodModel.create({
|
|
107
|
-
calories: 100,
|
|
108
|
-
created: Date.now() - 10,
|
|
109
|
-
name: "Carrots",
|
|
110
|
-
ownerId: admin._id,
|
|
111
|
-
}),
|
|
112
|
-
])];
|
|
113
|
-
case 2:
|
|
114
|
-
_b.sent();
|
|
75
|
+
testData = _a.sent();
|
|
76
|
+
admin = testData.users.admin;
|
|
77
|
+
notAdmin = testData.users.notAdmin;
|
|
115
78
|
app = (0, tests_1.getBaseServer)();
|
|
116
79
|
(0, auth_1.setupAuth)(app, tests_1.UserModel);
|
|
117
80
|
(0, auth_1.addAuthRoutes)(app, tests_1.UserModel);
|
|
@@ -156,7 +119,7 @@ var transformers_1 = require("./transformers");
|
|
|
156
119
|
return [4 /*yield*/, agent.get("/food").expect(200)];
|
|
157
120
|
case 2:
|
|
158
121
|
foodRes = _a.sent();
|
|
159
|
-
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(
|
|
122
|
+
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(3);
|
|
160
123
|
return [2 /*return*/];
|
|
161
124
|
}
|
|
162
125
|
});
|
|
@@ -171,7 +134,7 @@ var transformers_1 = require("./transformers");
|
|
|
171
134
|
return [4 /*yield*/, agent.get("/food").expect(200)];
|
|
172
135
|
case 2:
|
|
173
136
|
foodRes = _a.sent();
|
|
174
|
-
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(
|
|
137
|
+
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(4);
|
|
175
138
|
return [2 /*return*/];
|
|
176
139
|
}
|
|
177
140
|
});
|
|
@@ -186,7 +149,7 @@ var transformers_1 = require("./transformers");
|
|
|
186
149
|
return [4 /*yield*/, agent.get("/food").expect(200)];
|
|
187
150
|
case 2:
|
|
188
151
|
foodRes = _a.sent();
|
|
189
|
-
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(
|
|
152
|
+
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(4);
|
|
190
153
|
spinach = foodRes.body.data.find(function (food) { return food.name === "Spinach"; });
|
|
191
154
|
(0, bun_test_1.expect)(spinach.created).toBeDefined();
|
|
192
155
|
(0, bun_test_1.expect)(spinach.id).toBeDefined();
|
|
@@ -227,7 +190,7 @@ var transformers_1 = require("./transformers");
|
|
|
227
190
|
return [4 /*yield*/, agent.get("/food").expect(200)];
|
|
228
191
|
case 2:
|
|
229
192
|
foodRes = _a.sent();
|
|
230
|
-
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(
|
|
193
|
+
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(3);
|
|
231
194
|
spinach = foodRes.body.data.find(function (food) { return food.name === "Spinach"; });
|
|
232
195
|
(0, bun_test_1.expect)(spinach.id).toBeDefined();
|
|
233
196
|
(0, bun_test_1.expect)(spinach.name).toBe("Spinach");
|
|
@@ -289,7 +252,7 @@ var transformers_1 = require("./transformers");
|
|
|
289
252
|
return [4 /*yield*/, agent.get("/food").expect(200)];
|
|
290
253
|
case 2:
|
|
291
254
|
foodRes = _a.sent();
|
|
292
|
-
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(
|
|
255
|
+
(0, bun_test_1.expect)(foodRes.body.data).toHaveLength(3);
|
|
293
256
|
spinach = foodRes.body.data.find(function (food) { return food.name === "Spinach"; });
|
|
294
257
|
(0, bun_test_1.expect)(spinach.id).toBeDefined();
|
|
295
258
|
(0, bun_test_1.expect)(spinach.name).toBe("Spinach");
|
|
@@ -358,9 +321,10 @@ var transformers_1 = require("./transformers");
|
|
|
358
321
|
case 0: return [4 /*yield*/, server.get("/food")];
|
|
359
322
|
case 1:
|
|
360
323
|
res = _a.sent();
|
|
361
|
-
(0, bun_test_1.expect)(res.body.data).toHaveLength(
|
|
324
|
+
(0, bun_test_1.expect)(res.body.data).toHaveLength(3);
|
|
362
325
|
(0, bun_test_1.expect)(res.body.data.find(function (f) { return f.name === "Spinach"; })).toBeDefined();
|
|
363
326
|
(0, bun_test_1.expect)(res.body.data.find(function (f) { return f.name === "Carrots"; })).toBeDefined();
|
|
327
|
+
(0, bun_test_1.expect)(res.body.data.find(function (f) { return f.name === "Pizza"; })).toBeDefined();
|
|
364
328
|
return [2 /*return*/];
|
|
365
329
|
}
|
|
366
330
|
});
|
package/package.json
CHANGED
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"description": "Styled after the Django & Django REST Framework, a batteries-include framework for building REST APIs with Node/Express/Mongoose.",
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@biomejs/biome": "^2.3.6",
|
|
49
|
+
"@terreno/test": "workspace:*",
|
|
49
50
|
"@types/bcrypt": "^6.0.0",
|
|
50
51
|
"@types/bun": "^1.2.4",
|
|
51
52
|
"@types/cors": "^2.8.17",
|
|
@@ -80,6 +81,16 @@
|
|
|
80
81
|
],
|
|
81
82
|
"license": "Apache-2.0",
|
|
82
83
|
"main": "dist/index.js",
|
|
84
|
+
"exports": {
|
|
85
|
+
".": {
|
|
86
|
+
"types": "./dist/index.d.ts",
|
|
87
|
+
"default": "./dist/index.js"
|
|
88
|
+
},
|
|
89
|
+
"./testing": {
|
|
90
|
+
"types": "./dist/tests.d.ts",
|
|
91
|
+
"default": "./dist/tests.js"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
83
94
|
"name": "@terreno/api",
|
|
84
95
|
"publishConfig": {
|
|
85
96
|
"access": "public"
|
|
@@ -96,18 +107,21 @@
|
|
|
96
107
|
"json5": "2.2.3"
|
|
97
108
|
},
|
|
98
109
|
"scripts": {
|
|
99
|
-
"compile": "bun tsc",
|
|
110
|
+
"compile": "node ../.github/scripts/compile-workspace-deps.js && bun tsc",
|
|
100
111
|
"compile:watch": "bun tsc -w",
|
|
101
112
|
"dev": "bun tsc -w",
|
|
102
113
|
"docs": "typedoc --out docs src/index.ts",
|
|
103
114
|
"lint": "biome check ./src",
|
|
104
115
|
"lint:fix": "biome check --write ./src",
|
|
105
116
|
"lint:unsafefix": "biome check --fix --unsafe ./src",
|
|
106
|
-
"test": "bun test --
|
|
107
|
-
"test:ci": "bun test
|
|
117
|
+
"test": "bun test --update-snapshots",
|
|
118
|
+
"test:ci": "bun test",
|
|
108
119
|
"test:coverage": "bun run ../scripts/check-coverage.ts",
|
|
120
|
+
"test:cache:clean": "bun ./src/tests/mongoTestSetup.ts clean",
|
|
121
|
+
"test:cache:setup": "bun ./src/tests/mongoTestSetup.ts setup",
|
|
122
|
+
"test:cache:status": "bun ./src/tests/mongoTestSetup.ts status",
|
|
109
123
|
"updateSnapshot": "bun test --update-snapshots"
|
|
110
124
|
},
|
|
111
125
|
"types": "dist/index.d.ts",
|
|
112
|
-
"version": "0.
|
|
126
|
+
"version": "0.22.0"
|
|
113
127
|
}
|
|
@@ -910,6 +910,7 @@ exports[`OpenApiMiddlewareBuilder snapshot tests matches OpenAPI spec snapshot 1
|
|
|
910
910
|
"/food/stats": {
|
|
911
911
|
"get": {
|
|
912
912
|
"description": "Returns aggregated statistics about food items",
|
|
913
|
+
"operationId": "getFoodStats",
|
|
913
914
|
"parameters": [
|
|
914
915
|
{
|
|
915
916
|
"description": "Filter by food category",
|
|
@@ -30,19 +30,27 @@ describe("VersionCheckPlugin", () => {
|
|
|
30
30
|
it("returns ok when no VersionConfig exists", async () => {
|
|
31
31
|
const res = await app.get("/version-check").query({platform: "web", version: 100});
|
|
32
32
|
expect(res.status).toBe(200);
|
|
33
|
-
expect(res.body).
|
|
33
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
34
|
+
expect(res.body).toEqual(
|
|
35
|
+
expect.objectContaining({
|
|
36
|
+
pollingIntervalMs: 86400000,
|
|
37
|
+
status: "ok",
|
|
38
|
+
})
|
|
39
|
+
);
|
|
34
40
|
});
|
|
35
41
|
|
|
36
42
|
it("returns ok when version param is missing", async () => {
|
|
37
43
|
const res = await app.get("/version-check");
|
|
38
44
|
expect(res.status).toBe(200);
|
|
39
|
-
expect(res.body).
|
|
45
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
46
|
+
expect(res.body).toEqual(expect.objectContaining({status: "ok"}));
|
|
40
47
|
});
|
|
41
48
|
|
|
42
49
|
it("returns ok when version param is invalid", async () => {
|
|
43
50
|
const res = await app.get("/version-check").query({platform: "web", version: "invalid"});
|
|
44
51
|
expect(res.status).toBe(200);
|
|
45
|
-
expect(res.body).
|
|
52
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
53
|
+
expect(res.body).toEqual(expect.objectContaining({status: "ok"}));
|
|
46
54
|
});
|
|
47
55
|
|
|
48
56
|
it("returns ok when client version >= warning and required (web)", async () => {
|
|
@@ -53,12 +61,15 @@ describe("VersionCheckPlugin", () => {
|
|
|
53
61
|
|
|
54
62
|
const res = await app.get("/version-check").query({platform: "web", version: 150});
|
|
55
63
|
expect(res.status).toBe(200);
|
|
56
|
-
expect(res.body).
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
65
|
+
expect(res.body).toEqual(
|
|
66
|
+
expect.objectContaining({
|
|
67
|
+
pollingIntervalMs: 86400000,
|
|
68
|
+
requiredVersion: 50,
|
|
69
|
+
status: "ok",
|
|
70
|
+
warningVersion: 100,
|
|
71
|
+
})
|
|
72
|
+
);
|
|
62
73
|
});
|
|
63
74
|
|
|
64
75
|
it("returns warning when client version < warning (web)", async () => {
|
|
@@ -70,6 +81,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
70
81
|
|
|
71
82
|
const res = await app.get("/version-check").query({platform: "web", version: 80});
|
|
72
83
|
expect(res.status).toBe(200);
|
|
84
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
73
85
|
expect(res.body.status).toBe("warning");
|
|
74
86
|
expect(res.body.message).toBe("Please update!");
|
|
75
87
|
});
|
|
@@ -84,6 +96,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
84
96
|
|
|
85
97
|
const res = await app.get("/version-check").query({platform: "web", version: 50});
|
|
86
98
|
expect(res.status).toBe(200);
|
|
99
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
87
100
|
expect(res.body.status).toBe("required");
|
|
88
101
|
expect(res.body.message).toBe("Update required");
|
|
89
102
|
expect(res.body.updateUrl).toBe("https://example.com/update");
|
|
@@ -98,9 +111,11 @@ describe("VersionCheckPlugin", () => {
|
|
|
98
111
|
});
|
|
99
112
|
|
|
100
113
|
const webRes = await app.get("/version-check").query({platform: "web", version: 100});
|
|
114
|
+
expect(webRes.body.requestId).toBe(webRes.headers["x-request-id"]);
|
|
101
115
|
expect(webRes.body.status).toBe("ok");
|
|
102
116
|
|
|
103
117
|
const mobileRes = await app.get("/version-check").query({platform: "mobile", version: 100});
|
|
118
|
+
expect(mobileRes.body.requestId).toBe(mobileRes.headers["x-request-id"]);
|
|
104
119
|
expect(mobileRes.body.status).toBe("required");
|
|
105
120
|
});
|
|
106
121
|
|
|
@@ -111,6 +126,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
111
126
|
});
|
|
112
127
|
|
|
113
128
|
const res = await app.get("/version-check").query({platform: "invalid", version: 50});
|
|
129
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
114
130
|
expect(res.body.status).toBe("required");
|
|
115
131
|
});
|
|
116
132
|
|
|
@@ -122,12 +138,15 @@ describe("VersionCheckPlugin", () => {
|
|
|
122
138
|
|
|
123
139
|
const res = await app.get("/version-check").query({platform: "web", version: 100});
|
|
124
140
|
expect(res.status).toBe(200);
|
|
125
|
-
expect(res.body).
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
142
|
+
expect(res.body).toEqual(
|
|
143
|
+
expect.objectContaining({
|
|
144
|
+
pollingIntervalMs: 86400000,
|
|
145
|
+
requiredVersion: 50,
|
|
146
|
+
status: "ok",
|
|
147
|
+
warningVersion: 100,
|
|
148
|
+
})
|
|
149
|
+
);
|
|
131
150
|
});
|
|
132
151
|
|
|
133
152
|
it("returns pollingIntervalMs from config pollingIntervalMinutes", async () => {
|
|
@@ -139,6 +158,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
139
158
|
|
|
140
159
|
const res = await app.get("/version-check").query({platform: "web", version: 100});
|
|
141
160
|
expect(res.status).toBe(200);
|
|
161
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
142
162
|
expect(res.body.pollingIntervalMs).toBe(3600000);
|
|
143
163
|
});
|
|
144
164
|
|
|
@@ -150,6 +170,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
150
170
|
|
|
151
171
|
const res = await app.get("/version-check").query({platform: "web", version: 100});
|
|
152
172
|
expect(res.status).toBe(200);
|
|
173
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
153
174
|
expect(res.body.pollingIntervalMs).toBe(86400000);
|
|
154
175
|
});
|
|
155
176
|
|
|
@@ -161,6 +182,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
161
182
|
|
|
162
183
|
const res = await app.get("/version-check?version=50&platform=web");
|
|
163
184
|
expect(res.status).toBe(200);
|
|
185
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
164
186
|
expect(res.body.status).toBe("required");
|
|
165
187
|
});
|
|
166
188
|
|
|
@@ -172,6 +194,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
172
194
|
|
|
173
195
|
const res = await app.get("/version-check").query({platform: "web", version: 50});
|
|
174
196
|
expect(res.status).toBe(200);
|
|
197
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
175
198
|
expect(res.body.status).toBe("warning");
|
|
176
199
|
expect(res.body.message).toBe(
|
|
177
200
|
"A new version is available. Please update for the best experience."
|
|
@@ -186,6 +209,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
186
209
|
|
|
187
210
|
const res = await app.get("/version-check").query({platform: "web", version: 50});
|
|
188
211
|
expect(res.status).toBe(200);
|
|
212
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
189
213
|
expect(res.body.status).toBe("required");
|
|
190
214
|
expect(res.body.message).toBe(
|
|
191
215
|
"This version is no longer supported. Please update to continue."
|
|
@@ -200,6 +224,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
200
224
|
|
|
201
225
|
const res = await app.get("/version-check").query({platform: "web", version: 100});
|
|
202
226
|
expect(res.status).toBe(200);
|
|
227
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
203
228
|
expect(res.body.status).toBe("warning");
|
|
204
229
|
});
|
|
205
230
|
|
|
@@ -210,12 +235,14 @@ describe("VersionCheckPlugin", () => {
|
|
|
210
235
|
});
|
|
211
236
|
|
|
212
237
|
const warningRes = await app.get("/version-check").query({platform: "web", version: 150});
|
|
238
|
+
expect(warningRes.body.requestId).toBe(warningRes.headers["x-request-id"]);
|
|
213
239
|
expect(warningRes.body.status).toBe("warning");
|
|
214
240
|
expect(warningRes.body.message).toBe(
|
|
215
241
|
"A new version is available. Please update for the best experience."
|
|
216
242
|
);
|
|
217
243
|
|
|
218
244
|
const requiredRes = await app.get("/version-check").query({platform: "web", version: 50});
|
|
245
|
+
expect(requiredRes.body.requestId).toBe(requiredRes.headers["x-request-id"]);
|
|
219
246
|
expect(requiredRes.body.status).toBe("required");
|
|
220
247
|
expect(requiredRes.body.message).toBe(
|
|
221
248
|
"This version is no longer supported. Please update to continue."
|
|
@@ -225,6 +252,7 @@ describe("VersionCheckPlugin", () => {
|
|
|
225
252
|
it("handles numeric version parameter", async () => {
|
|
226
253
|
const res = await app.get("/version-check?version=50&platform=web");
|
|
227
254
|
expect(res.status).toBe(200);
|
|
255
|
+
expect(res.body.requestId).toBe(res.headers["x-request-id"]);
|
|
228
256
|
});
|
|
229
257
|
});
|
|
230
258
|
|