@memberjunction/actions 5.28.0 → 5.30.0

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.
package/README.md CHANGED
@@ -393,21 +393,24 @@ This package depends on:
393
393
 
394
394
  - [@memberjunction/global](../../MJGlobal/README.md) — ClassFactory and `@RegisterClass` decorator
395
395
  - [@memberjunction/core](../../MJCore/README.md) — `Metadata`, `RunView`, `BaseEntity`, logging utilities
396
- - [@memberjunction/actions-base](../Base/README.md) — Shared types (`ActionEngineBase`, `RunActionParams`, `ActionResult`, etc.)
396
+ - [@memberjunction/actions-base](../Base/README.md) — Shared types (`ActionEngineBase`, `RunActionParams`, `ActionResult`, `RuntimeActionBridgeBuilder` abstract)
397
397
  - [@memberjunction/core-entities](../../MJCoreEntities/README.md) — Generated entity classes (`ActionExecutionLogEntity`, `ActionFilterEntity`, etc.)
398
- - [@memberjunction/ai](../../AI/Core/README.md) — AI model integration
399
- - [@memberjunction/ai-core-plus](../../AI/CorePlus/README.md) — Extended AI utilities
400
- - [@memberjunction/aiengine](../../AI/Engine/README.md) — AI engine orchestration
401
- - [@memberjunction/ai-prompts](../../AI/Prompts/README.md) — AI prompt execution
398
+ - [@memberjunction/action-runtime](../Runtime/README.md) — Sandbox executor for `Type='Runtime'` actions
399
+ - [@memberjunction/code-execution](../CodeExecution/README.md) — `BridgeHandlerMap` type (host-side bridge passed to the sandbox)
400
+ - [@memberjunction/ai](../../AI/Core/README.md) — AI model integration (shared types)
401
+
402
+ **Not a direct dependency any longer**: `@memberjunction/ai-agents`, `@memberjunction/ai-prompts`, `@memberjunction/aiengine`, `@memberjunction/ai-core-plus`. These used to be pulled in for the Runtime-action bridge; the bridge was extracted into [`@memberjunction/action-runtime-host`](../RuntimeHost/README.md) (top of the Actions stack), and this package now resolves the concrete bridge builder via `MJGlobal.ClassFactory.CreateInstance(RuntimeActionBridgeBuilder)`. See the RuntimeHost README for the cycle-breaking architecture.
402
403
 
403
404
  ## Related Packages
404
405
 
405
406
  - [@memberjunction/actions-base](../Base/README.md) — Shared types and base classes used by both client and server
407
+ - [@memberjunction/action-runtime](../Runtime/README.md) — Sandboxed executor for `Type='Runtime'` actions (approval gate, input/output wiring, isolated-vm dispatch)
408
+ - [@memberjunction/action-runtime-host](../RuntimeHost/README.md) — Default `utilities.*` bridge (md / rv / rq / entity / actions / agents / ai) exposed to sandboxed Runtime-action code
406
409
  - [CoreActions](../CoreActions/) — Built-in action implementations (Create Record, generated actions, etc.)
407
410
  - [ScheduledActions](../ScheduledActions/) — Scheduled action execution support
408
411
  - [ApolloEnrichment](../ApolloEnrichment/) — Apollo data enrichment actions
409
412
  - [ContentAutotag](../ContentAutotag/) — Content auto-tagging actions
410
- - [CodeExecution](../CodeExecution/) — Dynamic code execution actions
413
+ - [CodeExecution](../CodeExecution/) — Isolated-vm sandbox + worker pool (`CodeExecutionService` used by `action-runtime`)
411
414
 
412
415
  For the Actions system philosophy and development guide, see the [Actions CLAUDE.md](../CLAUDE.md).
413
416
 
@@ -1,12 +1,33 @@
1
1
  import { MJActionExecutionLogEntity, MJActionFilterEntity } from "@memberjunction/core-entities";
2
- import { ActionEngineBase, MJActionEntityExtended, ActionParam, ActionResult, RunActionParams } from "@memberjunction/actions-base";
2
+ import { ActionEngineBase, MJActionEntityExtended, ActionParam, ActionResult, ActionResultSimple, RunActionParams } from "@memberjunction/actions-base";
3
3
  /**
4
4
  * Base class for executing actions. This class can be sub-classed if desired if you would like to modify the logic across ALL actions. To do so, sub-class this class and use the
5
5
  * @RegisterClass decorator from the @memberjunction/global package to register your sub-class with the ClassFactory. This will cause your sub-class to be used instead of this base class when the Metadata object insantiates the ActionEngine.
6
6
  */
