@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.
Files changed (107) hide show
  1. package/.ai/guidelines/core.md +71 -0
  2. package/.ai/skills/mongoose-schema-safety/SKILL.md +143 -0
  3. package/README.md +54 -1
  4. package/bunfig.toml +1 -1
  5. package/dist/__tests__/versionCheckPlugin.test.js +29 -7
  6. package/dist/actions.openApi.test.js +13 -11
  7. package/dist/api.js +98 -11
  8. package/dist/api.query.test.js +31 -1
  9. package/dist/api.test.js +211 -0
  10. package/dist/auth.test.js +418 -43
  11. package/dist/betterAuth.d.ts +1 -1
  12. package/dist/consentApp.test.js +1 -0
  13. package/dist/example.js +4 -4
  14. package/dist/expressServer.d.ts +0 -22
  15. package/dist/expressServer.js +1 -125
  16. package/dist/expressServer.test.js +90 -91
  17. package/dist/githubAuth.test.js +22 -22
  18. package/dist/logger.d.ts +154 -0
  19. package/dist/logger.js +445 -26
  20. package/dist/logger.test.js +435 -0
  21. package/dist/middleware.d.ts +7 -0
  22. package/dist/middleware.js +58 -1
  23. package/dist/middleware.test.js +159 -0
  24. package/dist/models/consentForm.js +2 -1
  25. package/dist/models/consentResponse.js +2 -1
  26. package/dist/models/versionConfig.js +2 -1
  27. package/dist/openApi.test.js +10 -17
  28. package/dist/openApiBuilder.d.ts +18 -0
  29. package/dist/openApiBuilder.js +21 -0
  30. package/dist/openApiBuilder.test.js +34 -10
  31. package/dist/permissions.test.js +10 -43
  32. package/dist/populate.test.js +10 -42
  33. package/dist/realtime/changeStreamWatcher.d.ts +4 -4
  34. package/dist/realtime/changeStreamWatcher.js +2 -4
  35. package/dist/realtime/queryMatcher.d.ts +1 -1
  36. package/dist/realtime/queryMatcher.js +39 -14
  37. package/dist/realtime/types.d.ts +3 -3
  38. package/dist/requestContext.d.ts +61 -0
  39. package/dist/requestContext.js +74 -0
  40. package/dist/secretProviders.test.js +335 -0
  41. package/dist/syncConsents.test.js +2 -2
  42. package/dist/terrenoApp.d.ts +27 -15
  43. package/dist/terrenoApp.js +24 -14
  44. package/dist/terrenoApp.test.js +52 -0
  45. package/dist/tests/bunSetup.js +66 -262
  46. package/dist/tests/createTestData.d.ts +9 -0
  47. package/dist/tests/createTestData.js +272 -0
  48. package/dist/tests/models.d.ts +71 -0
  49. package/dist/tests/models.js +134 -0
  50. package/dist/tests/mongoTestSetup.d.ts +7 -0
  51. package/dist/tests/mongoTestSetup.js +150 -0
  52. package/dist/tests/testEnv.d.ts +0 -0
  53. package/dist/tests/testEnv.js +6 -0
  54. package/dist/tests/testHelper.d.ts +22 -0
  55. package/dist/tests/testHelper.js +115 -0
  56. package/dist/tests/types.d.ts +29 -0
  57. package/dist/tests/types.js +2 -0
  58. package/dist/tests.d.ts +10 -78
  59. package/dist/tests.js +24 -241
  60. package/dist/transformers.test.js +14 -50
  61. package/package.json +18 -4
  62. package/src/__snapshots__/openApiBuilder.test.ts.snap +1 -0
  63. package/src/__tests__/versionCheckPlugin.test.ts +43 -15
  64. package/src/actions.openApi.test.ts +12 -10
  65. package/src/api.query.test.ts +24 -1
  66. package/src/api.test.ts +169 -0
  67. package/src/api.ts +71 -0
  68. package/src/auth.test.ts +287 -39
  69. package/src/betterAuth.ts +1 -1
  70. package/src/consentApp.test.ts +1 -0
  71. package/src/example.ts +4 -4
  72. package/src/expressServer.test.ts +82 -85
  73. package/src/expressServer.ts +1 -213
  74. package/src/githubAuth.test.ts +22 -22
  75. package/src/logger.test.ts +466 -1
  76. package/src/logger.ts +477 -14
  77. package/src/middleware.test.ts +74 -2
  78. package/src/middleware.ts +57 -0
  79. package/src/models/consentForm.ts +3 -4
  80. package/src/models/consentResponse.ts +6 -4
  81. package/src/models/versionConfig.ts +3 -4
  82. package/src/openApi.test.ts +10 -17
  83. package/src/openApiBuilder.test.ts +27 -10
  84. package/src/openApiBuilder.ts +24 -0
  85. package/src/permissions.test.ts +8 -23
  86. package/src/populate.test.ts +7 -22
  87. package/src/realtime/changeStreamWatcher.ts +15 -10
  88. package/src/realtime/queryMatcher.ts +54 -27
  89. package/src/realtime/types.ts +4 -4
  90. package/src/requestContext.ts +86 -0
  91. package/src/secretProviders.test.ts +219 -1
  92. package/src/syncConsents.test.ts +1 -1
  93. package/src/terrenoApp.test.ts +38 -0
  94. package/src/terrenoApp.ts +37 -15
  95. package/src/tests/bunSetup.ts +22 -236
  96. package/src/tests/createTestData.ts +176 -0
  97. package/src/tests/models.ts +164 -0
  98. package/src/tests/mongoTestSetup.ts +69 -0
  99. package/src/tests/testEnv.ts +4 -0
  100. package/src/tests/testHelper.ts +57 -0
  101. package/src/tests/types.ts +35 -0
  102. package/src/tests.ts +40 -231
  103. package/src/transformers.test.ts +11 -30
  104. package/tsconfig.typedoc.json +4 -0
  105. package/dist/tests/index.d.ts +0 -1
  106. package/dist/tests/index.js +0 -17
  107. package/src/tests/index.ts +0 -1
