@aeriajs/core 0.0.190 → 0.0.192

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.
@@ -25,7 +25,7 @@ export type BuildLookupPipelineOptions = {
25
25
  memoize?: string;
26
26
  project?: string[];
27
27
  };
28
- export declare const getReferences: (properties: FixedObjectProperty["properties"], options?: GetReferenceOptions) => Promise<{}>;
28
+ export declare const getReferences: (properties: FixedObjectProperty["properties"], options?: GetReferenceOptions) => Promise<ReferenceMap>;
29
29
  export declare const recurseSetStage: (reference: Reference, path: string[], parentElem: {}, options?: {
30
30
  noCond: boolean;
31
31
  }) => Document;
@@ -7,7 +7,7 @@ export type TraverseOptionsBase = {
7
7
  validateWholeness?: boolean | 'deep';
8
8
  fromProperties?: boolean;
9
9
  allowOperators?: boolean;
10
- allowInsecureOperators?: boolean;
10
+ noRegExpEscaping?: boolean;
11
11
  undefinedToNull?: boolean;
12
12
  preserveHidden?: boolean;
13
13
  recurseDeep?: boolean;
@@ -28,7 +28,6 @@ const types_1 = require("@aeriajs/types");
28
28
  const common_1 = require("@aeriajs/common");
29
29
  const validation_1 = require("@aeriajs/validation");
30
30
  const entrypoint_1 = require("@aeriajs/entrypoint");
31
- const security_1 = require("@aeriajs/security");
32
31
  const mongodb_1 = require("mongodb");
33
32
  const assets_js_1 = require("../assets.js");
34
33
  const context_js_1 = require("../context.js");
@@ -37,6 +36,9 @@ const reference_js_1 = require("./reference.js");
37
36
  const cascadingRemove_js_1 = require("./cascadingRemove.js");
38
37
  const path = __importStar(require("path"));
39
38
  const fs = __importStar(require("fs/promises"));
39
+ const escapeRegExp = (text) => {
40
+ return text.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
41
+ };
40
42
  const getProperty = (propName, parentProperty) => {
41
43
  if (propName === '_id') {
42
44
  return {
@@ -86,9 +88,10 @@ const cleanupReferences = async (value, ctx) => {
86
88
  return value;
87
89
  }
88
90
  }
89
- const refMap = await (0, reference_js_1.getReferences)(ctx.options.description.properties);
90
- const reference = (0, common_1.getValueFromPath)(refMap, ctx.propPath);
91
- await (0, cascadingRemove_js_1.preferredRemove)(referenceIds, reference, await (0, context_js_1.createContext)({
91
+ const refMap = await (0, reference_js_1.getReferences)({
92
+ [ctx.propName]: ctx.property,
93
+ });
94
+ await (0, cascadingRemove_js_1.preferredRemove)(referenceIds, refMap[ctx.propName], await (0, context_js_1.createContext)({
92
95
  parentContext: context,
93
96
  collectionName: refProperty.$ref,
94
97
  }));
@@ -270,7 +273,7 @@ const recurse = async (target, ctx) => {
270
273
  ...ctx.property.properties,
271
274
  }
272
275
  : target;
273
- for (const propName in entrypoint) {
276
+ entrypoint: for (const propName in entrypoint) {
274
277
  const value = target[propName];
275
278
  const property = getProperty(propName, ctx.property);
276
279
  if (propName === '_id') {
@@ -312,8 +315,17 @@ const recurse = async (target, ctx) => {
312
315
  if (!ctx.options.allowOperators) {
313
316
  return types_1.Result.error(types_1.ACError.InsecureOperator);
314
317
  }
315
- if (!ctx.options.context?.config.security.allowInsecureOperators && security_1.INSECURE_OPERATORS.includes(key)) {
316
- return types_1.Result.error(types_1.ACError.InsecureOperator);
318
+ if (key === '$regex' && typeof value[key] === 'string') {
319
+ if (!ctx.options.noRegExpEscaping) {
320
+ entries.push([
321
+ propName,
322
+ {
323
+ ...value,
324
+ $regex: escapeRegExp(value[key]),
325
+ },
326
+ ]);
327
+ continue entrypoint;
328
+ }
317
329
  }
318
330
  }
319
331
  }
@@ -3,7 +3,6 @@ import { Result, ACError, ValidationErrorCode, TraverseError } from "@aeriajs/ty
3
3
  import { throwIfError, pipe, isReference, getReferenceProperty, getValueFromPath, isError } from "@aeriajs/common";
4
4
  import { makeValidationError, validateProperty, validateWholeness } from "@aeriajs/validation";
5
5
  import { getCollection } from "@aeriajs/entrypoint";
6
- import { INSECURE_OPERATORS } from "@aeriajs/security";
7
6
  import { ObjectId } from "mongodb";
8
7
  import { getCollectionAsset } from "../assets.mjs";
9
8
  import { createContext } from "../context.mjs";
@@ -12,6 +11,9 @@ import { getReferences } from "./reference.mjs";
12
11
  import { preferredRemove } from "./cascadingRemove.mjs";
13
12
  import * as path from "path";
14
13
  import * as fs from "fs/promises";
14
+ const escapeRegExp = (text) => {
15
+ return text.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
16
+ };
15
17
  const getProperty = (propName, parentProperty) => {
16
18
  if (propName === "_id") {
17
19
  return {
@@ -60,9 +62,10 @@ const cleanupReferences = async (value, ctx) => {
60
62
  return value;
61
63
  }
62
64
  }
63
- const refMap = await getReferences(ctx.options.description.properties);
64
- const reference = getValueFromPath(refMap, ctx.propPath);
65
- await preferredRemove(referenceIds, reference, await createContext({
65
+ const refMap = await getReferences({
66
+ [ctx.propName]: ctx.property
67
+ });
68
+ await preferredRemove(referenceIds, refMap[ctx.propName], await createContext({
66
69
  parentContext: context,
67
70
  collectionName: refProperty.$ref
68
71
  }));
@@ -235,146 +238,156 @@ const recurse = async (target, ctx) => {
235
238
  _id: null,
236
239
  ...ctx.property.properties
237
240
  } : target;
238
- for (const propName in entrypoint) {
239
- const value = target[propName];
240
- const property = getProperty(propName, ctx.property);
241
- if (propName === "_id") {
242
- if (value) {
243
- if (ctx.options.autoCast) {
244
- entries.push([
245
- propName,
246
- autoCast(value, {
247
- ...ctx,
248
- target,
241
+ entrypoint:
242
+ for (const propName in entrypoint) {
243
+ const value = target[propName];
244
+ const property = getProperty(propName, ctx.property);
245
+ if (propName === "_id") {
246
+ if (value) {
247
+ if (ctx.options.autoCast) {
248
+ entries.push([
249
249
  propName,
250
- property: {
251
- $ref: ""
252
- }
253
- })
254
- ]);
255
- } else {
256
- entries.push([
257
- propName,
258
- value
259
- ]);
260
- }
261
- }
262
- continue;
263
- }
264
- if (ctx.options.undefinedToNull) {
265
- if (value === void 0) {
266
- entries.push([
267
- propName,
268
- null
269
- ]);
270
- continue;
271
- }
272
- }
273
- if (value && typeof value === "object") {
274
- for (const key in value) {
275
- if (key.startsWith("$")) {
276
- if (!ctx.options.allowOperators) {
277
- return Result.error(ACError.InsecureOperator);
278
- }
279
- if (!ctx.options.context?.config.security.allowInsecureOperators && INSECURE_OPERATORS.includes(key)) {
280
- return Result.error(ACError.InsecureOperator);
250
+ autoCast(value, {
251
+ ...ctx,
252
+ target,
253
+ propName,
254
+ property: {
255
+ $ref: ""
256
+ }
257
+ })
258
+ ]);
259
+ } else {
260
+ entries.push([
261
+ propName,
262
+ value
263
+ ]);
281
264
  }
282
265
  }
266
+ continue;
283
267
  }
284
- }
285
- if (!property) {
286
- if (value && (value.constructor === Object || value.constructor === Array)) {
287
- if (Array.isArray(value)) {
288
- const operations = [];
289
- for (const operation of value) {
290
- const { error: error2, result } = await recurse(operation, ctx);
291
- if (error2) {
292
- return Result.error(error2);
293
- }
294
- operations.push(result);
295
- }
268
+ if (ctx.options.undefinedToNull) {
269
+ if (value === void 0) {
296
270
  entries.push([
297
271
  propName,
298
- operations
272
+ null
299
273
  ]);
300
274
  continue;
301
275
  }
302
- const { error, result: operator } = await recurse(value, ctx);
303
- if (error) {
304
- return Result.error(error);
305
- }
306
- entries.push([
307
- propName,
308
- operator
309
- ]);
310
- continue;
311
- }
312
- entries.push([
313
- propName,
314
- value
315
- ]);
316
- } else {
317
- if (!ctx.options.preserveHidden && property.hidden) {
318
- continue;
319
276
  }
320
- if ("getters" in ctx.options && ctx.options.getters && "getter" in property) {
321
- if (property.requires) {
322
- const missing = property.requires.some((requiredPropName) => !(requiredPropName in target));
323
- if (missing) {
324
- continue;
277
+ if (value && typeof value === "object") {
278
+ for (const key in value) {
279
+ if (key.startsWith("$")) {
280
+ if (!ctx.options.allowOperators) {
281
+ return Result.error(ACError.InsecureOperator);
282
+ }
283
+ if (key === "$regex" && typeof value[key] === "string") {
284
+ if (!ctx.options.noRegExpEscaping) {
285
+ entries.push([
286
+ propName,
287
+ {
288
+ ...value,
289
+ $regex: escapeRegExp(value[key])
290
+ }
291
+ ]);
292
+ continue entrypoint;
293
+ }
294
+ }
325
295
  }
326
296
  }
327
297
  }
328
- if (ctx.options.recurseReferences) {
329
- const propCast = "items" in property ? property.items : property;
330
- if ("$ref" in propCast && value && !(value instanceof ObjectId)) {
331
- const targetDescription = await preloadDescription(throwIfError(await getCollectionAsset(propCast.$ref, "description")));
298
+ if (!property) {
299
+ if (value && (value.constructor === Object || value.constructor === Array)) {
332
300
  if (Array.isArray(value)) {
333
- const documents = [];
334
- for (const elem of value) {
335
- if (elem instanceof ObjectId) {
336
- documents.push(elem);
337
- continue;
338
- }
339
- if (typeof elem === "string") {
340
- documents.push(new ObjectId(elem));
341
- continue;
342
- }
343
- const { error: error2, result } = await traverseDocument(elem, targetDescription, ctx.options);
301
+ const operations = [];
302
+ for (const operation of value) {
303
+ const { error: error2, result } = await recurse(operation, ctx);
344
304
  if (error2) {
345
305
  return Result.error(error2);
346
306
  }
347
- documents.push(result);
307
+ operations.push(result);
348
308
  }
349
309
  entries.push([
350
310
  propName,
351
- documents
311
+ operations
352
312
  ]);
353
313
  continue;
354
314
  }
355
- const { error, result: document } = await traverseDocument(value, targetDescription, ctx.options);
315
+ const { error, result: operator } = await recurse(value, ctx);
356
316
  if (error) {
357
317
  return Result.error(error);
358
318
  }
359
319
  entries.push([
360
320
  propName,
361
- document
321
+ operator
362
322
  ]);
363
323
  continue;
364
324
  }
365
- }
366
- entries.push([
367
- propName,
368
- await ctx.options.pipe(value, {
369
- ...ctx,
370
- target,
325
+ entries.push([
371
326
  propName,
372
- propPath: ctx.propPath ? `${ctx.propPath}.${propName}` : propName,
373
- property
374
- })
375
- ]);
327
+ value
328
+ ]);
329
+ } else {
330
+ if (!ctx.options.preserveHidden && property.hidden) {
331
+ continue;
332
+ }
333
+ if ("getters" in ctx.options && ctx.options.getters && "getter" in property) {
334
+ if (property.requires) {
335
+ const missing = property.requires.some((requiredPropName) => !(requiredPropName in target));
336
+ if (missing) {
337
+ continue;
338
+ }
339
+ }
340
+ }
341
+ if (ctx.options.recurseReferences) {
342
+ const propCast = "items" in property ? property.items : property;
343
+ if ("$ref" in propCast && value && !(value instanceof ObjectId)) {
344
+ const targetDescription = await preloadDescription(throwIfError(await getCollectionAsset(propCast.$ref, "description")));
345
+ if (Array.isArray(value)) {
346
+ const documents = [];
347
+ for (const elem of value) {
348
+ if (elem instanceof ObjectId) {
349
+ documents.push(elem);
350
+ continue;
351
+ }
352
+ if (typeof elem === "string") {
353
+ documents.push(new ObjectId(elem));
354
+ continue;
355
+ }
356
+ const { error: error2, result } = await traverseDocument(elem, targetDescription, ctx.options);
357
+ if (error2) {
358
+ return Result.error(error2);
359
+ }
360
+ documents.push(result);
361
+ }
362
+ entries.push([
363
+ propName,
364
+ documents
365
+ ]);
366
+ continue;
367
+ }
368
+ const { error, result: document } = await traverseDocument(value, targetDescription, ctx.options);
369
+ if (error) {
370
+ return Result.error(error);
371
+ }
372
+ entries.push([
373
+ propName,
374
+ document
375
+ ]);
376
+ continue;
377
+ }
378
+ }
379
+ entries.push([
380
+ propName,
381
+ await ctx.options.pipe(value, {
382
+ ...ctx,
383
+ target,
384
+ propName,
385
+ propPath: ctx.propPath ? `${ctx.propPath}.${propName}` : propName,
386
+ property
387
+ })
388
+ ]);
389
+ }
376
390
  }
377
- }
378
391
  return Result.result(Object.fromEntries(entries));
379
392
  };
380
393
  export const traverseDocument = async (what, description, _options) => {
@@ -1,6 +1,6 @@
1
1
  import type { Context, SchemaWithId, CountPayload, CountReturnType } from '@aeriajs/types';
2
2
  export type CountOptions = {
3
3
  bypassSecurity?: boolean;
4
- allowInsecureOperators?: boolean;
4
+ noRegExpEscaping?: boolean;
5
5
  };
6
6
  export declare const count: <TContext extends Context>(payload: CountPayload<SchemaWithId<TContext["description"]>>, context: TContext extends Context ? TContext : never, options?: CountOptions) => Promise<CountReturnType>;
@@ -16,7 +16,7 @@ const internalCount = async (payload, context, options) => {
16
16
  const traversedFilters = (0, common_1.throwIfError)(await (0, index_js_1.traverseDocument)(filters, context.description, {
17
17
  autoCast: true,
18
18
  allowOperators: true,
19
- allowInsecureOperators: options.allowInsecureOperators,
19
+ noRegExpEscaping: options.noRegExpEscaping,
20
20
  context,
21
21
  }));
22
22
  if ($text) {
@@ -12,7 +12,7 @@ const internalCount = async (payload, context, options) => {
12
12
  const traversedFilters = throwIfError(await traverseDocument(filters, context.description, {
13
13
  autoCast: true,
14
14
  allowOperators: true,
15
- allowInsecureOperators: options.allowInsecureOperators,
15
+ noRegExpEscaping: options.noRegExpEscaping,
16
16
  context
17
17
  }));
18
18
  if ($text) {
@@ -1,6 +1,6 @@
1
1
  import type { Context, SchemaWithId, GetPayload, GetReturnType } from '@aeriajs/types';
2
2
  export type GetOptions = {
3
3
  bypassSecurity?: boolean;
4
- allowInsecureOperators?: boolean;
4
+ noRegExpEscaping?: boolean;
5
5
  };
6
6
  export declare const get: <TContext extends Context>(payload: GetPayload<SchemaWithId<TContext["description"]>>, context: TContext, options?: GetOptions) => Promise<GetReturnType<SchemaWithId<TContext["description"]>>>;
@@ -19,7 +19,7 @@ const internalGet = async (payload, context, options) => {
19
19
  const { error: filtersError, result: traversedFilters } = await (0, index_js_1.traverseDocument)(filters, context.description, {
20
20
  autoCast: true,
21
21
  allowOperators: true,
22
- allowInsecureOperators: options.allowInsecureOperators,
22
+ noRegExpEscaping: options.noRegExpEscaping,
23
23
  context,
24
24
  });
25
25
  if (filtersError) {
@@ -25,7 +25,7 @@ const internalGet = async (payload, context, options) => {
25
25
  const { error: filtersError, result: traversedFilters } = await traverseDocument(filters, context.description, {
26
26
  autoCast: true,
27
27
  allowOperators: true,
28
- allowInsecureOperators: options.allowInsecureOperators,
28
+ noRegExpEscaping: options.noRegExpEscaping,
29
29
  context
30
30
  });
31
31
  if (filtersError) {
@@ -2,6 +2,6 @@ import type { Context, SchemaWithId, GetAllPayload, GetAllReturnType } from '@ae
2
2
  export type GetAllOptions = {
3
3
  bypassSecurity?: boolean;
4
4
  noDefaultLimit?: boolean;
5
- allowInsecureOperators?: boolean;
5
+ noRegExpEscaping?: boolean;
6
6
  };
7
7
  export declare const getAll: <TContext extends Context>(payload: GetAllPayload<SchemaWithId<TContext["description"]>> | undefined, context: TContext, options?: GetAllOptions) => Promise<GetAllReturnType<SchemaWithId<TContext["description"]>>>;
@@ -42,7 +42,7 @@ const internalGetAll = async (payload, context, options) => {
42
42
  const { error: filtersError, result: traversedFilters } = await (0, index_js_1.traverseDocument)(filters, context.description, {
43
43
  autoCast: true,
44
44
  allowOperators: true,
45
- allowInsecureOperators: options.allowInsecureOperators,
45
+ noRegExpEscaping: options.noRegExpEscaping,
46
46
  context,
47
47
  });
48
48
  if (filtersError) {
@@ -42,7 +42,7 @@ const internalGetAll = async (payload, context, options) => {
42
42
  const { error: filtersError, result: traversedFilters } = await traverseDocument(filters, context.description, {
43
43
  autoCast: true,
44
44
  allowOperators: true,
45
- allowInsecureOperators: options.allowInsecureOperators,
45
+ noRegExpEscaping: options.noRegExpEscaping,
46
46
  context
47
47
  });
48
48
  if (filtersError) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriajs/core",
3
- "version": "0.0.190",
3
+ "version": "0.0.192",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "aeriaMain": "tests/fixtures/aeriaMain.js",
@@ -42,13 +42,13 @@
42
42
  "mongodb-memory-server": "^9.2.0"
43
43
  },
44
44
  "peerDependencies": {
45
- "@aeriajs/builtins": "^0.0.190",
46
- "@aeriajs/common": "^0.0.116",
47
- "@aeriajs/entrypoint": "^0.0.119",
48
- "@aeriajs/http": "^0.0.130",
49
- "@aeriajs/security": "^0.0.190",
50
- "@aeriajs/types": "^0.0.99",
51
- "@aeriajs/validation": "^0.0.119"
45
+ "@aeriajs/builtins": "^0.0.192",
46
+ "@aeriajs/common": "^0.0.118",
47
+ "@aeriajs/entrypoint": "^0.0.121",
48
+ "@aeriajs/http": "^0.0.132",
49
+ "@aeriajs/security": "^0.0.192",
50
+ "@aeriajs/types": "^0.0.101",
51
+ "@aeriajs/validation": "^0.0.121"
52
52
  },
53
53
  "dependencies": {
54
54
  "mongodb": "^6.5.0",