vanta-api 1.2.6 → 1.2.7

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/api-features.js +67 -63
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanta-api",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "description": "Advanced API features and security configuration for Node.js/MongoDB.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -91,70 +91,74 @@ export class ApiFeatures {
91
91
  return this;
92
92
  }
93
93
 
94
- populate(input = "") {
95
- let list = [];
96
- const raw = Array.isArray(input) ? input : [input];
97
- if (this.query.populate) raw.push(...this.query.populate.split(","));
98
-
99
- raw.forEach((item) => {
100
- if (typeof item === "string" && item.trim()) list.push(item.trim());
101
- else if (item?.path) list.push(item);
102
- });
103
-
104
- const map = new Map();
105
- list.forEach((opt) => {
106
- const key = typeof opt === "string" ? opt : opt.path;
107
- map.set(key, opt);
108
- });
109
-
110
- const allowed =
111
- securityConfig.accessLevels[this.userRole]?.allowedPopulate || [];
112
- const final = [];
113
- map.forEach((opt, key) => {
114
- if (allowed.includes("*") || allowed.includes(key)) final.push(opt);
115
- });
116
-
117
- for (const opt of final) {
118
- const field = typeof opt === "string" ? opt : opt.path;
119
- const proj =
120
- typeof opt === "object" && opt.select
121
- ? opt.select.split(" ").reduce((a, f) => {
122
- a[f] = 1;
123
- return a;
124
- }, {})
125
- : {};
126
-
127
- const { collection, isArray } = this._getCollectionInfo(field);
128
-
129
- const lookup =
130
- proj && Object.keys(proj).length
131
- ? {
132
- from: collection,
133
- let: { id: `$${field}` },
134
- pipeline: [
135
- { $match: { $expr: { $eq: ["$_id", "$$id"] } } },
136
- { $project: proj },
137
- ],
138
- as: field,
139
- }
140
- : {
141
- from: collection,
142
- localField: field,
143
- foreignField: "_id",
144
- as: field,
145
- };
146
-
147
- this.pipeline.push({ $lookup: lookup });
148
-
149
- if (!isArray) {
150
- this.pipeline.push({
151
- $unwind: { path: `$${field}`, preserveNullAndEmptyArrays: true },
152
- });
94
+ populate(input = "") {
95
+ let list = [];
96
+ const raw = Array.isArray(input) ? input : [input];
97
+ if (this.query.populate) raw.push(...this.query.populate.split(","));
98
+
99
+ raw.forEach((item) => {
100
+ if (typeof item === "string" && item.trim()) list.push(item.trim());
101
+ else if (item?.path) list.push(item);
102
+ });
103
+
104
+ const map = new Map();
105
+ list.forEach((opt) => {
106
+ const key = typeof opt === "string" ? opt : opt.path;
107
+ map.set(key, opt);
108
+ });
109
+
110
+ const allowed =
111
+ securityConfig.accessLevels[this.userRole]?.allowedPopulate || [];
112
+ const final = [];
113
+ map.forEach((opt, key) => {
114
+ if (allowed.includes("*") || allowed.includes(key)) final.push(opt);
115
+ });
116
+
117
+ for (const opt of final) {
118
+ const field = typeof opt === "string" ? opt : opt.path;
119
+ const proj =
120
+ typeof opt === "object" && opt.select
121
+ ? opt.select.split(" ").reduce(
122
+ (a, f) => {
123
+ a[f] = 1;
124
+ return a;
125
+ },
126
+ { _id: 1 }
127
+ )
128
+ : {};
129
+
130
+ const { collection, isArray } = this._getCollectionInfo(field);
131
+
132
+ const matchStage = isArray
133
+ ? { $match: { $expr: { $in: ["$_id", "$$id"] } } }
134
+ : { $match: { $expr: { $eq: ["$_id", "$$id"] } } };
135
+
136
+ const lookup =
137
+ proj && Object.keys(proj).length
138
+ ? {
139
+ from: collection,
140
+ let: { id: `$${field}` },
141
+ pipeline: [matchStage, { $project: proj }],
142
+ as: field,
143
+ }
144
+ : {
145
+ from: collection,
146
+ localField: field,
147
+ foreignField: "_id",
148
+ as: field,
149
+ };
150
+
151
+ this.pipeline.push({ $lookup: lookup });
152
+
153
+ if (!isArray) {
154
+ this.pipeline.push({
155
+ $unwind: { path: `$${field}`, preserveNullAndEmptyArrays: true },
156
+ });
157
+ }
153
158
  }
154
- }
155
159
 
156
- return this;
157
- }
160
+ return this;
161
+ }
158
162
 
159
163
  addManualFilters(filters) {
160
164
  if (filters) this.manualFilters = { ...this.manualFilters, ...filters };
@@ -285,7 +289,7 @@ populate(input = "") {
285
289
  resultObj[keyObj] = false;
286
290
  return;
287
291
  }
288
-
292
+
289
293
  if (typeof val === "string" && /^[0-9]+$/.test(val)) {
290
294
  resultObj[keyObj] = parseInt(val, 10);
291
295
  return;