Semántica de ejecución, restricciones y seguridad

Última actualización: 21 de julio de 2026

Esta página resume cómo se comporta un Script en tiempo de ejecución (orden, transacciones, errores, bloqueo), a qué restricciones estáticas está sujeto al guardarse y su modelo de seguridad. Para la sintaxis, consulte el Catálogo de statements y las Expresiones de valor; para combinaciones prácticas, consulte el Cookbook.

Orden y modo de ejecución

  • Los statements se ejecutan secuencialmente de arriba abajo. Cuando la ejecución alcanza un Return, termina en ese punto.
  • Sync se ejecuta en la ruta que atiende la solicitud; Async se ejecuta en segundo plano. Es solo una distinción de dónde ocurre la ejecución; en ambos casos el resultado es el valor de Return (para la forma de la respuesta de la llamada, consulte Solicitud y respuesta en la descripción general de Script y Modos de ejecución).
  • De la capacidad (capability) al modo: si el árbol de statements contiene alguno de ExternalIo (una llamada externa Http), MediaIngest (ingesta de archivo de Media; { source, encoding } bajo fields.file; común a url y base64) o LongRunning (un Loop grande, etc.), entonces executionMode se fuerza a Async. Estas tres son capacidades distintas y, en Restricciones estáticas más abajo, cuentan para límites diferentes.

Semántica de ejecución

Guard (condiciones previas)

No existe un statement guard dedicado. Se expresa con If y then:[Return]. Cuando se incumple la condición, devuelve un resultado y no ejecuta los statements siguientes (por supuesto, también es posible un Script sin guard).

{ "type": "If", "condition": { "<": [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] },
  "then": [ { "type": "Return", "value": { "ok": false, "reason": "insufficient credit" }, "statusCode": 402 } ] }

Sin transacciones y compensación best-effort

Un Script no es una transacción. Ante un fallo, el motor intenta compensar el trabajo realizado hasta ese momento y devuelve la causa del error, pero con las siguientes limitaciones (asumidas por diseño).

  • Deshacer un borrado crea un nuevo sys.id, por lo que las referencias que apuntaban a él se rompen (revertir una creación es fácil; una actualización necesita una before-image).
  • Los efectos externos (Http) son irreversibles (una llamada que ya ha salido, y su cobro, no se pueden deshacer).
  • En caso de caída del proceso, puede quedar un estado no compensado (un orphan).

Si necesita atomicidad real, escriba la compensación en el Script usted mismo o coloque las operaciones irreversibles (como las llamadas externas) al final. El orden más peligroso es el que «encadena hasta el final pero no puede revertirse, y aun así parece seguro».

Bloqueo optimista

La contención de update/patch se acota con version en ResourceUpdate y ResourcePatch. Si se proporciona version (una expresión de valor, Int), la actualización se realiza solo cuando coincide con el sys.version actual del destino; una discrepancia aborta con un error de conflicto de versión (que se puede manejar localmente con Try/catch). Si se omite, es last-write-wins sin comprobación. Normalmente se lee primero con ResourceRead o ResourcePageRead y se pasa ese sys.version (véase CAS de bloqueo optimista en el Cookbook).

Escrituras en origin

Las escrituras siempre se aplican en origin (draft), y la exposición en delivery (CDA/ACDA) se controla con publish (el publish de ResourceCreate/ResourceUpdate/ResourcePatch, o ResourcePublish/ResourceUnpublish).

Qué se considera un fallo

  • Un fallo real es un error de tiempo de ejecución de un statement: un status final de Http de 400 o superior (4xx·5xx; no es un fallo cuando ignoreStatusCode: true) o un tiempo de espera agotado, un cuerpo de respuesta que supera los 10MiB, o una operación de recurso fallida (destino inexistente, conflicto de versión, operación no admitida, etc.). Ante tales fallos, el motor aborta y compensa, y se pueden manejar localmente con Try/catch/finally.
  • Un Return no es un error, sino una salida anticipada normal. No es un objetivo de catch (no existe el concepto de throw de usuario).
  • Dentro de un catch, se referencia { message, statement } mediante /error.

Sin agregación en el servidor

No hay operaciones de servidor dedicadas a count, sum o group-by. El cálculo se hace iterando con ResourcePageRead y usando SetVar/JsonLogic, por lo que se está limitado por el tamaño de fetch y maxIterations (no es adecuado para agregar millones de registros).

Sin espera ni retardo

Un Script no tiene el statement Delay. Un Script se ejecuta una sola vez y termina, en la ruta de la solicitud (Sync) o en segundo plano (Async), y no espera ni sondea internamente a que termine un job externo (el resultado Async es aparte: el llamante sondea con el requestId recibido en el 202 para obtener el valor de Return).

