11import { all , create , type EvalFunction } from 'mathjs/number' ;
22
3+ import { ACTOR_LIMITS } from '@apify/consts' ;
34import log from '@apify/log' ;
45
56import type { LruCache } from '../../datastructures/src/lru_cache' ;
@@ -23,7 +24,7 @@ export const DEFAULT_MEMORY_MBYTES_MAX_CHARS = 1000;
2324
2425/**
2526 * A Set of allowed keys from ActorRunOptions that can be used in
26- * the {{variable}} syntax.
27+ * the {{runOptions. variable}} syntax.
2728 */
2829const ALLOWED_RUN_OPTION_KEYS = new Set < keyof ActorRunOptions > ( [
2930 'build' ,
@@ -75,8 +76,9 @@ const customGetFunc = (obj: any, path: string, defaultVal?: number) => {
7576
7677/**
7778 * Rounds a number to the closest power of 2.
79+ * The result is clamped to the allowed range (ACTOR_LIMITS.MIN_RUN_MEMORY_MBYTES - ACTOR_LIMITS.MAX_RUN_MEMORY_MBYTES).
7880 * @param num The number to round.
79- * @returns The closest power of 2.
81+ * @returns The closest power of 2 within min/max range .
8082*/
8183const roundToClosestPowerOf2 = ( num : number ) : number | undefined => {
8284 // Handle 0 or negative values. The smallest power of 2 is 2^7 = 128.
@@ -91,13 +93,14 @@ const roundToClosestPowerOf2 = (num: number): number | undefined => {
9193 const log2n = Math . log2 ( num ) ;
9294
9395 const roundedLog = Math . round ( log2n ) ;
96+ const result = 2 ** roundedLog ;
9497
95- return 2 ** roundedLog ;
98+ return Math . max ( ACTOR_LIMITS . MIN_RUN_MEMORY_MBYTES , Math . min ( result , ACTOR_LIMITS . MAX_RUN_MEMORY_MBYTES ) ) ;
9699} ;
97100
98101/**
99102 * Replaces `{{variable}}` placeholders in an expression string with the variable name.
100- * Enforces strict validation to only allow `input.*` paths or whitelisted `runOptions.*` keys.
103+ * Enforces strict validation to allow `{{ input.*}} ` paths or whitelisted `{{ runOptions.*}} ` keys.
101104 *
102105 * @example
103106 * // Returns "runOptions.memoryMbytes + 1024"
@@ -119,12 +122,13 @@ const preprocessDefaultMemoryExpression = (defaultMemoryMbytes: string): string
119122 ) ;
120123 }
121124
122- // 2. Check if the variable is accessing Input (e.g. {{input.someValue}})
125+ // 2. Check if the variable is accessing input (e.g. {{input.someValue}})
123126 // We do not validate the specific property name because input is dynamic.
124127 if ( variableName . startsWith ( 'input.' ) ) {
125128 return variableName ;
126129 }
127130
131+ // 3. Check if the variable is accessing runOptions (e.g. {{runOptions.memoryMbytes}}) and validate the keys.
128132 if ( variableName . startsWith ( 'runOptions.' ) ) {
129133 const key = variableName . slice ( 'runOptions.' . length ) ;
130134 if ( ! ALLOWED_RUN_OPTION_KEYS . has ( key as keyof ActorRunOptions ) ) {
0 commit comments