7
7
  export declare class ActionEngineServer extends ActionEngineBase {
8
8
  static get Instance(): ActionEngineServer;
9
+ /**
10
+ * Engine-default wall-clock timeout applied to any action whose
11
+ * `MaxExecutionTimeMS` is NULL. Intentionally generous (2 hours) because
12
+ * some integration actions do legitimately long sync work; per-action
13
+ * overrides should be used to tighten this for anything agent-facing.
14
+ * Sub-classes can override to globally change the default.
15
+ */
16
+ protected get DefaultActionTimeoutMS(): number;
9
17
  RunAction(params: RunActionParams): Promise<ActionResult>;
18
+ /**
19
+ * Wraps `InternalRunAction()` with a universal wall-clock timeout
20
+ * (`Action.MaxExecutionTimeMS`, falling back to `DefaultActionTimeoutMS`)
21
+ * and an `AbortSignal` passed to the action via `params.AbortSignal`.
22
+ *
23
+ * Enforcement is cooperative: when the timeout fires we set an abort on
24
+ * the signal so in-flight `fetch`/`setTimeout`/custom polling logic can
25
+ * short-circuit, and we race the action against a rejection that surfaces
26
+ * a `TIMEOUT` result. If the caller already supplied an `AbortSignal`
27
+ * (e.g. when being run from a Runtime-action bridge that has its own
28
+ * abort), we chain to it so either source can trigger cancellation.
29
+ */
30
+ protected RunActionWithTimeout(params: RunActionParams): Promise<ActionResult>;
10
31
  protected GetActionParamsForAction(action: MJActionEntityExtended): ActionParam[];
11
32
  /**
12
33
  * This method handles input validation. Subclasses can override this method to provide custom input validation.
@@ -23,6 +44,29 @@ export declare class ActionEngineServer extends ActionEngineBase {
23
44
  */
24
45
  protected RunSingleFilter(params: RunActionParams, filter: MJActionFilterEntity): Promise<boolean>;
25
46
  protected InternalRunAction(params: RunActionParams): Promise<ActionResult>;
47
+ /**
48
+ * Resolves and runs a Custom / Generated action via the ClassFactory.
49
+ * This is the pre-existing path — factored out of `InternalRunAction` so
50
+ * the Type dispatch is readable.
51
+ */
52
+ protected RunClassBasedAction(params: RunActionParams): Promise<ActionResultSimple>;
53
+ /**
54
+ * Runs an `Action.Type='Runtime'` action by delegating to the sandboxed
55
+ * RuntimeActionExecutor. Approval / Status / Code-presence checks are
56
+ * enforced inside the executor; here we parse the RuntimeActionConfiguration,
57
+ * build the permissioned bridge-handler map, and hand it off.
58
+ *
59
+ * The bridge handlers run in-process on the host (not inside the sandbox)
60
+ * so they have full access to Metadata, RunView, ActionEngine, etc.
61
+ * Permission enforcement against `RuntimeActionConfiguration.permissions`
62
+ * happens inside each handler — see `RuntimeActionBridge.ts`.
63
+ *
64
+ * If the configuration is missing or malformed, we still let the action
65
+ * run in pure-compute mode (no bridge). The action's Code can then only
66
+ * use `input` + `libs`; any attempt to call `utilities.*` at runtime
67
+ * rejects with a "handler not registered" error from the worker pool.
68
+ */
69
+ protected RunRuntimeAction(params: RunActionParams): Promise<ActionResultSimple>;
26
70
  protected StartActionLog(params: RunActionParams, saveRecord?: boolean): Promise<MJActionExecutionLogEntity>;
27
71
  protected EndActionLog(logEntity: MJActionExecutionLogEntity, params: RunActionParams, result: ActionResult): Promise<void>;
28
72
  protected StartAndEndActionLog(params: RunActionParams, result: ActionResult): Promise<MJActionExecutionLogEntity>;
@@ -1 +1 @@
1
- {"version":3,"file":"ActionEngine.d.ts","sourceRoot":"","sources":["../../src/generic/ActionEngine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAiD,MAAM,+BAA+B,CAAC;AAGhJ,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,WAAW,EAAE,YAAY,EAAsB,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAIxJ;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,gBAAgB;IAGrD,WAAkB,QAAQ,IAAI,kBAAkB,CAE/C;IAEY,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;IAuCtE,SAAS,CAAC,wBAAwB,CAAC,MAAM,EAAE,sBAAsB,GAAG,WAAW,EAAE;IAqCjF;;OAEG;cACa,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzE;;OAEG;cACa,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAWrE;;;;OAIG;cACa,eAAe,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;cAKxF,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;cAwDjE,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,UAAU,GAAE,OAAc,GAAG,OAAO,CAAC,0BAA0B,CAAC;cAqBxG,YAAY,CAAC,SAAS,EAAE,0BAA0B,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY;cAcjG,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,0BAA0B,CAAC;CAM1H"}
1
+ {"version":3,"file":"ActionEngine.d.ts","sourceRoot":"","sources":["../../src/generic/ActionEngine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAA8C,oBAAoB,EAAiD,MAAM,+BAA+B,CAAC;AAG5L,OAAO,EACH,gBAAgB,EAChB,sBAAsB,EACtB,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,eAAe,EAGlB,MAAM,8BAA8B,CAAC;AAMtC;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,gBAAgB;IAGrD,WAAkB,QAAQ,IAAI,kBAAkB,CAE/C;IAED;;;;;;OAMG;IACH,SAAS,KAAK,sBAAsB,IAAI,MAAM,CAE7C;IAEY,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;IAqCtE;;;;;;;;;;;OAWG;cACa,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;IAgFpF,SAAS,CAAC,wBAAwB,CAAC,MAAM,EAAE,sBAAsB,GAAG,WAAW,EAAE;IAqCjF;;OAEG;cACa,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzE;;OAEG;cACa,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAWrE;;;;OAIG;cACa,eAAe,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;cAKxF,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;IAqDjF;;;;OAIG;cACa,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAYzF;;;;;;;;;;;;;;;OAeG;cACa,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;cA6FtE,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,UAAU,GAAE,OAAc,GAAG,OAAO,CAAC,0BAA0B,CAAC;cAqBxG,YAAY,CAAC,SAAS,EAAE,0BAA0B,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY;cAoBjG,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,0BAA0B,CAAC;CAM1H"}
@@ -1,7 +1,8 @@
1
1
  import { LogError, Metadata } from "@memberjunction/core";
2
2
  import { MJGlobal, SafeJSONParse, UUIDsEqual } from "@memberjunction/global";
3
3
  import { BaseAction } from "./BaseAction.js";
4
- import { ActionEngineBase } from "@memberjunction/actions-base";
4
+ import { ActionEngineBase, RuntimeActionConfigurationSchema, RuntimeActionBridgeBuilder } from "@memberjunction/actions-base";
5
+ import { RuntimeActionExecutor } from "@memberjunction/action-runtime";
5
6
  /**
6
7
  * Base class for executing actions. This class can be sub-classed if desired if you would like to modify the logic across ALL actions. To do so, sub-class this class and use the
7
8
  * @RegisterClass decorator from the @memberjunction/global package to register your sub-class with the ClassFactory. This will cause your sub-class to be used instead of this base class when the Metadata object insantiates the ActionEngine.
@@ -10,6 +11,16 @@ export class ActionEngineServer extends ActionEngineBase {
10
11
  static get Instance() {
11
12
  return super.getInstance();
12
13
  }
14
+ /**
15
+ * Engine-default wall-clock timeout applied to any action whose
16
+ * `MaxExecutionTimeMS` is NULL. Intentionally generous (2 hours) because
17
+ * some integration actions do legitimately long sync work; per-action
18
+ * overrides should be used to tighten this for anything agent-facing.
19
+ * Sub-classes can override to globally change the default.
20
+ */
21
+ get DefaultActionTimeoutMS() {
22
+ return 2 * 60 * 60 * 1000;
23
+ }
13
24
  async RunAction(params) {
14
25
  const validInputs = await this.ValidateInputs(params);
15
26
  if (!validInputs) {
@@ -39,8 +50,90 @@ export class ActionEngineServer extends ActionEngineBase {
39
50
  result.LogEntry = await this.StartAndEndActionLog(params, result);
40
51
  }
41
52
  }
42
- const runActionResult = await this.InternalRunAction(params);
43
- return runActionResult;
53
+ return await this.RunActionWithTimeout(params);
54
+ }
55
+ /**
56
+ * Wraps `InternalRunAction()` with a universal wall-clock timeout
57
+ * (`Action.MaxExecutionTimeMS`, falling back to `DefaultActionTimeoutMS`)
58
+ * and an `AbortSignal` passed to the action via `params.AbortSignal`.
59
+ *
60
+ * Enforcement is cooperative: when the timeout fires we set an abort on
61
+ * the signal so in-flight `fetch`/`setTimeout`/custom polling logic can
62
+ * short-circuit, and we race the action against a rejection that surfaces
63
+ * a `TIMEOUT` result. If the caller already supplied an `AbortSignal`
64
+ * (e.g. when being run from a Runtime-action bridge that has its own
65
+ * abort), we chain to it so either source can trigger cancellation.
66
+ */
67
+ async RunActionWithTimeout(params) {
68
+ const actionTimeoutMS = params.Action.MaxExecutionTimeMS ?? this.DefaultActionTimeoutMS;
69
+ // Chain with any upstream AbortSignal (e.g. Runtime-action bridge).
70
+ const controller = new AbortController();
71
+ const externalSignal = params.AbortSignal;
72
+ const relayExternalAbort = () => {
73
+ if (!controller.signal.aborted) {
74
+ controller.abort(externalSignal?.reason ?? 'upstream abort');
75
+ }
76
+ };
77
+ if (externalSignal) {
78
+ if (externalSignal.aborted) {
79
+ relayExternalAbort();
80
+ }
81
+ else {
82
+ externalSignal.addEventListener('abort', relayExternalAbort, { once: true });
83
+ }
84
+ }
85
+ // Wall-clock timeout.
86
+ const timeoutId = setTimeout(() => {
87
+ if (!controller.signal.aborted) {
88
+ controller.abort(`Action '${params.Action.Name}' exceeded MaxExecutionTimeMS (${actionTimeoutMS}ms)`);
89
+ }
90
+ }, actionTimeoutMS);
91
+ // Assign the chained signal onto params so BaseAction subclasses can poll it.
92
+ const previousSignal = params.AbortSignal;
93
+ params.AbortSignal = controller.signal;
94
+ try {
95
+ const timeoutPromise = new Promise((_resolve, reject) => {
96
+ controller.signal.addEventListener('abort', () => {
97
+ reject(new Error(String(controller.signal.reason ?? 'aborted')));
98
+ }, { once: true });
99
+ });
100
+ try {
101
+ return await Promise.race([this.InternalRunAction(params), timeoutPromise]);
102
+ }
103
+ catch (err) {
104
+ // Timeout or upstream abort — return a standard TIMEOUT result.
105
+ // Result is left undefined (we don't guarantee a 'TIMEOUT' ActionResultCode
106
+ // exists on every action; the Success flag + Message are the canonical
107
+ // failure signal for timeouts).
108
+ if (controller.signal.aborted) {
109
+ const message = typeof controller.signal.reason === 'string'
110
+ ? controller.signal.reason
111
+ : `Action '${params.Action.Name}' was aborted`;
112
+ const timeoutResult = {
113
+ Success: false,
114
+ Message: message,
115
+ LogEntry: null,
116
+ Params: params.Params,
117
+ RunParams: params,
118
+ Result: undefined
119
+ };
120
+ if (!params.SkipActionLog) {
121
+ timeoutResult.LogEntry = await this.StartAndEndActionLog(params, timeoutResult);
122
+ }
123
+ return timeoutResult;
124
+ }
125
+ // Real runtime error unrelated to abort — rethrow so upstream handling catches it.
126
+ throw err;
127
+ }
128
+ }
129
+ finally {
130
+ clearTimeout(timeoutId);
131
+ if (externalSignal) {
132
+ externalSignal.removeEventListener('abort', relayExternalAbort);
133
+ }
134
+ // Restore whatever AbortSignal the caller had in place so we don't leak our own.
135
+ params.AbortSignal = previousSignal;
136
+ }
44
137
  }
45
138
  GetActionParamsForAction(action) {
46
139
  const params = action.Params.map((param) => {
@@ -104,20 +197,17 @@ export class ActionEngineServer extends ActionEngineBase {
104
197
  // temp stub above, replace with code that will run the filter
105
198
  }
106
199
  async InternalRunAction(params) {
107
- // this is where the actual action code will be implemented
108
- // first, let's get the right BaseAction derived sub-class for this particular action
109
- // using ClassFactory
110
200
  let logEntry;
111
201
  if (!params.SkipActionLog) {
112
202
  logEntry = await this.StartActionLog(params);
113
203
  }
114
204
  try {
115
- const action = MJGlobal.Instance.ClassFactory.CreateInstance(BaseAction, params.Action.DriverClass || params.Action.Name, params.ContextUser);
116
- if (!action || action.constructor === BaseAction) {
117
- throw new Error(`Could not find a class for action ${params.Action.Name}.`);
118
- }
119
- // we now have the action class for this particular action, so run it
120
- const simpleResult = await action.Run(params);
205
+ // Branch by Action.Type. Runtime actions go through the sandboxed
206
+ // RuntimeActionExecutor; Custom / Generated (and legacy rows where
207
+ // Type may be null) flow through the existing ClassFactory path.
208
+ const simpleResult = params.Action.Type === 'Runtime'
209
+ ? await this.RunRuntimeAction(params)
210
+ : await this.RunClassBasedAction(params);
121
211
  const resultCodeEntity = this.ActionResultCodes.find(r => UUIDsEqual(r.ActionID, params.Action.ID) &&
122
212
  r.ResultCode.trim().toLowerCase() === simpleResult.ResultCode.trim().toLowerCase());
123
213
  const result = {
@@ -126,7 +216,7 @@ export class ActionEngineServer extends ActionEngineBase {
126
216
  Message: simpleResult.Message,
127
217
  AIDirectives: simpleResult.AIDirectives,
128
218
  LogEntry: logEntry,
129
- Params: simpleResult.Params || params.Params, // use the params from the simple result if provided, otherwise use the original params
219
+ Params: simpleResult.Params || params.Params,
130
220
  Result: resultCodeEntity
131
221
  };
132
222
  if (logEntry) {
@@ -151,6 +241,111 @@ export class ActionEngineServer extends ActionEngineBase {
151
241
  return result;
152
242
  }
153
243
  }
244
+ /**
245
+ * Resolves and runs a Custom / Generated action via the ClassFactory.
246
+ * This is the pre-existing path — factored out of `InternalRunAction` so
247
+ * the Type dispatch is readable.
248
+ */
249
+ async RunClassBasedAction(params) {
250
+ const action = MJGlobal.Instance.ClassFactory.CreateInstance(BaseAction, params.Action.DriverClass || params.Action.Name, params.ContextUser);
251
+ if (!action || action.constructor === BaseAction) {
252
+ throw new Error(`Could not find a class for action ${params.Action.Name}.`);
253
+ }
254
+ return await action.Run(params);
255
+ }
256
+ /**
257
+ * Runs an `Action.Type='Runtime'` action by delegating to the sandboxed
258
+ * RuntimeActionExecutor. Approval / Status / Code-presence checks are
259
+ * enforced inside the executor; here we parse the RuntimeActionConfiguration,
260
+ * build the permissioned bridge-handler map, and hand it off.
261
+ *
262
+ * The bridge handlers run in-process on the host (not inside the sandbox)
263
+ * so they have full access to Metadata, RunView, ActionEngine, etc.
264
+ * Permission enforcement against `RuntimeActionConfiguration.permissions`
265
+ * happens inside each handler — see `RuntimeActionBridge.ts`.
266
+ *
267
+ * If the configuration is missing or malformed, we still let the action
268
+ * run in pure-compute mode (no bridge). The action's Code can then only
269
+ * use `input` + `libs`; any attempt to call `utilities.*` at runtime
270
+ * rejects with a "handler not registered" error from the worker pool.
271
+ */
272
+ async RunRuntimeAction(params) {
273
+ // Extract + validate the RuntimeActionConfiguration JSON blob. Uses
274
+ // the strongly-typed accessor from @memberjunction/core-entities
275
+ // (emitted by the JSONType codegen) rather than parsing the raw string.
276
+ const actionEntity = params.Action;
277
+ const rawConfig = actionEntity.RuntimeActionConfigurationObject;
278
+ let bridgeHandlers;
279
+ let preamble = '';
280
+ let maxBridgeCalls;
281
+ if (rawConfig) {
282
+ const parsed = RuntimeActionConfigurationSchema.safeParse(rawConfig);
283
+ if (!parsed.success) {
284
+ return {
285
+ Success: false,
286
+ ResultCode: 'INVALID_CONFIG',
287
+ Message: `Runtime action '${params.Action.Name}' has a malformed ` +
288
+ `RuntimeActionConfiguration: ${parsed.error.message}`,
289
+ Params: params.Params
290
+ };
291
+ }
292
+ // Cast to the JSONType-emitted interface: the Zod-inferred type
293
+ // has optional fields due to how `z.object()` composes with this
294
+ // repo's non-strict TS config; the runtime validation above has
295
+ // already proven the shape is valid, so the narrowing cast is safe.
296
+ const config = parsed.data;
297
+ // Resolve the concrete bridge builder via MJ's ClassFactory. The
298
+ // implementation lives in `@memberjunction/action-runtime-host`
299
+ // (top of the stack — can statically import AIEngine, AgentRunner,
300
+ // ActionEngineServer, etc. without creating a cycle). If nothing
301
+ // is registered (the host package wasn't imported), we fall through
302
+ // to pure-compute mode: the user's Runtime action still runs, it
303
+ // just can't call any `utilities.*` bridge namespaces.
304
+ const builder = MJGlobal.Instance.ClassFactory.CreateInstance(RuntimeActionBridgeBuilder);
305
+ if (builder) {
306
+ bridgeHandlers = builder.BuildHandlers({
307
+ action: params.Action,
308
+ config,
309
+ contextUser: params.ContextUser,
310
+ abortSignal: params.AbortSignal
311
+ });
312
+ preamble = builder.GetPreamble();
313
+ }
314
+ maxBridgeCalls = config.limits?.maxBridgeCalls;
315
+ }
316
+ // If we built a preamble, inject it BEFORE the user's code so
317
+ // `globalThis.utilities` is available from the first line. The
318
+ // executor wraps everything in an async IIFE — the preamble runs
319
+ // inside that same IIFE.
320
+ const codeToRun = preamble
321
+ ? `${preamble}\n${params.Action.Code ?? ''}`
322
+ : params.Action.Code ?? '';
323
+ // We mutate a defensive copy of the action entity so the executor sees
324
+ // the prepended preamble without modifying the live MJActionEntity
325
+ // instance (which the rest of the ActionEngine may still reference).
326
+ const actionForExecution = Object.create(Object.getPrototypeOf(params.Action), Object.getOwnPropertyDescriptors(params.Action));
327
+ // The executor checks `action.Code`; override just that getter.
328
+ Object.defineProperty(actionForExecution, 'Code', {
329
+ value: codeToRun,
330
+ writable: false,
331
+ enumerable: true,
332
+ configurable: true
333
+ });
334
+ const execResult = await RuntimeActionExecutor.Instance.execute({
335
+ action: actionForExecution,
336
+ params: params.Params ?? [],
337
+ contextUser: params.ContextUser,
338
+ abortSignal: params.AbortSignal,
339
+ bridgeHandlers,
340
+ maxBridgeCalls
341
+ });
342
+ return {
343
+ Success: execResult.success,
344
+ ResultCode: execResult.resultCode,
345
+ Message: execResult.message,
346
+ Params: execResult.params
347
+ };
348
+ }
154
349
  async StartActionLog(params, saveRecord = true) {
155
350
  // this is where the log entry for the action run will be created
156
351
  const md = new Metadata();
@@ -173,7 +368,13 @@ export class ActionEngineServer extends ActionEngineBase {
173
368
  async EndActionLog(logEntity, params, result) {
174
369
  // this is where the log entry for the action run will be created
175
370
  logEntity.EndedAt = new Date();
176
- logEntity.Params = JSON.stringify(params.Params);
371
+ // Persist the final merged param set (inputs + outputs) — Runtime actions
372
+ // return a fresh array from the sandbox executor that lives on
373
+ // `result.Params`, so logging `params.Params` would lose every new output
374
+ // key. Custom/Generated actions mutate `params.Params` in place, and
375
+ // `result.Params` falls back to that same reference, so they remain
376
+ // equivalent.
377
+ logEntity.Params = JSON.stringify(result.Params ?? params.Params);
177
378
  logEntity.ResultCode = result.Result?.ResultCode;
178
379
  logEntity.Message = result.Message;
179
380
  // save a second time to record the action ending
@@ -1 +1 @@
1
- {"version":3,"file":"ActionEngine.js","sourceRoot":"","sources":["../../src/generic/ActionEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ActionEngine.js","sourceRoot":"","sources":["../../src/generic/ActionEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EACH,gBAAgB,EAMhB,gCAAgC,EAChC,0BAA0B,EAC7B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAKvE;;;GAGG;AACH,MAAM,OAAO,kBAAmB,SAAQ,gBAAgB;IAG9C,MAAM,KAAK,QAAQ;QACvB,OAAO,KAAK,CAAC,WAAW,EAAsB,CAAC;IAClD,CAAC;IAED;;;;;;OAMG;IACH,IAAc,sBAAsB;QACjC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC7B,CAAC;IAEM,KAAK,CAAC,SAAS,CAAC,MAAuB;QAC3C,MAAM,WAAW,GAAY,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC/D,IAAG,CAAC,WAAW,EAAC,CAAC;YACd,MAAM,MAAM,GAAiB;gBAC1B,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,uDAAuD;gBAChE,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,SAAS,EAAE,MAAM;aACnB,CAAC;YAEF,IAAG,CAAC,MAAM,CAAC,aAAa,EAAC,CAAC;gBACvB,MAAM,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACrE,CAAC;YAED,OAAO,MAAM,CAAC;QACjB,CAAC;QAED,MAAM,aAAa,GAAY,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC7D,IAAG,CAAC,aAAa,EAAC,CAAC;YAChB,kDAAkD;YAClD,MAAM,MAAM,GAAiB;gBAC1B,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,kKAAkK;gBAC3K,QAAQ,EAAE,IAAI,EAAE,iBAAiB;gBACjC,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,SAAS,EAAE,MAAM;aACnB,CAAC;YAEF,IAAG,CAAC,MAAM,CAAC,aAAa,EAAC,CAAC;gBACvB,MAAM,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACrE,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED;;;;;;;;;;;OAWG;IACO,KAAK,CAAC,oBAAoB,CAAC,MAAuB;QACzD,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,kBAAkB,IAAI,IAAI,CAAC,sBAAsB,CAAC;QAExF,oEAAoE;QACpE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC;QAC1C,MAAM,kBAAkB,GAAG,GAAG,EAAE;YAC7B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC9B,UAAU,CAAC,KAAK,CAAC,cAAc,EAAE,MAAM,IAAI,gBAAgB,CAAC,CAAC;YAChE,CAAC;QACJ,CAAC,CAAC;QACF,IAAI,cAAc,EAAE,CAAC;YAClB,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;gBAC1B,kBAAkB,EAAE,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACL,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAChF,CAAC;QACJ,CAAC;QAED,sBAAsB;QACtB,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAC/B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC9B,UAAU,CAAC,KAAK,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,IAAI,kCAAkC,eAAe,KAAK,CAAC,CAAC;YACzG,CAAC;QACJ,CAAC,EAAE,eAAe,CAAC,CAAC;QAEpB,8EAA8E;QAC9E,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC;QAC1C,MAAM,CAAC,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC;QAEvC,IAAI,CAAC;YACF,MAAM,cAAc,GAAG,IAAI,OAAO,CAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;gBACnE,UAAU,CAAC,MAAM,CAAC,gBAAgB,CAC/B,OAAO,EACP,GAAG,EAAE;oBACF,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;gBACpE,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CAChB,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC;gBACF,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;YAC/E,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACZ,gEAAgE;gBAChE,4EAA4E;gBAC5E,uEAAuE;gBACvE,gCAAgC;gBAChC,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;oBAC7B,MAAM,OAAO,GACV,OAAO,UAAU,CAAC,MAAM,CAAC,MAAM,KAAK,QAAQ;wBACzC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM;wBAC1B,CAAC,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC;oBACrD,MAAM,aAAa,GAAiB;wBACjC,OAAO,EAAE,KAAK;wBACd,OAAO,EAAE,OAAO;wBAChB,QAAQ,EAAE,IAAI;wBACd,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,SAAS,EAAE,MAAM;wBACjB,MAAM,EAAE,SAAS;qBACnB,CAAC;oBACF,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;wBACzB,aAAa,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;oBACnF,CAAC;oBACD,OAAO,aAAa,CAAC;gBACxB,CAAC;gBACD,mFAAmF;gBACnF,MAAM,GAAG,CAAC;YACb,CAAC;QACJ,CAAC;gBAAS,CAAC;YACR,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,IAAI,cAAc,EAAE,CAAC;gBAClB,cAAc,CAAC,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACnE,CAAC;YACD,iFAAiF;YACjF,MAAM,CAAC,WAAW,GAAG,cAAc,CAAC;QACvC,CAAC;IACJ,CAAC;IAGS,wBAAwB,CAAC,MAA8B;QAC9D,MAAM,MAAM,GAAkB,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAA0B,EAAE,EAAE;YAC5E,IAAI,KAAK,GAAQ,IAAI,CAAC;YACtB,QAAQ,KAAK,CAAC,SAAS,EAAE,CAAC;gBACvB,KAAK,QAAQ;oBACV,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC;oBAC3B,MAAM;gBACT,KAAK,eAAe;oBACjB,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;oBACpD,IAAI,SAAS,EAAC,CAAC;wBACZ,KAAK,GAAG,SAAS,CAAC;oBACrB,CAAC;yBACG,CAAC;wBACF,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC;oBAC9B,CAAC;oBACD,MAAM;gBACT,KAAK,sBAAsB,CAAC;gBAC5B,KAAK,OAAO;oBACT,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC;oBAC3B,MAAM;gBACT;oBACG,QAAQ,CAAC,qBAAqB,KAAK,CAAC,SAAS,cAAc,KAAK,CAAC,IAAI,cAAc,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;oBAClG,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC;oBAC3B,MAAM;YAEZ,CAAC;YAED,OAAO;gBACJ,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,KAAK,CAAC,IAAI;aAClB,CAAA;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;IACjB,CAAC;IAED;;OAEG;IACO,KAAK,CAAC,cAAc,CAAC,MAAuB;QACnD,OAAO,IAAI,CAAC;IACf,CAAC;IAED;;OAEG;IACO,KAAK,CAAC,UAAU,CAAC,MAAuB;QAC/C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAClB,KAAK,IAAI,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjC,IAAI,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;oBAC/C,OAAO,KAAK,CAAC;gBAChB,CAAC;YACJ,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,CAAC,6DAA6D;IAC7E,CAAC;IAED;;;;OAIG;IACO,KAAK,CAAC,eAAe,CAAC,MAAuB,EAAE,MAA4B;QAClF,OAAO,IAAI,CAAC;QACZ,oEAAoE;IACvE,CAAC;IAES,KAAK,CAAC,iBAAiB,CAAC,MAAuB;QACtD,IAAI,QAAgD,CAAC;QACrD,IAAG,CAAC,MAAM,CAAC,aAAa,EAAC,CAAC;YACvB,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC;QAED,IAAI,CAAC;YACF,kEAAkE;YAClE,mEAAmE;YACnE,iEAAiE;YACjE,MAAM,YAAY,GACf,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;gBAC7B,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;gBACrC,CAAC,CAAC,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;YAE/C,MAAM,gBAAgB,GAAyC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClF,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;YAC1I,MAAM,MAAM,GAAiB;gBAC1B,SAAS,EAAE,MAAM;gBACjB,OAAO,EAAE,YAAY,CAAC,OAAO;gBAC7B,OAAO,EAAE,YAAY,CAAC,OAAO;gBAC7B,YAAY,EAAE,YAAY,CAAC,YAAY;gBACvC,QAAQ,EAAE,QAAQ;gBAClB,MAAM,EAAE,YAAY,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM;gBAC5C,MAAM,EAAE,gBAAgB;aAC1B,CAAC;YAEF,IAAG,QAAQ,EAAC,CAAC;gBACV,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;YACrD,CAAC;YAED,OAAO,MAAM,CAAC;QACjB,CAAC;QACD,OAAO,CAAC,EAAE,CAAC;YACR,0DAA0D;YAC1D,QAAQ,CAAC,wBAAwB,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;YAC3D,MAAM,MAAM,GAAiB;gBAC1B,SAAS,EAAE,MAAM;gBACjB,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,wBAAwB,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE;gBACnE,QAAQ,EAAE,QAAQ;gBAClB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,SAAS;aACnB,CAAC;YAEF,IAAG,QAAQ,EAAC,CAAC;gBACV,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;YACrD,CAAC;YAED,OAAO,MAAM,CAAC;QACjB,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACO,KAAK,CAAC,mBAAmB,CAAC,MAAuB;QACxD,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,cAAc,CACzD,UAAU,EACV,MAAM,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAC/C,MAAM,CAAC,WAAW,CACpB,CAAC;QACF,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,qCAAqC,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACO,KAAK,CAAC,gBAAgB,CAAC,MAAuB;QACrD,oEAAoE;QACpE,iEAAiE;QACjE,wEAAwE;QACxE,MAAM,YAAY,GAAG,MAAM,CAAC,MAE3B,CAAC;QACF,MAAM,SAAS,GAAG,YAAY,CAAC,gCAAgC,CAAC;QAEhE,IAAI,cAA4C,CAAC;QACjD,IAAI,QAAQ,GAAG,EAAE,CAAC;QAClB,IAAI,cAAkC,CAAC;QAEvC,IAAI,SAAS,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,gCAAgC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACrE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO;oBACJ,OAAO,EAAE,KAAK;oBACd,UAAU,EAAE,gBAAgB;oBAC5B,OAAO,EACJ,mBAAmB,MAAM,CAAC,MAAM,CAAC,IAAI,oBAAoB;wBACzD,+BAA+B,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;oBACxD,MAAM,EAAE,MAAM,CAAC,MAAM;iBACvB,CAAC;YACL,CAAC;YACD,gEAAgE;YAChE,iEAAiE;YACjE,gEAAgE;YAChE,oEAAoE;YACpE,MAAM,MAAM,GAAG,MAAM,CAAC,IAA6D,CAAC;YAEpF,iEAAiE;YACjE,gEAAgE;YAChE,mEAAmE;YACnE,iEAAiE;YACjE,oEAAoE;YACpE,iEAAiE;YACjE,uDAAuD;YACvD,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,cAAc,CAC1D,0BAA0B,CAC5B,CAAC;YACF,IAAI,OAAO,EAAE,CAAC;gBACX,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;oBACpC,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,MAAM;oBACN,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;iBACjC,CAAC,CAAC;gBACH,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;YACpC,CAAC;YACD,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC;QAClD,CAAC;QAED,8DAA8D;QAC9D,+DAA+D;QAC/D,iEAAiE;QACjE,yBAAyB;QACzB,MAAM,SAAS,GAAG,QAAQ;YACvB,CAAC,CAAC,GAAG,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,EAAE;YAC5C,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QAE9B,uEAAuE;QACvE,mEAAmE;QACnE,qEAAqE;QACrE,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CACrC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,EACpC,MAAM,CAAC,yBAAyB,CAAC,MAAM,CAAC,MAAM,CAAC,CACzB,CAAC;QAC1B,gEAAgE;QAChE,MAAM,CAAC,cAAc,CAAC,kBAAkB,EAAE,MAAM,EAAE;YAC/C,KAAK,EAAE,SAAS;YAChB,QAAQ,EAAE,KAAK;YACf,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,IAAI;SACpB,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC7D,MAAM,EAAE,kBAAkB;YAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;YAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,cAAc;YACd,cAAc;SAChB,CAAC,CAAC;QAEH,OAAO;YACJ,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,UAAU,EAAE,UAAU,CAAC,UAAU;YACjC,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,MAAM,EAAE,UAAU,CAAC,MAAM;SAC3B,CAAC;IACL,CAAC;IAES,KAAK,CAAC,cAAc,CAAC,MAAuB,EAAE,aAAsB,IAAI;QAC/E,iEAAiE;QACjE,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,eAAe,CAA6B,2BAA2B,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACtH,SAAS,CAAC,SAAS,EAAE,CAAC;QACtB,SAAS,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,SAAS,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QACjC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,qHAAqH;QACrH,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAEjD,IAAI,UAAU,EAAC,CAAC;YACb,+GAA+G;YAC/G,MAAM,UAAU,GAAY,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;YACnD,IAAG,CAAC,UAAU,EAAC,CAAC;gBACb,QAAQ,CAAC,oCAAoC,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;YAC1G,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC;IACpB,CAAC;IACS,KAAK,CAAC,YAAY,CAAC,SAAqC,EAAE,MAAuB,EAAE,MAAoB;QAC9G,iEAAiE;QACjE,SAAS,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC;QAC/B,0EAA0E;QAC1E,+DAA+D;QAC/D,0EAA0E;QAC1E,qEAAqE;QACrE,oEAAoE;QACpE,cAAc;QACd,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;QAClE,SAAS,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;QACjD,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,iDAAiD;QACjD,MAAM,UAAU,GAAY,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QACnD,IAAG,CAAC,UAAU,EAAC,CAAC;YACb,QAAQ,CAAC,kCAAkC,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;QACxG,CAAC;IACJ,CAAC;IAES,KAAK,CAAC,oBAAoB,CAAC,MAAuB,EAAE,MAAoB;QAC/E,4BAA4B;QAC5B,MAAM,SAAS,GAA+B,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACvF,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACnD,OAAO,SAAS,CAAC;IACpB,CAAC;CACH"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@memberjunction/actions",
3
3
  "type": "module",
4
- "version": "5.28.0",
4
+ "version": "5.30.0",
5
5
  "description": "Main library for MemberJunction Actions. This library is only intended to be imported on the server side.",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -11,7 +11,8 @@
11
11
  "scripts": {
12
12
  "start": "ts-node-dev src/index.ts",
13
13
  "build": "tsc && tsc-alias -f",
14
- "test": "echo \"No tests configured yet\""
14
+ "test": "vitest run",
15
+ "test:watch": "vitest"
15
16
  },
16
17
  "author": "MemberJunction.com",
17
18
  "license": "ISC",
@@ -20,15 +21,14 @@
20
21
  "typescript": "^5.9.3"
21
22
  },
22
23
  "dependencies": {
23
- "@memberjunction/global": "5.28.0",
24
- "@memberjunction/core": "5.28.0",
25
- "@memberjunction/actions-base": "5.28.0",
26
- "@memberjunction/core-entities": "5.28.0",
27
- "@memberjunction/ai": "5.28.0",
28
- "@memberjunction/ai-core-plus": "5.28.0",
29
- "@memberjunction/aiengine": "5.28.0",
30
- "@memberjunction/ai-prompts": "5.28.0",
31
- "@memberjunction/doc-utils": "5.28.0"
24
+ "@memberjunction/action-runtime": "5.30.0",
25
+ "@memberjunction/actions-base": "5.30.0",
26
+ "@memberjunction/ai": "5.30.0",
27
+ "@memberjunction/code-execution": "5.30.0",
28
+ "@memberjunction/core": "5.30.0",
29
+ "@memberjunction/core-entities": "5.30.0",
30
+ "@memberjunction/doc-utils": "5.30.0",
31
+ "@memberjunction/global": "5.30.0"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",
package/readme.md DELETED
@@ -1,416 +0,0 @@
1
- # @memberjunction/actions
2
-
3
- Server-side action execution engine for MemberJunction. This package provides the runtime infrastructure for executing actions — including input validation, filter evaluation, ClassFactory-based action dispatch, execution logging, OAuth token management, and entity-bound action invocation. It is intended for server-side use only.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @memberjunction/actions
9
- ```
10
-
11
- ## Overview
12
-
13
- The Actions Engine sits between external consumers (AI agents, workflows, APIs) and the actual action implementations registered via `@RegisterClass`. It handles the full execution lifecycle: validating inputs, running pre-execution filters, dispatching to the correct `BaseAction` subclass via ClassFactory, and logging results.
14
-
15
- The package contains two subsystems:
16
-
17
- - **Generic Action Engine** — Executes standalone actions with validation, filtering, and logging
18
- - **Entity Action Engine** — Executes actions bound to entity records, supporting CRUD lifecycle hooks, list/view batch operations, and record validation
19
-
20
- ```mermaid
21
- flowchart TD
22
- subgraph Consumers["External Consumers"]
23
- Agent["AI Agents"]
24
- WF["Workflows"]
25
- API["GraphQL API"]
26
- end
27
-
28
- subgraph Engine["@memberjunction/actions"]
29
- AES["ActionEngineServer"]
30
- EAES["EntityActionEngineServer"]
31
- end
32
-
33
- subgraph Pipeline["Execution Pipeline"]
34
- Validate["Validate Inputs"]
35
- Filter["Run Filters"]
36
- Dispatch["ClassFactory Dispatch"]
37
- Log["Execution Logging"]
38
- end
39
-
40
- subgraph Actions["Registered Actions"]
41
- BA["BaseAction Subclasses"]
42
- OAuth["BaseOAuthAction Subclasses"]
43
- end
44
-
45
- Consumers --> Engine
46
- AES --> Validate --> Filter --> Dispatch --> Log
47
- Dispatch --> BA
48
- Dispatch --> OAuth
49
- EAES --> AES
50
-
51
- style Consumers fill:#2d6a9f,stroke:#1a4971,color:#fff
52
- style Engine fill:#7c5295,stroke:#563a6b,color:#fff
53
- style Pipeline fill:#2d8659,stroke:#1a5c3a,color:#fff
54
- style Actions fill:#b8762f,stroke:#8a5722,color:#fff
55
- ```
56
-
57
- ## Key Features
58
-
59
- - **Action Execution Pipeline** — Validates inputs, evaluates filters, dispatches via ClassFactory, and logs all executions
60
- - **ClassFactory Dispatch** — Looks up `BaseAction` subclasses by `DriverClass` or action name at runtime
61
- - **Pre-Execution Filters** — `BaseActionFilter` subclasses can gate whether an action should run
62
- - **Execution Logging** — Automatic start/end logging to `Action Execution Logs` entity with params and result codes
63
- - **OAuth Token Management** — `BaseOAuthAction` provides token lifecycle (refresh, retry on auth failure, persistence)
64
- - **OAuth2Manager** — Standalone OAuth2 client supporting authorization code, client credentials, and refresh token flows
65
- - **Entity Action Invocation** — Bind actions to entity CRUD lifecycle events (BeforeCreate, AfterUpdate, etc.)
66
- - **Batch Entity Actions** — Run actions against Lists or Views of records with consolidated results
67
- - **Script Evaluation** — Entity action params support runtime script evaluation with entity context
68
-
69
- ## Usage
70
-
71
- ### Running a Standalone Action
72
-
73
- ```typescript
74
- import { ActionEngineServer } from '@memberjunction/actions';
75
-
76
- // Configure the engine (typically done once at startup)
77
- await ActionEngineServer.Instance.Config(false, contextUser);
78
-
79
- // Find the action by name
80
- const action = ActionEngineServer.Instance.Actions.find(a => a.Name === 'Send Email');
81
-
82
- // Execute it
83
- const result = await ActionEngineServer.Instance.RunAction({
84
- Action: action,
85
- ContextUser: contextUser,
86
- Params: [
87
- { Name: 'to', Value: 'user@example.com', Type: 'Input' },
88
- { Name: 'subject', Value: 'Hello', Type: 'Input' },
89
- { Name: 'body', Value: 'Message content', Type: 'Input' }
90
- ],
91
- Filters: []
92
- });
93
-
94
- if (result.Success) {
95
- console.log('Action completed:', result.Message);
96
- } else {
97
- console.error('Action failed:', result.Message);
98
- }
99
- ```
100
-
101
- ### Creating a Custom Action
102
-
103
- All actions extend `BaseAction` and implement `InternalRunAction`. Register them with `@RegisterClass` so the engine can discover them via ClassFactory:
104
-
105
- ```typescript
106
- import { RegisterClass } from '@memberjunction/global';
107
- import { BaseAction } from '@memberjunction/actions';
108
- import { RunActionParams, ActionResultSimple } from '@memberjunction/actions-base';
109
-
110
- @RegisterClass(BaseAction, 'My Custom Action')
111
- export class MyCustomAction extends BaseAction {
112
- protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
113
- const inputValue = params.Params.find(p => p.Name === 'input')?.Value;
114
-
115
- // Your action logic here
116
- const result = await this.doWork(inputValue);
117
-
118
- return {
119
- Success: true,
120
- ResultCode: 'SUCCESS',
121
- Message: `Processed: ${result}`
122
- };
123
- }
124
-
125
- private async doWork(input: string): Promise<string> {
126
- // Delegate to service classes for real logic
127
- return `Done with ${input}`;
128
- }
129
- }
130
- ```
131
-
132
- ### Creating an OAuth-Authenticated Action
133
-
134
- For actions that need to call external APIs with OAuth2 credentials:
135
-
136
- ```typescript
137
- import { RegisterClass } from '@memberjunction/global';
138
- import { BaseOAuthAction } from '@memberjunction/actions';
139
- import { RunActionParams, ActionResultSimple } from '@memberjunction/actions-base';
140
-
141
- @RegisterClass(BaseAction, 'Fetch External Data')
142
- export class FetchExternalDataAction extends BaseOAuthAction {
143
- protected async refreshAccessToken(): Promise<void> {
144
- // Platform-specific token refresh logic
145
- const response = await fetch('https://api.example.com/oauth/token', {
146
- method: 'POST',
147
- body: new URLSearchParams({
148
- grant_type: 'refresh_token',
149
- refresh_token: this.getRefreshToken(),
150
- })
151
- });
152
- const data = await response.json();
153
- await this.updateStoredTokens(data.access_token, data.refresh_token, data.expires_in);
154
- }
155
-
156
- protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
157
- const companyIntegrationId = params.Params.find(
158
- p => p.Name === 'CompanyIntegrationID'
159
- )?.Value as string;
160
-
161
- // Initialize OAuth (loads tokens, refreshes if expired)
162
- if (!await this.initializeOAuth(companyIntegrationId)) {
163
- return this.handleOAuthError(new Error('OAuth initialization failed'));
164
- }
165
-
166
- // Make authenticated request with automatic retry on 401
167
- const data = await this.makeAuthenticatedRequest(async (token) => {
168
- const res = await fetch('https://api.example.com/data', {
169
- headers: { Authorization: `Bearer ${token}` }
170
- });
171
- return res.json();
172
- });
173
-
174
- return { Success: true, ResultCode: 'SUCCESS', Message: JSON.stringify(data) };
175
- }
176
- }
177
- ```
178
-
179
- ### Using OAuth2Manager Directly
180
-
181
- For standalone OAuth2 token management outside the action framework:
182
-
183
- ```typescript
184
- import { OAuth2Manager } from '@memberjunction/actions';
185
-
186
- const oauth = new OAuth2Manager({
187
- clientId: 'your-client-id',
188
- clientSecret: 'your-client-secret',
189
- tokenEndpoint: 'https://api.example.com/oauth/token',
190
- scopes: ['read', 'write'],
191
- onTokenUpdate: async (tokens) => {
192
- // Persist tokens to your storage
193
- await saveTokens(tokens);
194
- }
195
- });
196
-
197
- // Get a valid token (auto-refreshes if expired)
198
- const token = await oauth.getAccessToken();
199
-
200
- // Or use client credentials flow
201
- const tokenData = await oauth.getClientCredentialsToken();
202
- ```
203
-
204
- ## Architecture
205
-
206
- ### Action Execution Pipeline
207
-
208
- The `ActionEngineServer.RunAction()` method follows this sequence:
209
-
210
- ```mermaid
211
- sequenceDiagram
212
- participant Caller
213
- participant Engine as ActionEngineServer
214
- participant Filter as BaseActionFilter
215
- participant CF as ClassFactory
216
- participant Action as BaseAction Subclass
217
- participant Log as Execution Log
218
-
219
- Caller->>Engine: RunAction(params)
220
- Engine->>Engine: ValidateInputs(params)
221
- alt Validation fails
222
- Engine->>Log: StartAndEndActionLog()
223
- Engine-->>Caller: {Success: false}
224
- end
225
- Engine->>Filter: RunFilters(params)
226
- alt Filters block execution
227
- Engine->>Log: StartAndEndActionLog()
228
- Engine-->>Caller: {Success: true, "Filters blocked"}
229
- end
230
- Engine->>Log: StartActionLog()
231
- Engine->>CF: CreateInstance(BaseAction, driverClass)
232
- CF-->>Engine: action instance
233
- Engine->>Action: Run(params)
234
- Action->>Action: InternalRunAction(params)
235
- Action-->>Engine: ActionResultSimple
236
- Engine->>Log: EndActionLog()
237
- Engine-->>Caller: ActionResult
238
- ```
239
-
240
- ### Entity Action Invocation
241
-
242
- Entity actions are bound to entity lifecycle events. The `EntityActionEngineServer` delegates to invocation-type-specific handlers via ClassFactory:
243
-
244
- ```mermaid
245
- classDiagram
246
- class EntityActionInvocationBase {
247
- <<abstract>>
248
- +InvokeAction(params) EntityActionResult
249
- +MapParams(params, entityActionParams, entity) ActionParam[]
250
- +SafeEvalScript(id, script, entity) any
251
- }
252
-
253
- class SingleRecord {
254
- +InvokeAction(params) EntityActionResult
255
- +ValidateParams(params) boolean
256
- }
257
-
258
- class MultipleRecords {
259
- +InvokeAction(params) EntityActionResult
260
- #GetRecordList() BaseEntity[]
261
- }
262
-
263
- class Validate {
264
- +InvokeAction(params) EntityActionResult
265
- }
266
-
267
- EntityActionInvocationBase <|-- SingleRecord
268
- EntityActionInvocationBase <|-- MultipleRecords
269
- SingleRecord <|-- Validate
270
-
271
- note for SingleRecord "Registered for: Read, BeforeCreate,\nBeforeUpdate, BeforeDelete, AfterCreate,\nAfterUpdate, AfterDelete, SingleRecord"
272
- note for MultipleRecords "Registered for: List, View"
273
- note for Validate "Registered for: Validate"
274
- ```
275
-
276
- ### Class Hierarchy
277
-
278
- ```mermaid
279
- classDiagram
280
- class BaseAction {
281
- <<abstract>>
282
- +Run(params) ActionResultSimple
283
- #InternalRunAction(params)* ActionResultSimple
284
- }
285
-
286
- class BaseOAuthAction {
287
- <<abstract>>
288
- #initializeOAuth(id) boolean
289
- #getAccessToken() string
290
- #makeAuthenticatedRequest(fn) T
291
- #refreshAccessToken()* void
292
- }
293
-
294
- class BaseActionFilter {
295
- <<abstract>>
296
- +Run(params, filter) boolean
297
- #InternalRun(params, filter)* boolean
298
- }
299
-
300
- class ActionEngineServer {
301
- +RunAction(params) ActionResult
302
- #ValidateInputs(params) boolean
303
- #RunFilters(params) boolean
304
- #InternalRunAction(params) ActionResult
305
- }
306
-
307
- class EntityActionEngineServer {
308
- +RunEntityAction(params) EntityActionResult
309
- }
310
-
311
- class OAuth2Manager {
312
- +getAccessToken() string
313
- +getAuthorizationUrl() string
314
- +exchangeAuthorizationCode(code) OAuth2TokenData
315
- +getClientCredentialsToken() OAuth2TokenData
316
- +refreshAccessToken() OAuth2TokenData
317
- }
318
-
319
- BaseAction <|-- BaseOAuthAction
320
- ActionEngineServer --> BaseAction : dispatches to
321
- ActionEngineServer --> BaseActionFilter : evaluates
322
- EntityActionEngineServer --> ActionEngineServer : delegates to
323
- BaseOAuthAction --> OAuth2Manager : can use
324
- ```
325
-
326
- ## API Reference
327
-
328
- ### ActionEngineServer
329
-
330
- Singleton engine that executes actions. Access via `ActionEngineServer.Instance`.
331
-
332
- | Method | Description |
333
- |--------|-------------|
334
- | `Config(forceRefresh, contextUser)` | Initialize/refresh the engine's action and filter metadata |
335
- | `RunAction(params)` | Execute an action through the full pipeline (validate, filter, dispatch, log) |
336
-
337
- ### BaseAction
338
-
339
- Abstract base class for all action implementations.
340
-
341
- | Method | Description |
342
- |--------|-------------|
343
- | `Run(params)` | Public entry point — calls `InternalRunAction` |
344
- | `InternalRunAction(params)` | **Abstract** — implement your action logic here |
345
-
346
- ### BaseOAuthAction
347
-
348
- Abstract base for actions requiring OAuth authentication. Extends `BaseAction`.
349
-
350
- | Method | Description |
351
- |--------|-------------|
352
- | `initializeOAuth(companyIntegrationId)` | Load integration, check/refresh tokens |
353
- | `getAccessToken()` | Get the current access token |
354
- | `makeAuthenticatedRequest(fn)` | Execute a request with automatic retry on 401/403 |
355
- | `refreshAccessToken()` | **Abstract** — implement platform-specific token refresh |
356
- | `updateStoredTokens(access, refresh?, expiresIn?)` | Persist new tokens to the Company Integration entity |
357
- | `handleOAuthError(error)` | Return a standardized error result for OAuth failures |
358
-
359
- ### BaseActionFilter
360
-
361
- Abstract base for pre-execution filters.
362
-
363
- | Method | Description |
364
- |--------|-------------|
365
- | `Run(params, filter)` | Public entry point — calls `InternalRun` |
366
- | `InternalRun(params, filter)` | **Abstract** — implement filter logic, return `true` to allow execution |
367
-
368
- ### EntityActionEngineServer
369
-
370
- Singleton engine for entity-bound actions. Access via `EntityActionEngineServer.Instance`.
371
-
372
- | Method | Description |
373
- |--------|-------------|
374
- | `RunEntityAction(params)` | Execute an entity action, dispatching to the correct invocation type handler |
375
-
376
- ### OAuth2Manager
377
-
378
- Standalone OAuth2 token manager supporting multiple grant types.
379
-
380
- | Method | Description |
381
- |--------|-------------|
382
- | `getAccessToken()` | Get a valid token, auto-refreshing if needed (thread-safe) |
383
- | `getAuthorizationUrl(state?)` | Build the authorization URL for auth code flow |
384
- | `exchangeAuthorizationCode(code)` | Exchange an auth code for tokens |
385
- | `getClientCredentialsToken()` | Obtain tokens via client credentials flow |
386
- | `refreshAccessToken()` | Refresh using the stored refresh token |
387
- | `setTokens(access, refresh?, expiresIn?)` | Set tokens obtained externally |
388
- | `isTokenValid()` | Check if current token is valid (with buffer) |
389
-
390
- ## Dependencies
391
-
392
- This package depends on:
393
-
394
- - [@memberjunction/global](../../MJGlobal/README.md) — ClassFactory and `@RegisterClass` decorator
395
- - [@memberjunction/core](../../MJCore/README.md) — `Metadata`, `RunView`, `BaseEntity`, logging utilities
396
- - [@memberjunction/actions-base](../Base/README.md) — Shared types (`ActionEngineBase`, `RunActionParams`, `ActionResult`, etc.)
397
- - [@memberjunction/core-entities](../../MJCoreEntities/README.md) — Generated entity classes (`ActionExecutionLogEntity`, `ActionFilterEntity`, etc.)
398
- - [@memberjunction/ai](../../AI/Core/README.md) — AI model integration
399
- - [@memberjunction/ai-core-plus](../../AI/CorePlus/README.md) — Extended AI utilities
400
- - [@memberjunction/aiengine](../../AI/Engine/README.md) — AI engine orchestration
401
- - [@memberjunction/ai-prompts](../../AI/Prompts/README.md) — AI prompt execution
402
-
403
- ## Related Packages
404
-
405
- - [@memberjunction/actions-base](../Base/README.md) — Shared types and base classes used by both client and server
406
- - [CoreActions](../CoreActions/) — Built-in action implementations (Create Record, generated actions, etc.)
407
- - [ScheduledActions](../ScheduledActions/) — Scheduled action execution support
408
- - [ApolloEnrichment](../ApolloEnrichment/) — Apollo data enrichment actions
409
- - [ContentAutotag](../ContentAutotag/) — Content auto-tagging actions
410
- - [CodeExecution](../CodeExecution/) — Dynamic code execution actions
411
-
412
- For the Actions system philosophy and development guide, see the [Actions CLAUDE.md](../CLAUDE.md).
413
-
414
- ## Contributing
415
-
416
- See the [MemberJunction Contributing Guide](../../../CONTRIBUTING.md) for development setup and guidelines.