@mastra/temporal 0.4.19 → 0.5.0-alpha.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/dist/worker.js CHANGED
@@ -1,9 +1,14 @@
1
1
  import { t as toWorkflowType } from "./utils-R6cB86BM.js";
2
2
  import { builtinModules } from "module";
3
+ import { validateStepInput, validateStepRequestContext } from "@mastra/core/workflows";
3
4
  import { readFileSync } from "fs";
4
5
  import { writeFile } from "fs/promises";
5
6
  import path, { basename, join } from "path";
6
7
  import { fileURLToPath, pathToFileURL } from "url";
8
+ import { RequestContext } from "@mastra/core/di";
9
+ import { MastraError } from "@mastra/core/error";
10
+ import { toStandardSchema } from "@mastra/core/schema";
11
+ import { ApplicationFailure } from "@temporalio/activity";
7
12
  import { generate } from "@babel/generator";
8
13
  import { parse } from "@babel/parser";
9
14
  import * as t from "@babel/types";
@@ -407,26 +412,18 @@ function createTemporalActivitiesHelperStatements(mastraImportPath, hasMastraBin
407
412
  };
408
413
  }
409
414
 
410
- ${mastraImportPath ? `
411
- function createStep(args) {
412
- return async (params) => {
413
- const { mastra } = await import(${JSON.stringify(mastraImportPath)});
414
- return args.execute({ ...withRequestContext(params), mastra });
415
- };
416
- }
417
- ` : hasMastraBinding ? `
418
- function createStep(args) {
419
- return async (params) => {
420
- return args.execute({ ...withRequestContext(params), mastra });
421
- };
422
- }
423
- ` : `
424
- function createStep(args) {
425
- return async (params) => {
426
- return args.execute(withRequestContext(params));
427
- };
428
- }
429
- `}
415
+ function createStep(args) {
416
+ return {
417
+ inputSchema: args.inputSchema,
418
+ requestContextSchema: args.requestContextSchema,
419
+ execute: async (params) => {
420
+ ${mastraImportPath ? `
421
+ const { mastra } = await import(${JSON.stringify(mastraImportPath)});
422
+ return args.execute({ ...withRequestContext(params), mastra });
423
+ ` : hasMastraBinding ? "return args.execute({ ...withRequestContext(params), mastra });" : "return args.execute(withRequestContext(params));"}
424
+ },
425
+ };
426
+ }
430
427
  `;
431
428
  return parse(helperSource, {
432
429
  sourceType: "module",
@@ -669,6 +666,43 @@ function getWorkflowIdMetadata(workflowConfig, workflowName, filePath) {
669
666
  }
670
667
  throw new Error(`Unable to determine workflow id for ${workflowName} in ${filePath}`);
671
668
  }
669
+ function getStaticKey(property) {
670
+ if (property.computed && t.isTemplateLiteral(property.key) && property.key.expressions.length === 0) return property.key.quasis[0]?.value.cooked ?? null;
671
+ if (property.computed && t.isStringLiteral(property.key)) return property.key.value;
672
+ return getObjectPropertyName(property);
673
+ }
674
+ function isDynamicKey(property) {
675
+ return property.computed && !t.isStringLiteral(property.key) && !(t.isTemplateLiteral(property.key) && property.key.expressions.length === 0);
676
+ }
677
+ function findStaticProperty(object, name) {
678
+ let found = { readable: true };
679
+ for (const property of object.properties) {
680
+ if (t.isSpreadElement(property) || isDynamicKey(property)) {
681
+ found = { readable: false };
682
+ continue;
683
+ }
684
+ if (getStaticKey(property) === name) found = t.isObjectProperty(property) ? {
685
+ readable: true,
686
+ value: property.value
687
+ } : { readable: false };
688
+ }
689
+ return found;
690
+ }
691
+ /**
692
+ * Read at build time so runs started outside `TemporalRun` (Schedules, the Temporal CLI) use the
693
+ * workflow's setting too. `TemporalRun` also sends the setting, which covers `options` the build
694
+ * cannot read.
695
+ */
696
+ function getWorkflowValidateInputs(workflowConfig, workflowName, filePath) {
697
+ const options = findStaticProperty(workflowConfig, "options");
698
+ if (options.readable && !options.value) return;
699
+ if (options.readable && t.isObjectExpression(options.value)) {
700
+ const validateInputs = findStaticProperty(options.value, "validateInputs");
701
+ if (validateInputs.readable && !validateInputs.value) return;
702
+ if (validateInputs.readable && t.isBooleanLiteral(validateInputs.value)) return validateInputs.value.value;
703
+ }
704
+ console.warn(`[@mastra/temporal] Could not read options.validateInputs of ${workflowName} in ${filePath} at build time. Runs started with run.start() or run.startAsync() use the workflow setting. Runs started another way, such as from a Temporal Schedule, check step input.`);
705
+ }
672
706
  /**
673
707
  * The helper runtime lives in its own `.mjs` module so it can be linted and unit-tested
674
708
  * like normal code. We parse that file directly here instead of using `Function#toString()`,
