@@ -70,14 +70,23 @@ const math = create({
7070const { compile } = math ;
7171
7272// Disable potentially dangerous functions
73- math . import ( {
74- // We disable evaluate to prevent users from calling it inside their expressions.
75- // For example: defaultMemoryMbytes = "evaluate('2 + 2')"
76- evaluate ( ) { throw new Error ( 'Function evaluate is disabled.' ) ; } ,
77- compile ( ) { throw new Error ( 'Function compile is disabled.' ) ; } ,
78- // We need to disable it, because compileDependencies imports parseDependencies.
79- parse ( ) { throw new Error ( 'Function parse is disabled.' ) ; } ,
80- } , { override : true } ) ;
73+ math . import (
74+ {
75+ // We disable evaluate to prevent users from calling it inside their expressions.
76+ // For example: defaultMemoryMbytes = "evaluate('2 + 2')"
77+ evaluate ( ) {
78+ throw new Error ( 'Function evaluate is disabled.' ) ;
79+ } ,
80+ compile ( ) {
81+ throw new Error ( 'Function compile is disabled.' ) ;
82+ } ,
83+ // We need to disable it, because compileDependencies imports parseDependencies.
84+ parse ( ) {
85+ throw new Error ( 'Function parse is disabled.' ) ;
86+ } ,
87+ } ,
88+ { override : true } ,
89+ ) ;
8190
8291/**
8392 * Safely retrieves a nested property from an object using a dot-notation string path.
@@ -89,17 +98,17 @@ math.import({
8998 * @param path A dot-separated string representing the nested path (e.g., "input.payload.size").
9099 * @param defaultVal The value to return if the path is not found or the value is `null` or `undefined`.
91100 * @returns The retrieved value, or `defaultVal` if the path is unreachable.
92- */
101+ */
93102const customGetFunc = ( obj : any , path : string , defaultVal ?: number ) => {
94- return ( path . split ( '.' ) . reduce ( ( current , key ) => current ?. [ key ] , obj ) ) ?? defaultVal ;
103+ return path . split ( '.' ) . reduce ( ( current , key ) => current ?. [ key ] , obj ) ?? defaultVal ;
95104} ;
96105
97106/**
98107 * Rounds a number to the closest power of 2.
99108 * The result is clamped to the allowed range (ACTOR_LIMITS.MIN_RUN_MEMORY_MBYTES - ACTOR_LIMITS.MAX_RUN_MEMORY_MBYTES).
100109 * @param num The number to round.
101110 * @returns The closest power of 2 within min/max range.
102- */
111+ */
103112const roundToClosestPowerOf2 = ( num : number ) : number => {
104113 if ( typeof num !== 'number' || Number . isNaN ( num ) || ! Number . isFinite ( num ) ) {
105114 throw new Error ( `Calculated memory value is not a valid number: ${ num } .` ) ;
@@ -139,44 +148,46 @@ const roundToClosestPowerOf2 = (num: number): number => {
139148const processTemplateVariables = ( defaultMemoryMbytes : string ) : string => {
140149 const variableRegex = / { { \s * ( [ a - z A - Z 0 - 9 _ . ] + ) \s * } } / g;
141150
142- const processedExpression = defaultMemoryMbytes . replace (
143- variableRegex ,
144- ( _ , variableName : string ) => {
145- // 1. Check if the variable is accessing input (e.g. {{input.someValue}})
146- // We do not validate the specific property name because `input` is dynamic.
147- if ( variableName . startsWith ( 'input.' ) ) {
148- return variableName ;
151+ const processedExpression = defaultMemoryMbytes . replace ( variableRegex , ( _ , variableName : string ) => {
152+ // 1. Check if the variable is accessing input (e.g. {{input.someValue}})
153+ // We do not validate the specific property name because `input` is dynamic.
154+ if ( variableName . startsWith ( 'input.' ) ) {
155+ return variableName ;
156+ }
157+
158+ // 2. Check if the variable is accessing runOptions (e.g. {{runOptions.memoryMbytes}}) and validate the keys.
159+ if ( variableName . startsWith ( 'runOptions.' ) ) {
160+ const key = variableName . slice ( 'runOptions.' . length ) ;
161+ if ( ! ALLOWED_RUN_OPTION_KEYS . has ( key as keyof ActorRunOptions ) ) {
162+ throw new Error (
163+ `Invalid variable '{{${ variableName } }}' in expression. Only the following runOptions are allowed: ${ Array . from (
164+ ALLOWED_RUN_OPTION_KEYS ,
165+ )
166+ . map ( ( k ) => `runOptions.${ k } ` )
167+ . join ( ', ' ) } .`,
168+ ) ;
149169 }
170+ return variableName ;
171+ }
150172
151- // 2. Check if the variable is accessing runOptions (e.g. {{runOptions.memoryMbytes}}) and validate the keys.
152- if ( variableName . startsWith ( 'runOptions.' ) ) {
153- const key = variableName . slice ( 'runOptions.' . length ) ;
154- if ( ! ALLOWED_RUN_OPTION_KEYS . has ( key as keyof ActorRunOptions ) ) {
155- throw new Error (
156- `Invalid variable '{{${ variableName } }}' in expression. Only the following runOptions are allowed: ${ Array . from ( ALLOWED_RUN_OPTION_KEYS ) . map ( ( k ) => `runOptions.${ k } ` ) . join ( ', ' ) } .` ,
157- ) ;
158- }
159- return variableName ;
160- }
161-
162- // 3. Throw error for unrecognized variables (e.g. {{someVariable}})
163- throw new Error (
164- `Invalid variable '{{${ variableName } }}' in expression.` ,
165- ) ;
166- } ,
167- ) ;
173+ // 3. Throw error for unrecognized variables (e.g. {{someVariable}})
174+ throw new Error ( `Invalid variable '{{${ variableName } }}' in expression.` ) ;
175+ } ) ;
168176
169177 return processedExpression ;
170178} ;
171179
172180/*
173- * Retrieves a compiled expression from the cache or compiles it if not present.
174- *
175- * @param expression The expression string to compile.
176- * @param cache An optional cache to store/retrieve compiled expressions.
177- * @returns The compiled CompilationResult.
178- */
179- const getCompiledExpression = async ( expression : string , cache : CompilationCache | undefined ) : Promise < CompilationResult > => {
181+ * Retrieves a compiled expression from the cache or compiles it if not present.
182+ *
183+ * @param expression The expression string to compile.
184+ * @param cache An optional cache to store/retrieve compiled expressions.
185+ * @returns The compiled CompilationResult.
186+ */
187+ const getCompiledExpression = async (
188+ expression : string ,
189+ cache : CompilationCache | undefined ,
190+ ) : Promise < CompilationResult > => {
180191 if ( ! cache ) {
181192 return compile ( expression ) ;
182193 }
@@ -199,14 +210,16 @@ const getCompiledExpression = async (expression: string, cache: CompilationCache
199210 * @param context The `MemoryEvaluationContext` (containing `input` and `runOptions`) available to the expression.
200211 * @param options.cache Optional synchronous cache. Since compiled functions cannot be saved to a database/Redis, they are kept in local memory.
201212 * @returns The calculated memory value rounded to the closest power of 2 and clamped within allowed limits.
202- */
213+ */
203214export const calculateRunDynamicMemory = async (
204215 defaultMemoryMbytes : string ,
205216 context : MemoryEvaluationContext ,
206217 options : { cache : CompilationCache } | undefined = undefined ,
207218) => {
208219 if ( defaultMemoryMbytes . length > DEFAULT_MEMORY_MBYTES_EXPRESSION_MAX_LENGTH ) {
209- throw new Error ( `The defaultMemoryMbytes expression is too long. Max length is ${ DEFAULT_MEMORY_MBYTES_EXPRESSION_MAX_LENGTH } characters.` ) ;
220+ throw new Error (
221+ `The defaultMemoryMbytes expression is too long. Max length is ${ DEFAULT_MEMORY_MBYTES_EXPRESSION_MAX_LENGTH } characters.` ,
222+ ) ;
210223 }
211224
212225 // Replaces all occurrences of {{variable}} with variable
0 commit comments