vanta-api 1.2.5 → 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 +21 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanta-api",
3
- "version": "1.2.5",
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": {
@@ -92,7 +92,6 @@ export class ApiFeatures {
92
92
  }
93
93
 
94
94
  populate(input = "") {
95
- // Build list from input and query.populate
96
95
  let list = [];
97
96
  const raw = Array.isArray(input) ? input : [input];
98
97
  if (this.query.populate) raw.push(...this.query.populate.split(","));
@@ -102,14 +101,12 @@ export class ApiFeatures {
102
101
  else if (item?.path) list.push(item);
103
102
  });
104
103
 
105
- // Deduplicate
106
104
  const map = new Map();
107
105
  list.forEach((opt) => {
108
106
  const key = typeof opt === "string" ? opt : opt.path;
109
107
  map.set(key, opt);
110
108
  });
111
109
 
112
- // Enforce role-based populate
113
110
  const allowed =
114
111
  securityConfig.accessLevels[this.userRole]?.allowedPopulate || [];
115
112
  const final = [];
@@ -117,27 +114,31 @@ export class ApiFeatures {
117
114
  if (allowed.includes("*") || allowed.includes(key)) final.push(opt);
118
115
  });
119
116
 
120
- // Apply lookups
121
117
  for (const opt of final) {
122
118
  const field = typeof opt === "string" ? opt : opt.path;
123
119
  const proj =
124
120
  typeof opt === "object" && opt.select
125
- ? opt.select.split(" ").reduce((a, f) => {
126
- a[f] = 1;
127
- return a;
128
- }, {})
121
+ ? opt.select.split(" ").reduce(
122
+ (a, f) => {
123
+ a[f] = 1;
124
+ return a;
125
+ },
126
+ { _id: 1 }
127
+ )
129
128
  : {};
130
129
 
131
- const { collection } = this._getCollectionInfo(field);
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
+
132
136
  const lookup =
133
137
  proj && Object.keys(proj).length
134
138
  ? {
135
139
  from: collection,
136
140
  let: { id: `$${field}` },
137
- pipeline: [
138
- { $match: { $expr: { $eq: ["$_id", "$$id"] } } },
139
- { $project: proj },
140
- ],
141
+ pipeline: [matchStage, { $project: proj }],
141
142
  as: field,
142
143
  }
143
144
  : {
@@ -148,9 +149,12 @@ export class ApiFeatures {
148
149
  };
149
150
 
150
151
  this.pipeline.push({ $lookup: lookup });
151
- this.pipeline.push({
152
- $unwind: { path: `$${field}`, preserveNullAndEmptyArrays: true },
153
- });
152
+
153
+ if (!isArray) {
154
+ this.pipeline.push({
155
+ $unwind: { path: `$${field}`, preserveNullAndEmptyArrays: true },
156
+ });
157
+ }
154
158
  }
155
159
 
156
160
  return this;
@@ -285,7 +289,7 @@ export class ApiFeatures {
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;