@@ -889,9 +923,11 @@ function getExportedName(node) {
889
923
  * we emit a deterministic exported function whose name matches Temporal's runtime
890
924
  * lookup and whose body delegates into the injected helper runtime.
891
925
  */
892
- function createTemporalWorkflowStatements(exportName, workflowId, workflowIdValue, methods, filePath, includeCommit, stepBindings, workflowBindings, runtimeOptions) {
926
+ function createTemporalWorkflowStatements(exportName, workflowId, workflowIdValue, methods, filePath, includeCommit, stepBindings, workflowBindings, runtimeOptions, validateInputs) {
893
927
  const createWorkflowArgs = [t.cloneNode(workflowId, true)];
894
- if (runtimeOptions) createWorkflowArgs.push(t.cloneNode(runtimeOptions, true));
928
+ const optionProperties = runtimeOptions ? runtimeOptions.properties.map((property) => t.cloneNode(property, true)) : [];
929
+ if (validateInputs !== void 0) optionProperties.push(t.objectProperty(t.identifier("validateInputs"), t.booleanLiteral(validateInputs)));
930
+ if (optionProperties.length > 0) createWorkflowArgs.push(t.objectExpression(optionProperties));
895
931
  let expression = t.callExpression(t.identifier("createWorkflow"), createWorkflowArgs);
896
932
  let mappingOrdinal = 0;
897
933
  for (const method of methods) {
@@ -1026,7 +1062,7 @@ function rewriteWorkflowVariableDeclaration(statement, filePath, state) {
1026
1062
  if (!workflowExport) throw new Error(`Unable to determine workflow export for ${declaration.id.name} in ${filePath}`);
1027
1063
  const { exportName } = workflowExport;
1028
1064
  state.workflowExports.push(workflowExport);
1029
- state.statements.push(...createTemporalWorkflowStatements(exportName, workflowId, workflowIdValue, workflowChain.methods, filePath, state.committedWorkflowNames.has(declaration.id.name), state.stepBindings, state.workflowBindings, state.runtimeOptions));
1065
+ state.statements.push(...createTemporalWorkflowStatements(exportName, workflowId, workflowIdValue, workflowChain.methods, filePath, state.committedWorkflowNames.has(declaration.id.name), state.stepBindings, state.workflowBindings, state.runtimeOptions, getWorkflowValidateInputs(workflowConfig, declaration.id.name, filePath)));
1030
1066
  }
1031
1067
  if (declarations.length > 0) {
1032
1068
  const cloned = declarations.map((declaration) => t.cloneNode(declaration, true));
@@ -1120,6 +1156,36 @@ function getGeneratedActivitiesModulePath(outputDir) {
1120
1156
  function getActivityBindingsPath(outputDir) {
1121
1157
  return path.join(outputDir, ACTIVITY_BINDINGS_FILE_NAME);
1122
1158
  }
1159
+ /**
1160
+ * Activities queued by a Workflow built before `validateInputs` existed carry no flag and run
1161
+ * unchecked. A mismatch is non-retryable because a retry gets the same input.
1162
+ */
1163
+ async function checkStepParams(stepId, { inputSchema, requestContextSchema }, { validateInputs, ...params }) {
1164
+ if (validateInputs !== true) return params;
1165
+ const [input, requestContext] = await Promise.all([validateStepInput({
1166
+ prevOutput: params.inputData,
1167
+ step: { inputSchema: inputSchema && toStandardSchema(inputSchema) },
1168
+ validateInputs: true
1169
+ }), validateStepRequestContext({
1170
+ requestContext: new RequestContext(Object.entries(params.requestContext ?? {})),
1171
+ step: {
1172
+ id: stepId,
1173
+ requestContextSchema: requestContextSchema && toStandardSchema(requestContextSchema)
1174
+ },
1175
+ validateInputs: true
1176
+ })]);
1177
+ const error = input.validationError ?? requestContext.validationError;
1178
+ if (error) throw ApplicationFailure.create({
1179
+ type: error instanceof MastraError ? error.id : error.name,
1180
+ message: error.message,
1181
+ nonRetryable: true,
1182
+ cause: error
1183
+ });
1184
+ return {
1185
+ ...params,
1186
+ inputData: input.inputData
1187
+ };
1188
+ }
1123
1189
  var MastraPlugin = class {
1124
1190
  entryFile;
1125
1191
  projectRoot;
@@ -1175,10 +1241,11 @@ var MastraPlugin = class {
1175
1241
  const generatedActivities = {};
1176
1242
  for (const binding of activityBindings) {
1177
1243
  if (generatedActivities[binding.stepId]) continue;
1178
- generatedActivities[binding.stepId] = async (...args) => {
1244
+ generatedActivities[binding.stepId] = async (params) => {
1179
1245
  const activity = (await this.#loadCompiledActivitiesModule(compiledActivitiesPath))[binding.exportName];
1180
- if (typeof activity !== "function") throw new Error(`Unable to load activity '${binding.exportName}' from ${compiledActivitiesPath}`);
1181
- return activity(...args);
1246
+ if (typeof activity === "function") return activity(params);
1247
+ if (typeof activity?.execute !== "function") throw new Error(`Unable to load activity '${binding.exportName}' from ${compiledActivitiesPath}`);
1248
+ return activity.execute(await checkStepParams(binding.stepId, activity, params));
1182
1249
  };
1183
1250
  }
1184
1251
  return generatedActivities;