@dbos-inc/dbos-sdk 2.11.7-preview.gc208400219 → 2.11.15-preview.gd8ed483d92

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.
Files changed (49) hide show
  1. package/dist/src/authdecorators.js +3 -3
  2. package/dist/src/authdecorators.js.map +1 -1
  3. package/dist/src/client.d.ts +7 -1
  4. package/dist/src/client.d.ts.map +1 -1
  5. package/dist/src/client.js +3 -3
  6. package/dist/src/client.js.map +1 -1
  7. package/dist/src/conductor/conductor.d.ts.map +1 -1
  8. package/dist/src/conductor/conductor.js +18 -0
  9. package/dist/src/conductor/conductor.js.map +1 -1
  10. package/dist/src/conductor/protocol.d.ts +17 -1
  11. package/dist/src/conductor/protocol.d.ts.map +1 -1
  12. package/dist/src/conductor/protocol.js +20 -1
  13. package/dist/src/conductor/protocol.js.map +1 -1
  14. package/dist/src/context.d.ts +1 -0
  15. package/dist/src/context.d.ts.map +1 -1
  16. package/dist/src/context.js +11 -1
  17. package/dist/src/context.js.map +1 -1
  18. package/dist/src/datasource.d.ts +104 -0
  19. package/dist/src/datasource.d.ts.map +1 -0
  20. package/dist/src/datasource.js +141 -0
  21. package/dist/src/datasource.js.map +1 -0
  22. package/dist/src/dbos-executor.d.ts +1 -1
  23. package/dist/src/dbos-executor.d.ts.map +1 -1
  24. package/dist/src/dbos-executor.js +14 -20
  25. package/dist/src/dbos-executor.js.map +1 -1
  26. package/dist/src/dbos-runtime/workflow_management.d.ts +1 -1
  27. package/dist/src/dbos-runtime/workflow_management.d.ts.map +1 -1
  28. package/dist/src/dbos-runtime/workflow_management.js +1 -2
  29. package/dist/src/dbos-runtime/workflow_management.js.map +1 -1
  30. package/dist/src/dbos.d.ts +53 -3
  31. package/dist/src/dbos.d.ts.map +1 -1
  32. package/dist/src/dbos.js +216 -199
  33. package/dist/src/dbos.js.map +1 -1
  34. package/dist/src/decorators.d.ts +8 -1
  35. package/dist/src/decorators.d.ts.map +1 -1
  36. package/dist/src/decorators.js +32 -7
  37. package/dist/src/decorators.js.map +1 -1
  38. package/dist/src/httpServer/server.d.ts +18 -0
  39. package/dist/src/httpServer/server.d.ts.map +1 -1
  40. package/dist/src/httpServer/server.js +113 -1
  41. package/dist/src/httpServer/server.js.map +1 -1
  42. package/dist/src/paramdecorators.js +12 -12
  43. package/dist/src/paramdecorators.js.map +1 -1
  44. package/dist/src/system_database.d.ts +1 -1
  45. package/dist/src/system_database.d.ts.map +1 -1
  46. package/dist/src/workflow.js +1 -1
  47. package/dist/src/workflow.js.map +1 -1
  48. package/dist/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +13 -1
package/dist/src/dbos.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InitContext = exports.DBOS = exports.runAsWorkflowStep = exports.getExecutor = void 0;
3
+ exports.InitContext = exports.DBOS = exports.runInternalStep = exports.getExecutor = void 0;
4
4
  const context_1 = require("./context");
5
5
  const dbos_executor_1 = require("./dbos-executor");
6
6
  const logs_1 = require("./telemetry/logs");
@@ -14,6 +14,7 @@ const middleware_1 = require("./httpServer/middleware");
14
14
  const user_database_1 = require("./user_database");
15
15
  const node_crypto_1 = require("node:crypto");
16
16
  const _1 = require(".");
17
+ const _2 = require(".");
17
18
  const handlerTypes_1 = require("./httpServer/handlerTypes");
18
19
  const lodash_1 = require("lodash");
19
20
  const conductor_1 = require("./conductor/conductor");
@@ -63,23 +64,24 @@ function getExecutor() {
63
64
  return dbos_executor_1.DBOSExecutor.globalInstance;
64
65
  }
65
66
  exports.getExecutor = getExecutor;