Restricciones estáticas (validadas al guardar)

Lo siguiente se comprueba cuando se guarda un Script (al crear/actualizar). Si algo se incumple, se rechaza el guardado (falla en el momento de la autoría, no en tiempo de ejecución).

RestricciónPredeterminado
Si hay I/O externa, executionMode debe ser AsyncNo aplica
Dentro del body de un Loop, las llamadas externas Http y la ingesta de archivo de Media están prohibidasNo aplica
Máximo de llamadas externas Http por definición3 (maxExternalIo)
Máximo de SetVar por definición (anidados incluidos)5 (maxSetVar)
Máximo total de statements por definición (anidados incluidos)15 (maxStatements)
Límite de Http.retry2 (maxHttpRetry)

Estos límites se pueden ajustar mediante la configuración del servidor (weegloo.core.script.*); los valores anteriores son los predeterminados.

La ingesta de archivo de Media es la capacidad MediaIngest y, a diferencia de una llamada externa Http (ExternalIo), no cuenta para el límite de maxExternalIo (3). En cambio, el requisito de Async y la prohibición del body de Loop se le aplican igual que a Http.

Presupuesto de tiempo (en tiempo de ejecución)

ModoPresupuesto predeterminado
Sync10 segundos (syncTimeoutMs)
Async60 segundos (asyncTimeoutMs)

Límites de cantidad por plan

Script es un recurso Billable y su número por Organization está limitado por plan.

PlanNúmero de Script
Free3
Basic10
Pro50
EnterpriseIlimitado

Cuando se alcanza el límite, se rechaza la creación de un nuevo Script (por la misma vía que otros recursos Billable).

Modelo de seguridad

Cabeceras secret

Un elemento de Http.headers con secret:true es exclusivo de CMA (administrador): no se expone al usuario final (ServiceUser) y solo se descifra justo antes de la transmisión. Coloque aquí secretos como una clave de API de LLM (incluso al empaquetarse en un App Bundle, el valor secret se enmascara y nunca sale del Space de origen).

Identidad de ejecución y autorización

  • Identidad de ejecución: durante la ejecución, toda operación de recurso se realiza bajo la identidad del usuario que llamó a /execute. El createdBy/updatedBy de cualquier recurso que se cree o actualice es el llamante, y un ámbito createdBy: ":self" también se resuelve respecto al llamante.
  • Hay dos límites de autorización y en tiempo de ejecución el motor no vuelve a comprobar los permisos de recurso en cada statement.
    1. En el momento de la autoría (guardado): al guardar un Script, se comprueba si el autor posee realmente los permisos de recurso y de acción que usan sus statements. Si falta aunque sea uno, se rechaza el guardado (WGL403015). Es decir, un Script que contiene una operación no autorizada no se guarda en primer lugar.
    2. En el momento de la llamada (/execute): solo se comprueba el permiso Execute de Script del llamante. Sin él, el resultado es 403. Una vez que pasa, los permisos de recurso por statement no se vuelven a comprobar en tiempo de ejecución; la ejecución continúa. Funciona como el permiso de ejecución de una función en programación. Si se tiene permiso para ejecutar la función, no se vuelve a preguntar por el permiso de cada operación individual dentro de ella.
  • Ámbito de propiedad: createdBy: ":self" en un filtro where significa «solo lo que ha creado el llamante actual» (por ejemplo, consultar solo la propia cartera).
  • Permisos delegados (atención al autor): al combinar los dos límites anteriores, ejecutar un Script equivale a actuar con los permisos del autor delegados. El llamante solo necesita Execute, y los statements dentro del Script se ejecutan exactamente dentro del ámbito para el que se autorizó al autor al guardar. En consecuencia, una operación de recurso que el llamante no podría realizar por sí mismo puede ocurrir igualmente a través del Script. Dado que los permisos concedidos al autor son el alcance efectivo de ese Script, decida con cuidado qué operaciones incluye en un Script.

Lista de comprobación resumida

Antes de guardar, compruebe lo siguiente.

  • Si hay una llamada externa (Http) o ingesta de archivo de Media, executionMode es "Async".
  • No hay ninguna llamada externa dentro del body de un Loop.
  • Las llamadas externas son 3 o menos, SetVar 5 o menos y los statements totales 15 o menos.
  • Los valores secret se han colocado únicamente mediante secret:true en Http.headers.
  • Las operaciones irreversibles (llamadas externas) se han colocado lo más tarde posible.
  • Si preocupa la contención de update/patch, se usa version en ResourceUpdate o ResourcePatch.
  • Para devolver un resultado, se ha especificado Return.value.