@aeriajs/core 0.0.191 → 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.split('.').join('.deepReferences.'));
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,11 +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
- const allowInsecureOperators = ctx.options.allowInsecureOperators === undefined
316
- ? ctx.options.context?.config.security.allowInsecureOperators
317
- : ctx.options.allowInsecureOperators;
318
- if (!allowInsecureOperators && security_1.INSECURE_OPERATORS.includes(key)) {
319
- 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
+ }
320
329
  }
321
330
  }
322
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.split(".").join(".deepReferences."));
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,147 +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
- const allowInsecureOperators = ctx.options.allowInsecureOperators === void 0 ? ctx.options.context?.config.security.allowInsecureOperators : ctx.options.allowInsecureOperators;
280
- if (!allowInsecureOperators && INSECURE_OPERATORS.includes(key)) {
281
- 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
+ ]);
282
264
  }
283
265
  }
266
+ continue;
284
267
  }
285
- }
286
- if (!property) {
287
- if (value && (value.constructor === Object || value.constructor === Array)) {
288
- if (Array.isArray(value)) {
289
- const operations = [];
290
- for (const operation of value) {
291
- const { error: error2, result } = await recurse(operation, ctx);
292
- if (error2) {
293
- return Result.error(error2);
294
- }
295
- operations.push(result);
296
- }
268
+ if (ctx.options.undefinedToNull) {
269
+ if (value === void 0) {
297
270
  entries.push([
298
271
  propName,
299
- operations
272
+ null
300
273
  ]);
301
274
  continue;
302
275
  }
303
- const { error, result: operator } = await recurse(value, ctx);
304
- if (error) {
305
- return Result.error(error);
306
- }
307
- entries.push([
308
- propName,
309
- operator
310
- ]);
311
- continue;
312
- }
313
- entries.push([
314
- propName,
315
- value
316
- ]);
317
- } else {
318
- if (!ctx.options.preserveHidden && property.hidden) {
319
- continue;
320
276
  }
321
- if ("getters" in ctx.options && ctx.options.getters && "getter" in property) {
322
- if (property.requires) {
323
- const missing = property.requires.some((requiredPropName) => !(requiredPropName in target));
324
- if (missing) {
325
- 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
+ }
326
295
  }
327
296
  }
328
297
  }
329
- if (ctx.options.recurseReferences) {
330
- const propCast = "items" in property ? property.items : property;
331
- if ("$ref" in propCast && value && !(value instanceof ObjectId)) {
332
- const targetDescription = await preloadDescription(throwIfError(await getCollectionAsset(propCast.$ref, "description")));
298
+ if (!property) {
299
+ if (value && (value.constructor === Object || value.constructor === Array)) {
333
300
  if (Array.isArray(value)) {
334
- const documents = [];
335
- for (const elem of value) {
336
- if (elem instanceof ObjectId) {
337
- documents.push(elem);
338
- continue;
339
- }
340
- if (typeof elem === "string") {
341
- documents.push(new ObjectId(elem));
342
- continue;
343
- }
344
- 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);
345
304
  if (error2) {
346
305
  return Result.error(error2);
347
306
  }
348
- documents.push(result);
307
+ operations.push(result);
349
308
  }
350
309
  entries.push([
351
310
  propName,
352
- documents
311
+ operations
353
312
  ]);
354
313
  continue;
355
314
  }
356
- const { error, result: document } = await traverseDocument(value, targetDescription, ctx.options);
315
+ const { error, result: operator } = await recurse(value, ctx);
357
316
  if (error) {
358
317
  return Result.error(error);
359
318
  }
360
319
  entries.push([
361
320
  propName,
362
- document
321
+ operator
363
322
  ]);
364
323
  continue;
365
324
  }
366
- }
367
- entries.push([
368
- propName,
369
- await ctx.options.pipe(value, {
370
- ...ctx,
371
- target,
325
+ entries.push([
372
326
  propName,
373
- propPath: ctx.propPath ? `${ctx.propPath}.${propName}` : propName,
374
- property
375
- })
376
- ]);
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
+ }
377
390
  }
378
- }
379
391
  return Result.result(Object.fromEntries(entries));
380
392
  };
381
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.191",
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.191",
46
- "@aeriajs/common": "^0.0.117",
47
- "@aeriajs/entrypoint": "^0.0.120",
48
- "@aeriajs/http": "^0.0.131",
49
- "@aeriajs/security": "^0.0.191",
50
- "@aeriajs/types": "^0.0.100",
51
- "@aeriajs/validation": "^0.0.120"
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",