66
- function runAsWorkflowStep(callback, funcName, childWFID) {
67
+ function runInternalStep(callback, funcName, childWFID) {
67
68
  if (DBOS.isWithinWorkflow()) {
68
69
  if (DBOS.isInStep()) {
69
70
  // OK to use directly
70
- return dbos_executor_1.DBOSExecutor.globalInstance.runAsStep(callback, funcName, undefined, undefined, childWFID);
71
+ return callback();
71
72
  }
72
73
  else if (DBOS.isInWorkflow()) {
73
74
  const wfctx = (0, context_1.assertCurrentWorkflowContext)();
74
- return dbos_executor_1.DBOSExecutor.globalInstance.runAsStep(callback, funcName, DBOS.workflowID, wfctx.functionIDGetIncrement(), childWFID);
75
+ return dbos_executor_1.DBOSExecutor.globalInstance.runInternalStep(callback, funcName, DBOS.workflowID, // assume DBOS.workflowID is defined because of assertCurrentWorkflowContext call above
76
+ wfctx.functionIDGetIncrement(), childWFID);
75
77
  }
76
78
  else {
77
79
  throw new error_1.DBOSInvalidWorkflowTransitionError(`Invalid call to \`${funcName}\` inside a \`transaction\` or \`procedure\``);
78
80
  }
79
81
  }
80
- return dbos_executor_1.DBOSExecutor.globalInstance.runAsStep(callback, funcName, undefined, undefined, childWFID);
82
+ return callback();
81
83
  }
82
- exports.runAsWorkflowStep = runAsWorkflowStep;
84
+ exports.runInternalStep = runInternalStep;
83
85
  class DBOS {
84
86
  ///////
85
87
  // Lifecycle
@@ -204,6 +206,9 @@ class DBOS {
204
206
  return; // return for cases where process.exit is mocked
205
207
  }
206
208
  await dbos_executor_1.DBOSExecutor.globalInstance.initEventReceivers();
209
+ for (const [_n, ds] of decorators_1.transactionalDataSources) {
210
+ await ds.initialize();
211
+ }
207
212
  if (options?.conductorKey) {
208
213
  if (!options.conductorURL) {
209
214
  const dbosDomain = process.env.DBOS_DOMAIN || 'cloud.dbos.dev';
@@ -310,6 +315,9 @@ class DBOS {
310
315
  await dbos_executor_1.DBOSExecutor.globalInstance.destroy();
311
316
  dbos_executor_1.DBOSExecutor.globalInstance = undefined;
312
317
  }
318
+ for (const [_n, ds] of decorators_1.transactionalDataSources) {
319
+ await ds.destroy();
320
+ }
313
321
  // Reset the global app version and executor ID
314
322
  utils_1.globalParams.appVersion = process.env.DBOS__APPVERSION || '';
315
323
  utils_1.globalParams.wasComputed = false;
@@ -636,9 +644,6 @@ class DBOS {
636
644
  //////
637
645
  // Workflow and other operations
638
646
  //////
639
- static #runAsWorkflowStep(callback, funcName) {
640
- return runAsWorkflowStep(callback, funcName);
641
- }
642
647
  /**
643
648
  * Get the workflow status given a workflow ID
644
649
  * @param workflowID - ID of the workflow
@@ -671,7 +676,7 @@ class DBOS {
671
676
  if (DBOS.isWithinWorkflow() && timeoutSeconds !== undefined) {
672
677
  timerFuncID = (0, context_1.assertCurrentWorkflowContext)().functionIDGetIncrement();
673
678
  }
674
- return await runAsWorkflowStep(async () => {
679
+ return await runInternalStep(async () => {
675
680
  const rres = await dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.awaitWorkflowResult(workflowID, timeoutSeconds, DBOS.workflowID, timerFuncID);
676
681
  if (!rres)
677
682
  return null;
@@ -704,7 +709,7 @@ class DBOS {
704
709
  * @deprecated Use `DBOS.listWorkflows` instead
705
710
  */
706
711
  static async getWorkflows(input) {
707
- return await DBOS.#runAsWorkflowStep(async () => {
712
+ return await runInternalStep(async () => {
708
713
  const wfs = await DBOS.#executor.listWorkflows(input);
709
714
  return { workflowUUIDs: wfs.map((wf) => wf.workflowID) };
710
715
  }, 'DBOS.getWorkflows');
@@ -715,7 +720,7 @@ class DBOS {
715
720
  * @returns `WorkflowStatus` array containing details of the matching workflows
716
721
  */
717
722
  static async listWorkflows(input) {
718
- return await DBOS.#runAsWorkflowStep(async () => {
723
+ return await runInternalStep(async () => {
719
724
  return await DBOS.#executor.listWorkflows(input);
720
725
  }, 'DBOS.listWorkflows');
721
726
  }
@@ -725,7 +730,7 @@ class DBOS {
725
730
  * @returns `WorkflowStatus` array containing details of the matching workflows
726
731
  */
727
732
  static async listQueuedWorkflows(input) {
728
- return await DBOS.#runAsWorkflowStep(async () => {
733
+ return await runInternalStep(async () => {
729
734
  return await DBOS.#executor.listQueuedWorkflows(input);
730
735
  }, 'DBOS.listQueuedWorkflows');
731
736
  }
@@ -735,7 +740,7 @@ class DBOS {
735
740
  * @returns `StepInfo` array listing the executed steps of the workflow. If the workflow is not found, `undefined` is returned.
736
741
  */
737
742
  static async listWorkflowSteps(workflowID) {
738
- return await DBOS.#runAsWorkflowStep(async () => {
743
+ return await runInternalStep(async () => {
739
744
  return await DBOS.#executor.listWorkflowSteps(workflowID);
740
745
  }, 'DBOS.listWorkflowSteps');
741
746
  }
@@ -746,7 +751,7 @@ class DBOS {
746
751
  * @param workflowID - ID of the workflow
747
752
  */
748
753
  static async cancelWorkflow(workflowID) {
749
- return await DBOS.#runAsWorkflowStep(async () => {
754
+ return await runInternalStep(async () => {
750
755
  return await DBOS.#executor.cancelWorkflow(workflowID);
751
756
  }, 'DBOS.cancelWorkflow');
752
757
  }
@@ -755,7 +760,7 @@ class DBOS {
755
760
  * @param workflowID - ID of the workflow
756
761
  */
757
762
  static async resumeWorkflow(workflowID) {
758
- await DBOS.#runAsWorkflowStep(async () => {
763
+ await runInternalStep(async () => {
759
764
  return await DBOS.#executor.resumeWorkflow(workflowID);
760
765
  }, 'DBOS.resumeWorkflow');
761
766
  return this.retrieveWorkflow(workflowID);
@@ -769,7 +774,7 @@ class DBOS {
769
774
  * @throws DBOSInvalidStepIDError if the `startStep` is greater than the maximum step ID of the workflow
770
775
  */
771
776
  static async forkWorkflow(workflowID, startStep, options) {
772
- const forkedID = await DBOS.#runAsWorkflowStep(async () => {
777
+ const forkedID = await runInternalStep(async () => {
773
778
  return await DBOS.#executor.forkWorkflow(workflowID, startStep, options);
774
779
  }, 'DBOS.forkWorkflow');
775
780
  return this.retrieveWorkflow(forkedID);
@@ -929,114 +934,39 @@ class DBOS {
929
934
  }, callback);
930
935
  }
931
936
  }
932
- static startWorkflow(target, params) {
933
- if (typeof target === 'function') {
934
- return DBOS.#proxyInvokeWF(target, null, params);
935
- }
936
- else {
937
- return DBOS.#proxyInvokeWF(target, target, params);
937
+ /**
938
+ * Start a workflow in the background, returning a handle that can be used to check status,
939
+ * await the result, or otherwise interact with the workflow.
940
+ * @param func - The function to start. If a class or instance method, supply `this` within `params`.
941
+ * @param params - `StartWorkflowFunctionParams` which may specify the ID, queue, `this`, or other parameters
942
+ * @param args - Arguments passed to `func`
943
+ * @returns `WorkflowHandle` which can be used to interact with the started workflow
944
+ */
945
+ static async startWorkflowFunction(params, func, ...args) {
946
+ const regOp = (0, decorators_1.getRegistrationForFunction)(func);
947
+ if (!regOp) {
948
+ throw new error_1.DBOSNotRegisteredError(func.name, `${func.name} is not a registered DBOS workflow function`);
938
949
  }
950
+ return await DBOS.#invokeWorkflow(params?.instance, regOp, args, params ?? {});
939
951
  }
940
- static #proxyInvokeWF(object, configuredInstance, inParams) {
941
- const ops = (0, decorators_1.getRegisteredOperations)(object);
942
- const proxy = {};
943
- let wfId = (0, context_1.getNextWFID)(inParams?.workflowID);
944
- const pctx = (0, context_1.getCurrentContextStore)();
945
- // If this is called from within a workflow, this is a child workflow,
946
- // For OAOO, we will need a consistent ID formed from the parent WF and call number
947
- if (DBOS.isWithinWorkflow()) {
948
- if (!DBOS.isInWorkflow()) {
949
- throw new error_1.DBOSInvalidWorkflowTransitionError('Invalid call to `DBOS.startWorkflow` from within a `step` or `transaction`');
950
- }
951
- const wfctx = (0, context_1.assertCurrentWorkflowContext)();
952
- const funcId = wfctx.functionIDGetIncrement();
953
- wfId = wfId || wfctx.workflowUUID + '-' + funcId;
954
- const wfParams = {
955
- workflowUUID: wfId,
956
- parentCtx: wfctx,
957
- configuredInstance,
958
- queueName: inParams?.queueName ?? pctx?.queueAssignedForWorkflows,
959
- timeoutMS: inParams?.timeoutMS ?? pctx?.workflowTimeoutMS,
960
- deadlineEpochMS: wfctx.deadlineEpochMS,
961
- enqueueOptions: inParams?.enqueueOptions,
962
- };
963
- // Detach child deadline if a null timeout is configured
964
- // We must check the inParams but also pctx (if the workflow was called withWorkflowTimeout)
965
- if (inParams?.timeoutMS === null || pctx?.workflowTimeoutMS === null) {
966
- wfParams.deadlineEpochMS = undefined;
967
- }
968
- for (const op of ops) {
969
- if (op.workflowConfig) {
970
- proxy[op.name] = (...args) => dbos_executor_1.DBOSExecutor.globalInstance.internalWorkflow(op.registeredFunction, wfParams, wfctx.workflowUUID, funcId, ...args);
971
- }
972
- else if (op.txnConfig) {
973
- const txn = op.registeredFunction;
974
- proxy[op.name] = (...args) => dbos_executor_1.DBOSExecutor.globalInstance.startTransactionTempWF(txn, wfParams, wfctx.workflowUUID, funcId, ...args);
975
- }
976
- else if (op.stepConfig) {
977
- const step = op.registeredFunction;
978
- proxy[op.name] = (...args) => {
979
- return dbos_executor_1.DBOSExecutor.globalInstance.startStepTempWF(step, wfParams, wfctx.workflowUUID, funcId, ...args);
980
- };
981
- }
982
- else {
983
- proxy[op.name] = (..._args) => {
984
- throw new error_1.DBOSNotRegisteredError(op.name, `${op.name} is not a registered DBOS workflow, step, or transaction function`);
985
- };
952
+ static startWorkflow(target, params) {
953
+ const instance = typeof target === 'function' ? null : target;
954
+ if (instance && !(instance instanceof _2.ConfiguredInstance)) {
955
+ throw new error_1.DBOSInvalidWorkflowTransitionError('Attempt to call `startWorkflow` on an object that is not a `ConfiguredInstance`');
956
+ }
957
+ const regOps = (0, decorators_1.getRegisteredOperations)(target);
958
+ const handler = {
959
+ get(target, p, receiver) {
960
+ const func = Reflect.get(target, p, receiver);
961
+ const regOp = (0, decorators_1.getRegistrationForFunction)(func) ?? regOps.find((op) => op.name === p);
962
+ if (regOp) {
963
+ return (...args) => DBOS.#invokeWorkflow(instance, regOp, args, params);
986
964
  }
987
- }
988
- augmentProxy(configuredInstance ?? object, proxy);
989
- return proxy;
990
- }
991
- // Else, we setup a parent context that includes all the potential metadata the application could have set in DBOSLocalCtx
992
- let parentCtx = undefined;
993
- if (pctx) {
994
- // If pctx has no span, e.g., has not been setup through `withTracedContext`, set up a parent span for the workflow here.
995
- let span = pctx.span;
996
- if (!span) {
997
- span = DBOS.#executor.tracer.startSpan(pctx.operationCaller || 'startWorkflow', {
998
- operationUUID: wfId,
999
- operationType: pctx.operationType,
1000
- authenticatedUser: pctx.authenticatedUser,
1001
- assumedRole: pctx.assumedRole,
1002
- authenticatedRoles: pctx.authenticatedRoles,
1003
- });
1004
- }
1005
- parentCtx = new context_1.DBOSContextImpl(pctx.operationCaller || 'startWorkflow', span, DBOS.logger);
1006
- parentCtx.request = pctx.request || {};
1007
- parentCtx.authenticatedUser = pctx.authenticatedUser || '';
1008
- parentCtx.assumedRole = pctx.assumedRole || '';
1009
- parentCtx.authenticatedRoles = pctx.authenticatedRoles || [];
1010
- parentCtx.workflowUUID = wfId || '';
1011
- }
1012
- const wfParams = {
1013
- workflowUUID: wfId,
1014
- queueName: inParams?.queueName ?? pctx?.queueAssignedForWorkflows,
1015
- enqueueOptions: inParams?.enqueueOptions,
1016
- configuredInstance,
1017
- parentCtx,
1018
- timeoutMS: inParams?.timeoutMS ?? pctx?.workflowTimeoutMS,
965
+ const name = typeof p === 'string' ? p : String(p);
966
+ throw new error_1.DBOSNotRegisteredError(name, `${name} is not a registered DBOS workflow function`);
967
+ },
1019
968
  };
1020
- for (const op of ops) {
1021
- if (op.workflowConfig) {
1022
- proxy[op.name] = (...args) => DBOS.#executor.workflow(op.registeredFunction, wfParams, ...args);
1023
- }
1024
- else if (op.txnConfig) {
1025
- const txn = op.registeredFunction;
1026
- proxy[op.name] = (...args) => dbos_executor_1.DBOSExecutor.globalInstance.startTransactionTempWF(txn, wfParams, undefined, undefined, ...args);
1027
- }
1028
- else if (op.stepConfig) {
1029
- const step = op.registeredFunction;
1030
- proxy[op.name] = (...args) => dbos_executor_1.DBOSExecutor.globalInstance.startStepTempWF(step, wfParams, undefined, undefined, ...args);
1031
- }
1032
- else {
1033
- proxy[op.name] = (..._args) => {
1034
- throw new error_1.DBOSNotRegisteredError(op.name, `${op.name} is not a registered DBOS workflow, step, or transaction function`);
1035
- };
1036
- }
1037
- }
1038
- augmentProxy(configuredInstance ?? object, proxy);
1039
- return proxy;
969
+ return new Proxy(target, handler);
1040
970
  }
1041
971
  static invoke(object) {
1042
972
  if (!DBOS.isWithinWorkflow()) {
@@ -1244,85 +1174,113 @@ class DBOS {
1244
1174
  static workflow(config = {}) {
1245
1175
  function decorator(target, propertyKey, inDescriptor) {
1246
1176
  const { descriptor, registration } = (0, decorators_1.registerAndWrapDBOSFunction)(target, propertyKey, inDescriptor);
1247
- registration.setWorkflowConfig(config);
1248
- const invokeWrapper = async function (...rawArgs) {
1249
- const pctx = (0, context_1.getCurrentContextStore)();
1250
- let inst = undefined;
1251
- if (this === undefined || typeof this === 'function') {
1252
- // This is static
1253
- }
1254
- else {
1255
- inst = this;
1256
- if (!('name' in inst)) {
1257
- throw new error_1.DBOSInvalidWorkflowTransitionError('Attempt to call a `workflow` function on an object that is not a `ConfiguredInstance`');
1258
- }
1259
- }
1260
- let wfId = (0, context_1.getNextWFID)(undefined);
1261
- // If this is called from within a workflow, this is a child workflow,
1262
- // For OAOO, we will need a consistent ID formed from the parent WF and call number
1263
- if (DBOS.isWithinWorkflow()) {
1264
- if (!DBOS.isInWorkflow()) {
1265
- throw new error_1.DBOSInvalidWorkflowTransitionError('Invalid call to a `workflow` function from within a `step` or `transaction`');
1266
- }
1267
- const wfctx = (0, context_1.assertCurrentWorkflowContext)();
1268
- const funcId = wfctx.functionIDGetIncrement();
1269
- wfId = wfId || wfctx.workflowUUID + '-' + funcId;
1270
- const params = {
1271
- workflowUUID: wfId,
1272
- parentCtx: wfctx,
1273
- configuredInstance: inst,
1274
- queueName: pctx?.queueAssignedForWorkflows,
1275
- timeoutMS: pctx?.workflowTimeoutMS,
1276
- deadlineEpochMS: wfctx.deadlineEpochMS,
1277
- };
1278
- // Detach child deadline if a null timeout is configured
1279
- if (pctx?.workflowTimeoutMS === null) {
1280
- params.deadlineEpochMS = undefined;
1281
- }
1282
- const cwfh = await dbos_executor_1.DBOSExecutor.globalInstance.internalWorkflow(registration.registeredFunction, params, wfctx.workflowUUID, funcId, ...rawArgs);
1283
- return await cwfh.getResult();
1284
- }
1285
- // Else, we setup a parent context that includes all the potential metadata the application could have set in DBOSLocalCtx
1286
- let parentCtx = undefined;
1287
- if (pctx) {
1288
- // If pctx has no span, e.g., has not been setup through `withTracedContext`, set up a parent span for the workflow here.
1289
- let span = pctx.span;
1290
- if (!span) {
1291
- span = DBOS.#executor.tracer.startSpan(pctx.operationCaller || 'workflowCaller', {
1292
- operationUUID: wfId,
1293
- operationType: pctx.operationType,
1294
- authenticatedUser: pctx.authenticatedUser,
1295
- assumedRole: pctx.assumedRole,
1296
- authenticatedRoles: pctx.authenticatedRoles,
1297
- });
1298
- }
1299
- parentCtx = new context_1.DBOSContextImpl(pctx.operationCaller || 'workflowCaller', span, DBOS.logger);
1300
- parentCtx.request = pctx.request || {};
1301
- parentCtx.authenticatedUser = pctx.authenticatedUser || '';
1302
- parentCtx.assumedRole = pctx.assumedRole || '';
1303
- parentCtx.authenticatedRoles = pctx.authenticatedRoles || [];
1304
- parentCtx.workflowUUID = wfId || '';
1305
- }
1306
- const wfParams = {
1307
- workflowUUID: wfId,
1308
- queueName: pctx?.queueAssignedForWorkflows,
1309
- configuredInstance: inst,
1310
- parentCtx,
1311
- timeoutMS: pctx?.workflowTimeoutMS,
1312
- };
1313
- const handle = await DBOS.#executor.workflow(registration.registeredFunction, wfParams, ...rawArgs);
1314
- return await handle.getResult();
1315
- };
1316
- descriptor.value = invokeWrapper;
1317
- registration.wrappedFunction = invokeWrapper;
1318
- Object.defineProperty(invokeWrapper, 'name', {
1319
- value: registration.name,
1320
- });
1321
- (0, decorators_1.registerFunctionWrapper)(invokeWrapper, registration);
1177
+ const invoker = DBOS.#getWorkflowInvoker(registration, config);
1178
+ descriptor.value = invoker;
1179
+ registration.wrappedFunction = invoker;
1322
1180
  return descriptor;
1323
1181
  }
1324
1182
  return decorator;
1325
1183
  }
1184
+ /**
1185
+ * Create a DBOS workflow function from a provided function.
1186
+ * Similar to the DBOS.workflow, but without requiring a decorator
1187
+ * Durable execution will be applied to calls to the function returned by registerWorkflow
1188
+ * This also registers the function so that it is available during recovery
1189
+ * @param func - The function to register as a workflow
1190
+ * @param name - The name of the registered workflow
1191
+ * @param options - Configuration information for the registered workflow
1192
+ */
1193
+ static registerWorkflow(func, name, options = {}) {
1194
+ const { registration } = (0, decorators_1.registerAndWrapDBOSFunctionByName)(options.classOrInst, options.className, name, func);
1195
+ return DBOS.#getWorkflowInvoker(registration, options.config);
1196
+ }
1197
+ static async #invokeWorkflow($this, regOP, args, params = {}) {
1198
+ const wfId = (0, context_1.getNextWFID)(params.workflowID);
1199
+ const pctx = (0, context_1.getCurrentContextStore)();
1200
+ const queueName = params.queueName ?? pctx?.queueAssignedForWorkflows;
1201
+ const timeoutMS = params.timeoutMS ?? pctx?.workflowTimeoutMS;
1202
+ const instance = $this === undefined || typeof $this === 'function' ? undefined : $this;
1203
+ if (instance && !(instance instanceof _2.ConfiguredInstance)) {
1204
+ throw new error_1.DBOSInvalidWorkflowTransitionError('Attempt to call a `workflow` function on an object that is not a `ConfiguredInstance`');
1205
+ }
1206
+ // If this is called from within a workflow, this is a child workflow,
1207
+ // For OAOO, we will need a consistent ID formed from the parent WF and call number
1208
+ if (DBOS.isWithinWorkflow()) {
1209
+ if (!DBOS.isInWorkflow()) {
1210
+ throw new error_1.DBOSInvalidWorkflowTransitionError('Invalid call to a `workflow` function from within a `step` or `transaction`');
1211
+ }
1212
+ const wfctx = (0, context_1.assertCurrentWorkflowContext)();
1213
+ const funcId = wfctx.functionIDGetIncrement();
1214
+ const wfParams = {
1215
+ workflowUUID: wfId || wfctx.workflowUUID + '-' + funcId,
1216
+ parentCtx: wfctx,
1217
+ configuredInstance: instance,
1218
+ queueName,
1219
+ timeoutMS,
1220
+ // Detach child deadline if a null timeout is configured
1221
+ deadlineEpochMS: params.timeoutMS === null || pctx?.workflowTimeoutMS === null ? undefined : wfctx.deadlineEpochMS,
1222
+ enqueueOptions: params.enqueueOptions,
1223
+ };
1224
+ return await invokeRegOp(wfParams, wfctx.workflowUUID, funcId);
1225
+ }
1226
+ else {
1227
+ // Else, we setup a parent context that includes all the potential metadata the application could have set in DBOSLocalCtx
1228
+ let parentCtx = undefined;
1229
+ if (pctx) {
1230
+ // If pctx has no span, e.g., has not been setup through `withTracedContext`, set up a parent span for the workflow here.
1231
+ const span = pctx.span ??
1232
+ DBOS.#executor.tracer.startSpan(pctx.operationCaller || 'workflowCaller', {
1233
+ operationUUID: wfId,
1234
+ operationType: pctx.operationType,
1235
+ authenticatedUser: pctx.authenticatedUser,
1236
+ assumedRole: pctx.assumedRole,
1237
+ authenticatedRoles: pctx.authenticatedRoles,
1238
+ });
1239
+ parentCtx = new context_1.DBOSContextImpl(pctx.operationCaller || 'workflowCaller', span, DBOS.logger);
1240
+ parentCtx.request = pctx.request ?? {};
1241
+ parentCtx.authenticatedUser = pctx.authenticatedUser ?? '';
1242
+ parentCtx.assumedRole = pctx.assumedRole ?? '';
1243
+ parentCtx.authenticatedRoles = pctx.authenticatedRoles ?? [];
1244
+ parentCtx.workflowUUID = wfId ?? '';
1245
+ }
1246
+ const wfParams = {
1247
+ workflowUUID: wfId,
1248
+ queueName,
1249
+ enqueueOptions: params.enqueueOptions,
1250
+ configuredInstance: instance,
1251
+ parentCtx,
1252
+ timeoutMS,
1253
+ };
1254
+ return await invokeRegOp(wfParams, undefined, undefined);
1255
+ }
1256
+ function invokeRegOp(wfParams, workflowID, funcNum) {
1257
+ if (regOP.workflowConfig) {
1258
+ const func = regOP.registeredFunction;
1259
+ return dbos_executor_1.DBOSExecutor.globalInstance.internalWorkflow(func, wfParams, workflowID, funcNum, ...args);
1260
+ }
1261
+ if (regOP.txnConfig) {
1262
+ const func = regOP.registeredFunction;
1263
+ return dbos_executor_1.DBOSExecutor.globalInstance.startTransactionTempWF(func, wfParams, workflowID, funcNum, ...args);
1264
+ }
1265
+ if (regOP.stepConfig) {
1266
+ const func = regOP.registeredFunction;
1267
+ return dbos_executor_1.DBOSExecutor.globalInstance.startStepTempWF(func, wfParams, workflowID, funcNum, ...args);
1268
+ }
1269
+ throw new error_1.DBOSNotRegisteredError(regOP.name, `${regOP.name} is not a registered DBOS workflow, step, or transaction function`);
1270
+ }
1271
+ }
1272
+ static #getWorkflowInvoker(registration, config) {
1273
+ registration.setWorkflowConfig(config ?? {});
1274
+ const invoker = async function (...rawArgs) {
1275
+ const handle = await DBOS.#invokeWorkflow(this, registration, rawArgs);
1276
+ return await handle.getResult();
1277
+ };
1278
+ (0, decorators_1.registerFunctionWrapper)(invoker, registration);
1279
+ Object.defineProperty(invoker, 'name', {
1280
+ value: registration.name,
1281
+ });
1282
+ return invoker;
1283
+ }
1326
1284
  /**
1327
1285
  * Decorator designating a method as a DBOS transaction, making SQL clients available.
1328
1286
  * A durable execution checkpoint will be applied to to the underlying database transaction
@@ -1340,7 +1298,7 @@ class DBOS {
1340
1298
  }
1341
1299
  else {
1342
1300
  inst = this;
1343
- if (!('name' in inst)) {
1301
+ if (!(inst instanceof _2.ConfiguredInstance)) {
1344
1302
  throw new error_1.DBOSInvalidWorkflowTransitionError('Attempt to call a `transaction` function on an object that is not a `ConfiguredInstance`');
1345
1303
  }
1346
1304
  }
@@ -1466,7 +1424,7 @@ class DBOS {
1466
1424
  }
1467
1425
  else {
1468
1426
  inst = this;
1469
- if (!('name' in inst)) {
1427
+ if (!(inst instanceof _2.ConfiguredInstance)) {
1470
1428
  throw new error_1.DBOSInvalidWorkflowTransitionError('Attempt to call a `step` function on an object that is not a `ConfiguredInstance`');
1471
1429
  }
1472
1430
  }
@@ -1519,6 +1477,65 @@ class DBOS {
1519
1477
  }
1520
1478
  return decorator;
1521
1479
  }
1480
+ /**
1481
+ * Create a check pointed DBOS step function from a provided function
1482
+ * Similar to the DBOS.step decorator, but without requiring a decorator
1483
+ * A durable checkpoint will be made after the step completes
1484
+ * This ensures "at least once" execution of the step, and that the step will not
1485
+ * be executed again once the checkpoint is recorded
1486
+ * @param func - The function to register as a step
1487
+ * @param config - Configuration information for the step, particularly the retry policy
1488
+ * @param config.name - The name of the step; if not provided, the function name will be used
1489
+ */
1490
+ static registerStep(func, config = {}) {
1491
+ const name = config.name ?? func.name;
1492
+ const invokeWrapper = async function (...rawArgs) {
1493
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
1494
+ const inst = this;
1495
+ if (DBOS.isWithinWorkflow()) {
1496
+ if (DBOS.isInTransaction()) {
1497
+ throw new error_1.DBOSInvalidWorkflowTransitionError('Invalid call to a `step` function from within a `transaction`');
1498
+ }
1499
+ if (DBOS.isInStep()) {
1500
+ // There should probably be checks here about the compatibility of the StepConfig...
1501
+ return func.call(this, ...rawArgs);
1502
+ }
1503
+ const wfctx = (0, context_1.assertCurrentWorkflowContext)();
1504
+ return await dbos_executor_1.DBOSExecutor.globalInstance.callStepFunction(func, name, config, inst ?? null, wfctx, ...rawArgs);
1505
+ }
1506
+ if ((0, context_1.getNextWFID)(undefined)) {
1507
+ throw new error_1.DBOSInvalidWorkflowTransitionError(`Invalid call to step '${name}' outside of a workflow; with directive to start a workflow.`);
1508
+ }
1509
+ return func.call(this, ...rawArgs);
1510
+ };
1511
+ Object.defineProperty(invokeWrapper, 'name', { value: name });
1512
+ return invokeWrapper;
1513
+ }
1514
+ /**
1515
+ * Run the enclosed `callback` as a checkpointed step within a DBOS workflow
1516
+ * @param callback - function containing code to run
1517
+ * @param config - Configuration information for the step, particularly the retry policy
1518
+ * @param config.name - The name of the step; if not provided, the function name will be used
1519
+ * @returns - result (either obtained from invoking function, or retrieved if run before)
1520
+ */
1521
+ static runStep(func, config = {}) {
1522
+ const name = config.name ?? func.name;
1523
+ if (DBOS.isWithinWorkflow()) {
1524
+ if (DBOS.isInTransaction()) {
1525
+ throw new error_1.DBOSInvalidWorkflowTransitionError('Invalid call to a runStep from within a `transaction`');
1526
+ }
1527
+ if (DBOS.isInStep()) {
1528
+ // There should probably be checks here about the compatibility of the StepConfig...
1529
+ return func();
1530
+ }
1531
+ const wfctx = (0, context_1.assertCurrentWorkflowContext)();
1532
+ return dbos_executor_1.DBOSExecutor.globalInstance.callStepFunction(func, name, config, null, wfctx);
1533
+ }
1534
+ if ((0, context_1.getNextWFID)(undefined)) {
1535
+ throw new error_1.DBOSInvalidWorkflowTransitionError(`Invalid call to step '${name}' outside of a workflow; with directive to start a workflow.`);
1536
+ }
1537
+ return func();
1538
+ }
1522
1539
  /** Decorator indicating that the method is the target of HTTP GET operations for `url` */
1523
1540
  static getApi(url) {
1524
1541
  return httpApiDec(handlerTypes_1.APITypes.GET, url);
@@ -1589,7 +1606,7 @@ class DBOS {
1589
1606
  * Register a middleware provider
1590
1607
  */
1591
1608
  static registerMiddlewareInstaller(mwp) {
1592
- (0, decorators_1.registerMiddlewareInserter)(mwp);
1609
+ (0, decorators_1.registerMiddlewareInstaller)(mwp);
1593
1610
  }
1594
1611
  /**
1595
1612
  * Register information to be associated with a DBOS class