@@ -0,0 +1,71 @@
1
+ import mongoose, { type Model, Schema } from "mongoose";
2
+ export interface User {
3
+ admin: boolean;
4
+ name?: string;
5
+ username: string;
6
+ email: string;
7
+ age?: number;
8
+ disabled?: boolean;
9
+ }
10
+ export interface SuperUser extends User {
11
+ superTitle: string;
12
+ }
13
+ export interface StaffUser extends User {
14
+ department: string;
15
+ }
16
+ export interface FoodCategory {
17
+ _id?: string;
18
+ name: string;
19
+ show: boolean;
20
+ created: Date;
21
+ updated: Date;
22
+ }
23
+ export interface Food {
24
+ _id: string;
25
+ name: string;
26
+ calories: number;
27
+ created: Date;
28
+ ownerId: mongoose.Types.ObjectId | User;
29
+ hidden?: boolean;
30
+ source: {
31
+ name: string;
32
+ href?: string;
33
+ dateAdded?: string;
34
+ };
35
+ tags: string[];
36
+ eatenBy: [Schema.Types.ObjectId | User];
37
+ lastEatenWith: {
38
+ [name: string]: Date;
39
+ };
40
+ categories: FoodCategory[];
41
+ expiration: string;
42
+ likesIds: {
43
+ userId: string;
44
+ likes: boolean;
45
+ }[];
46
+ }
47
+ export interface RequiredField {
48
+ name: string;
49
+ about?: string;
50
+ }
51
+ export declare const UserModel: mongoose.Model<User, {}, {}, {}, mongoose.Document<unknown, {}, User, {}, {}> & User & {
52
+ _id: mongoose.Types.ObjectId;
53
+ } & {
54
+ __v: number;
55
+ }, any>;
56
+ export declare const SuperUserModel: mongoose.Model<User & SuperUser, {}, {}, {}, mongoose.Document<unknown, {}, User & SuperUser, {}, {}> & User & SuperUser & {
57
+ _id: mongoose.Types.ObjectId;
58
+ } & {
59
+ __v: number;
60
+ }, any>;
61
+ export declare const StaffUserModel: mongoose.Model<User & StaffUser, {}, {}, {}, mongoose.Document<unknown, {}, User & StaffUser, {}, {}> & User & StaffUser & {
62
+ _id: mongoose.Types.ObjectId;
63
+ } & {
64
+ __v: number;
65
+ }, any>;
66
+ export declare const FoodModel: Model<Food>;
67
+ export declare const RequiredModel: mongoose.Model<RequiredField, {}, {}, {}, mongoose.Document<unknown, {}, RequiredField, {}, {}> & RequiredField & {
68
+ _id: mongoose.Types.ObjectId;
69
+ } & {
70
+ __v: number;
71
+ }, any>;
@@ -0,0 +1,134 @@
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 __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.RequiredModel = exports.FoodModel = exports.StaffUserModel = exports.SuperUserModel = exports.UserModel = void 0;
43
+ var mongoose_1 = require("mongoose");
44
+ var passport_local_mongoose_1 = __importDefault(require("passport-local-mongoose"));
45
+ var plugins_1 = require("../plugins");
46
+ var userSchema = new mongoose_1.Schema({
47
+ admin: { default: false, description: "Whether the user has admin privileges", type: Boolean },
48
+ age: { description: "The user's age", type: Number },
49
+ name: { description: "The user's display name", type: String },
50
+ username: { description: "The user's username", type: String },
51
+ });
52
+ userSchema.plugin(passport_local_mongoose_1.default, {
53
+ attemptsField: "attempts",
54
+ interval: process.env.NODE_ENV === "test" ? 1 : 100,
55
+ limitAttempts: true,
56
+ maxAttempts: 3,
57
+ maxInterval: process.env.NODE_ENV === "test" ? 1 : 300000,
58
+ usernameCaseInsensitive: true,
59
+ usernameField: "email",
60
+ });
61
+ userSchema.plugin(plugins_1.createdUpdatedPlugin);
62
+ userSchema.plugin(plugins_1.isDisabledPlugin);
63
+ userSchema.methods.postCreate = function (body) {
64
+ return __awaiter(this, void 0, void 0, function () {
65
+ return __generator(this, function (_a) {
66
+ this.age = body.age;
67
+ return [2 /*return*/, this.save()];
68
+ });
69
+ });
70
+ };
71
+ exports.UserModel = (0, mongoose_1.model)("User", userSchema);
72
+ var superUserSchema = new mongoose_1.Schema({
73
+ superTitle: { description: "The super user's title", required: true, type: String },
74
+ });
75
+ exports.SuperUserModel = exports.UserModel.discriminator("SuperUser", superUserSchema);
76
+ var staffUserSchema = new mongoose_1.Schema({
77
+ department: {
78
+ description: "The department the staff member belongs to",
79
+ required: true,
80
+ type: String,
81
+ },
82
+ });
83
+ exports.StaffUserModel = exports.UserModel.discriminator("Staff", staffUserSchema);
84
+ var foodCategorySchema = new mongoose_1.Schema({
85
+ name: { description: "The name of the food category", type: String },
86
+ show: { description: "Whether this category is visible", type: Boolean },
87
+ }, { timestamps: { createdAt: "created", updatedAt: "updated" } });
88
+ var likesSchema = new mongoose_1.Schema({
89
+ likes: { description: "Whether the user liked the item", type: Boolean },
90
+ userId: { description: "The user who liked the item", ref: "User", type: "ObjectId" },
91
+ });
92
+ var foodSchema = new mongoose_1.Schema({
93
+ calories: { description: "Number of calories in the food", type: Number },
94
+ categories: { description: "Categories this food belongs to", type: [foodCategorySchema] },
95
+ created: { description: "When this food was created", type: Date },
96
+ eatenBy: [
97
+ {
98
+ description: "Users who have eaten this food",
99
+ ref: "User",
100
+ required: true,
101
+ type: mongoose_1.Schema.Types.ObjectId,
102
+ },
103
+ ],
104
+ // biome-ignore lint/suspicious/noExplicitAny: DateOnly is a custom SchemaType not recognized by Mongoose's built-in type definitions
105
+ expiration: { description: "Expiration date of the food", type: plugins_1.DateOnly },
106
+ hidden: {
107
+ default: false,
108
+ description: "Whether this food is hidden from listings",
109
+ type: Boolean,
110
+ },
111
+ lastEatenWith: {
112
+ description: "Map of user names to dates they last ate this food with",
113
+ of: Date,
114
+ type: Map,
115
+ },
116
+ likesIds: { description: "User likes for this food", required: true, type: [likesSchema] },
117
+ name: { description: "The name of the food", type: String },
118
+ ownerId: { description: "The user who owns this food entry", ref: "User", type: "ObjectId" },
119
+ source: {
120
+ dateAdded: { description: "When the source was added", type: String },
121
+ href: { description: "URL of the source", type: String },
122
+ name: { description: "Name of the source", type: String },
123
+ },
124
+ tags: { description: "Tags associated with this food", type: [String] },
125
+ }, { strict: "throw", toJSON: { virtuals: true }, toObject: { virtuals: true } });
126
+ foodSchema.virtual("description").get(function () {
127
+ return "".concat(this.name, " has ").concat(this.calories, " calories");
128
+ });
129
+ exports.FoodModel = (0, mongoose_1.model)("Food", foodSchema);
130
+ var requiredSchema = new mongoose_1.Schema({
131
+ about: { description: "Information about the item", type: String },
132
+ name: { description: "The name of the item", required: true, type: String },
133
+ });
134
+ exports.RequiredModel = (0, mongoose_1.model)("Required", requiredSchema);
@@ -0,0 +1,7 @@
1
+ import type { TestData } from "./types";
2
+ export declare const cacheFilesExist: () => boolean, cleanCache: () => void, loadTestDataFromCache: () => Promise<void>, setupTestCache: (options?: {
3
+ force?: boolean;
4
+ }) => Promise<void>;
5
+ /** Loads fixture documents after the collection cache has been restored. */
6
+ export declare const loadTestData: () => Promise<TestData>;
7
+ export declare const resetCachedTestData: () => void;
@@ -0,0 +1,150 @@
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
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __generator = (this && this.__generator) || function (thisArg, body) {
45
+ 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);
46
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
47
+ function verb(n) { return function (v) { return step([n, v]); }; }
48
+ function step(op) {
49
+ if (f) throw new TypeError("Generator is already executing.");
50
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
51
+ 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;
52
+ if (y = 0, t) op = [op[0] & 2, t.value];
53
+ switch (op[0]) {
54
+ case 0: case 1: t = op; break;
55
+ case 4: _.label++; return { value: op[1], done: false };
56
+ case 5: _.label++; y = op[1]; op = [0]; continue;
57
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
58
+ default:
59
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
60
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
61
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
62
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
63
+ if (t[2]) _.ops.pop();
64
+ _.trys.pop(); continue;
65
+ }
66
+ op = body.call(thisArg, _);
67
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
68
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
69
+ }
70
+ };
71
+ var _a;
72
+ Object.defineProperty(exports, "__esModule", { value: true });
73
+ exports.resetCachedTestData = exports.loadTestData = exports.setupTestCache = exports.loadTestDataFromCache = exports.cleanCache = exports.cacheFilesExist = void 0;
74
+ var fs = __importStar(require("node:fs"));
75
+ var path = __importStar(require("node:path"));
76
+ var test_1 = require("@terreno/test");
77
+ var createTestData_1 = require("./createTestData");
78
+ var moduleDir = __dirname;
79
+ var defaultCacheDir = process.env.TERRENO_TEST_CACHE_DIR || path.join("/tmp", "terreno-api-test-cache");
80
+ var apiTestCache = (0, test_1.createMongoTestCache)({
81
+ baseDatabaseName: "terrenoTest_base",
82
+ cacheDir: defaultCacheDir,
83
+ createTestData: function () { return __awaiter(void 0, void 0, void 0, function () {
84
+ var testData;
85
+ return __generator(this, function (_a) {
86
+ switch (_a.label) {
87
+ case 0: return [4 /*yield*/, (0, createTestData_1.createTestData)()];
88
+ case 1:
89
+ testData = _a.sent();
90
+ return [2 /*return*/, (0, createTestData_1.toCachedTestData)(testData)];
91
+ }
92
+ });
93
+ }); },
94
+ sourceDirs: [path.resolve(moduleDir, "..")],
95
+ });
96
+ exports.cacheFilesExist = apiTestCache.cacheFilesExist, exports.cleanCache = apiTestCache.cleanCache, exports.loadTestDataFromCache = apiTestCache.loadTestDataFromCache, exports.setupTestCache = apiTestCache.setupTestCache;
97
+ var cachedTestData;
98
+ /** Loads fixture documents after the collection cache has been restored. */
99
+ var loadTestData = function () { return __awaiter(void 0, void 0, void 0, function () {
100
+ var cachedFilePath, cached;
101
+ return __generator(this, function (_a) {
102
+ switch (_a.label) {
103
+ case 0:
104
+ if (cachedTestData) {
105
+ return [2 /*return*/, cachedTestData];
106
+ }
107
+ cachedFilePath = path.join(defaultCacheDir, "cached-data.json");
108
+ cached = JSON.parse(fs.readFileSync(cachedFilePath, "utf-8"));
109
+ return [4 /*yield*/, (0, createTestData_1.loadTestDataFromDocuments)(cached)];
110
+ case 1:
111
+ cachedTestData = _a.sent();
112
+ return [2 /*return*/, cachedTestData];
113
+ }
114
+ });
115
+ }); };
116
+ exports.loadTestData = loadTestData;
117
+ var resetCachedTestData = function () {
118
+ cachedTestData = undefined;
119
+ };
120
+ exports.resetCachedTestData = resetCachedTestData;
121
+ if ((_a = process.argv[1]) === null || _a === void 0 ? void 0 : _a.includes("mongoTestSetup")) {
122
+ var command_1 = process.argv[2];
123
+ var force_1 = process.argv.includes("--force");
124
+ void (function () { return __awaiter(void 0, void 0, void 0, function () {
125
+ return __generator(this, function (_a) {
126
+ switch (_a.label) {
127
+ case 0:
128
+ if (!(command_1 === "setup")) return [3 /*break*/, 2];
129
+ return [4 /*yield*/, (0, exports.setupTestCache)({ force: force_1 })];
130
+ case 1:
131
+ _a.sent();
132
+ process.exit(0);
133
+ _a.label = 2;
134
+ case 2:
135
+ if (command_1 === "clean") {
136
+ (0, exports.cleanCache)();
137
+ (0, exports.resetCachedTestData)();
138
+ process.exit(0);
139
+ }
140
+ if (command_1 === "status") {
141
+ console.info("[mongoTestSetup] cache exists: ".concat((0, exports.cacheFilesExist)()));
142
+ process.exit(0);
143
+ }
144
+ console.error("[mongoTestSetup] Unknown command: ".concat(command_1 !== null && command_1 !== void 0 ? command_1 : "(none)", ". Usage: setup | clean | status"));
145
+ process.exit(1);
146
+ return [2 /*return*/];
147
+ }
148
+ });
149
+ }); })();
150
+ }
File without changes
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ var _a;
3
+ /** Use in-memory MongoDB when no external test URI is configured (local / CI without mongod). */
4
+ if (!((_a = process.env.TERRENO_TEST_MONGODB_URI) === null || _a === void 0 ? void 0 : _a.trim())) {
5
+ process.env.TERRENO_TEST_USE_MEMORY_MONGO = "true";
6
+ }
@@ -0,0 +1,22 @@
1
+ import type { TestData } from "./types";
2
+ export declare const applyTestAuthEnv: () => void;
3
+ /** Seeds only the standard users (legacy helper). */
4
+ export declare const setupDb: () => Promise<readonly [import("mongoose").Document<unknown, {}, import("./models").User, {}, {}> & import("./models").User & {
5
+ _id: import("mongoose").Types.ObjectId;
6
+ } & {
7
+ __v: number;
8
+ }, import("mongoose").Document<unknown, {}, import("./models").User, {}, {}> & import("./models").User & {
9
+ _id: import("mongoose").Types.ObjectId;
10
+ } & {
11
+ __v: number;
12
+ }, import("mongoose").Document<unknown, {}, import("./models").User, {}, {}> & import("./models").User & {
13
+ _id: import("mongoose").Types.ObjectId;
14
+ } & {
15
+ __v: number;
16
+ }]>;
17
+ /** Seeds users, foods, and required docs — the recommended API test baseline. */
18
+ export declare const setupTestData: () => Promise<TestData>;
19
+ /** Clears all API test collections without re-seeding. */
20
+ export declare const resetTestCollections: () => Promise<void>;
21
+ export { createTestData } from "./createTestData";
22
+ export { loadTestData } from "./mongoTestSetup";
@@ -0,0 +1,115 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.loadTestData = exports.createTestData = exports.resetTestCollections = exports.setupTestData = exports.setupDb = exports.applyTestAuthEnv = void 0;
40
+ var test_1 = require("@terreno/test");
41
+ var logger_1 = require("../logger");
42
+ var createTestData_1 = require("./createTestData");
43
+ var models_1 = require("./models");
44
+ var mongoTestSetup_1 = require("./mongoTestSetup");
45
+ var defaultTestMongoUri = "mongodb://127.0.0.1/terreno?&connectTimeoutMS=360000";
46
+ var applyTestAuthEnv = function () {
47
+ process.env.REFRESH_TOKEN_SECRET = "refresh_secret";
48
+ process.env.TOKEN_SECRET = "secret";
49
+ process.env.TOKEN_EXPIRES_IN = "30m";
50
+ process.env.TOKEN_ISSUER = "example.com";
51
+ process.env.SESSION_SECRET = "session";
52
+ };
53
+ exports.applyTestAuthEnv = applyTestAuthEnv;
54
+ var ensureConnected = function () { return __awaiter(void 0, void 0, void 0, function () {
55
+ return __generator(this, function (_a) {
56
+ switch (_a.label) {
57
+ case 0: return [4 /*yield*/, (0, test_1.ensureTestMongooseConnected)({
58
+ defaultUri: defaultTestMongoUri,
59
+ onConnectError: logger_1.logger.catch,
60
+ })];
61
+ case 1:
62
+ _a.sent();
63
+ (0, exports.applyTestAuthEnv)();
64
+ return [2 /*return*/];
65
+ }
66
+ });
67
+ }); };
68
+ /** Seeds only the standard users (legacy helper). */
69
+ var setupDb = function () { return __awaiter(void 0, void 0, void 0, function () {
70
+ var users, error_1;
71
+ return __generator(this, function (_a) {
72
+ switch (_a.label) {
73
+ case 0: return [4 /*yield*/, ensureConnected()];
74
+ case 1:
75
+ _a.sent();
76
+ return [4 /*yield*/, Promise.all([models_1.UserModel.deleteMany({}), models_1.FoodModel.deleteMany({})]).catch(logger_1.logger.catch)];
77
+ case 2:
78
+ _a.sent();
79
+ _a.label = 3;
80
+ case 3:
81
+ _a.trys.push([3, 5, , 6]);
82
+ return [4 /*yield*/, (0, createTestData_1.createTestUsers)()];
83
+ case 4:
84
+ users = _a.sent();
85
+ return [2 /*return*/, [users.admin, users.notAdmin, users.adminOther]];
86
+ case 5:
87
+ error_1 = _a.sent();
88
+ logger_1.logger.error("Error setting up DB", error_1);
89
+ throw error_1;
90
+ case 6: return [2 /*return*/];
91
+ }
92
+ });
93
+ }); };
94
+ exports.setupDb = setupDb;
95
+ /** Seeds users, foods, and required docs — the recommended API test baseline. */
96
+ var setupTestData = function () { return __awaiter(void 0, void 0, void 0, function () {
97
+ return __generator(this, function (_a) {
98
+ switch (_a.label) {
99
+ case 0: return [4 /*yield*/, ensureConnected()];
100
+ case 1:
101
+ _a.sent();
102
+ if (process.env.TERRENO_TEST_USE_FIXTURE_CACHE === "true") {
103
+ return [2 /*return*/, (0, mongoTestSetup_1.loadTestData)()];
104
+ }
105
+ return [2 /*return*/, (0, createTestData_1.createTestData)()];
106
+ }
107
+ });
108
+ }); };
109
+ exports.setupTestData = setupTestData;
110
+ /** Clears all API test collections without re-seeding. */
111
+ exports.resetTestCollections = createTestData_1.clearTestCollections;
112
+ var createTestData_2 = require("./createTestData");
113
+ Object.defineProperty(exports, "createTestData", { enumerable: true, get: function () { return createTestData_2.createTestData; } });
114
+ var mongoTestSetup_2 = require("./mongoTestSetup");
115
+ Object.defineProperty(exports, "loadTestData", { enumerable: true, get: function () { return mongoTestSetup_2.loadTestData; } });
@@ -0,0 +1,29 @@
1
+ import type { HydratedDocument } from "mongoose";
2
+ import type { Food, RequiredField, User } from "./models";
3
+ export interface TestUsers {
4
+ admin: HydratedDocument<User>;
5
+ adminOther: HydratedDocument<User>;
6
+ notAdmin: HydratedDocument<User>;
7
+ }
8
+ export interface TestFoods {
9
+ apple: HydratedDocument<Food>;
10
+ carrots: HydratedDocument<Food>;
11
+ pizza: HydratedDocument<Food>;
12
+ spinach: HydratedDocument<Food>;
13
+ }
14
+ export interface TestRequired {
15
+ sample: HydratedDocument<RequiredField>;
16
+ withAbout: HydratedDocument<RequiredField>;
17
+ }
18
+ /** Canonical API integration-test fixture graph. */
19
+ export interface TestData {
20
+ foods: TestFoods;
21
+ required: TestRequired;
22
+ users: TestUsers;
23
+ }
24
+ /** JSON-serializable snapshot stored alongside collection cache files. */
25
+ export interface CachedTestData {
26
+ foods: Record<keyof TestFoods, string>;
27
+ required: Record<keyof TestRequired, string>;
28
+ users: Record<keyof TestUsers, string>;
29
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/tests.d.ts CHANGED
@@ -1,81 +1,13 @@
1
- import express, { type Express } from "express";
2
- import mongoose, { type Model, Schema } from "mongoose";
1
+ import type express from "express";
2
+ import type { Express } from "express";
3
3
  import type TestAgent from "supertest/lib/agent";
4
- export interface User {
5
- admin: boolean;
6
- name?: string;
7
- username: string;
8
- email: string;
9
- age?: number;
10
- disabled?: boolean;
11
- }
12
- export interface SuperUser extends User {
13
- superTitle: string;
14
- }
15
- export interface StaffUser extends User {
16
- department: string;
17
- }
18
- export interface FoodCategory {
19
- _id?: string;
20
- name: string;
21
- show: boolean;
22
- created: Date;
23
- updated: Date;
24
- }
25
- export interface Food {
26
- _id: string;
27
- name: string;
28
- calories: number;
29
- created: Date;
30
- ownerId: mongoose.Types.ObjectId | User;
31
- hidden?: boolean;
32
- source: {
33
- name: string;
34
- href?: string;
35
- dateAdded?: string;
36
- };
37
- tags: string[];
38
- eatenBy: [Schema.Types.ObjectId | User];
39
- lastEatenWith: {
40
- [name: string]: Date;
41
- };
42
- categories: FoodCategory[];
43
- expiration: string;
44
- likesIds: {
45
- userId: string;
46
- likes: boolean;
47
- }[];
48
- }
49
- export declare const UserModel: mongoose.Model<User, {}, {}, {}, mongoose.Document<unknown, {}, User, {}, {}> & User & {
50
- _id: mongoose.Types.ObjectId;
51
- } & {
52
- __v: number;
53
- }, any>;
54
- export declare const SuperUserModel: mongoose.Model<User & SuperUser, {}, {}, {}, mongoose.Document<unknown, {}, User & SuperUser, {}, {}> & User & SuperUser & {
55
- _id: mongoose.Types.ObjectId;
56
- } & {
57
- __v: number;
58
- }, any>;
59
- export declare const StaffUserModel: mongoose.Model<User & StaffUser, {}, {}, {}, mongoose.Document<unknown, {}, User & StaffUser, {}, {}> & User & StaffUser & {
60
- _id: mongoose.Types.ObjectId;
61
- } & {
62
- __v: number;
63
- }, any>;
64
- export declare const FoodModel: Model<Food>;
65
- interface RequiredField {
66
- name: string;
67
- about?: string;
68
- }
69
- export declare const RequiredModel: mongoose.Model<RequiredField, {}, {}, {}, mongoose.Document<unknown, {}, RequiredField, {}, {}> & RequiredField & {
70
- _id: mongoose.Types.ObjectId;
71
- } & {
72
- __v: number;
73
- }, any>;
4
+ import { createTestData } from "./tests/createTestData";
5
+ import { type Food, type FoodCategory, FoodModel, type RequiredField, RequiredModel, type StaffUser, StaffUserModel, type SuperUser, SuperUserModel, type User, UserModel } from "./tests/models";
6
+ import { loadTestDataFromCache, setupTestCache } from "./tests/mongoTestSetup";
7
+ import { setupDb, setupTestData } from "./tests/testHelper";
8
+ import type { TestData } from "./tests/types";
9
+ export type { Food, FoodCategory, RequiredField, StaffUser, SuperUser, TestData, User };
10
+ export { createTestData, FoodModel, loadTestDataFromCache, RequiredModel, StaffUserModel, SuperUserModel, setupDb, setupTestCache, setupTestData, UserModel, };
74
11
  export declare const getBaseServer: () => Express;
75
12
  export declare const authAsUser: (app: express.Application, type: "admin" | "notAdmin") => Promise<TestAgent>;
76
- export declare const setupDb: () => Promise<(mongoose.Document<unknown, {}, User, {}, {}> & User & {
77
- _id: mongoose.Types.ObjectId;
78
- } & {
79
- __v: number;
80
- })[]>;
81
- export {};
13
+ export { loadTestData } from "./tests/mongoTestSetup";