@dudousxd/nestjs-durable-core 0.41.0 → 0.43.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/index.cjs CHANGED
@@ -772,6 +772,70 @@ function eventMatches(payload, match) {
772
772
  }
773
773
  __name(eventMatches, "eventMatches");
774
774
 
775
+ // src/remote-workflow-executor.ts
776
+ var taskCounter = 0;
777
+ var RemoteWorkflowExecutor = class {
778
+ static {
779
+ __name(this, "RemoteWorkflowExecutor");
780
+ }
781
+ transport;
782
+ group;
783
+ opts;
784
+ pending = /* @__PURE__ */ new Map();
785
+ subscribed = false;
786
+ constructor(transport, group, opts = {}) {
787
+ this.transport = transport;
788
+ this.group = group;
789
+ this.opts = opts;
790
+ }
791
+ ensureSubscribed() {
792
+ if (this.subscribed) return;
793
+ if (!this.transport.onDecision) {
794
+ throw new Error("transport does not support workflow decisions (onDecision)");
795
+ }
796
+ this.subscribed = true;
797
+ this.transport.onDecision(async (decision) => {
798
+ const resolve = this.pending.get(decision.taskId);
799
+ if (resolve) {
800
+ this.pending.delete(decision.taskId);
801
+ resolve(decision);
802
+ }
803
+ });
804
+ }
805
+ async advance(run, history) {
806
+ if (!this.transport.dispatchWorkflowTask) {
807
+ throw new Error("transport does not support workflow tasks (dispatchWorkflowTask)");
808
+ }
809
+ this.ensureSubscribed();
810
+ taskCounter += 1;
811
+ const taskId = `${run.id}:wf:${taskCounter}`;
812
+ const task = {
813
+ taskId,
814
+ runId: run.id,
815
+ workflow: run.workflow,
816
+ workflowVersion: run.workflowVersion,
817
+ input: run.input,
818
+ history,
819
+ group: this.group,
820
+ priority: run.priority,
821
+ attempt: 1
822
+ };
823
+ const decision = new Promise((resolve, reject) => {
824
+ this.pending.set(taskId, resolve);
825
+ const { timeoutMs } = this.opts;
826
+ if (timeoutMs) {
827
+ const timer = setTimeout(() => {
828
+ this.pending.delete(taskId);
829
+ reject(new RemoteWorkflowTimeout(taskId, timeoutMs));
830
+ }, timeoutMs);
831
+ timer.unref?.();
832
+ }
833
+ });
834
+ await this.transport.dispatchWorkflowTask(task);
835
+ return decision;
836
+ }
837
+ };
838
+
775
839
  // src/singleton-gate.ts
776
840
  var SINGLETON_RETRY_MS = 1e3;
777
841
  var SINGLETON_RETRY_JITTER_MS = 250;
@@ -873,6 +937,19 @@ var TransportPool = class {
873
937
  get size() {
874
938
  return this.transports.length;
875
939
  }
940
+ /**
941
+ * The primary (first) transport — the one `dispatch` prefers when no `preferId` is pinned. A
942
+ * {@link RemoteWorkflowExecutor} built by `engine.remote()` rides it (it needs a single
943
+ * `dispatchWorkflowTask`/`onDecision` Transport, not the whole failover pool). Throws if the pool
944
+ * is empty — there is nothing to dispatch a remote workflow over.
945
+ */
946
+ get primary() {
947
+ const first = this.transports[0];
948
+ if (!first) {
949
+ throw new Error("no transport configured \u2014 engine.remote() needs a transport (or transports)");
950
+ }
951
+ return first.transport;
952
+ }
876
953
  /** Register the engine's result/heartbeat/step-event handlers on EVERY transport — a result can come
877
954
  * back on whichever one delivered the task, so failover stays symmetric. `onStepEvent` is wired only
878
955
  * on transports that carry streamed workflow step lifecycle (BullMQ); others simply skip it. */
@@ -1792,6 +1869,28 @@ var WorkflowEngine = class {
1792
1869
  if (!current || isNewerVersion(version, current.version)) this.latest.set(name, registered);
1793
1870
  }
1794
1871
  /**
1872
+ * The convenience form of {@link registerRemote}: register a workflow whose body runs on a worker
1873
+ * `group` (e.g. the Python `durable-worker`, or a separate TS worker), without hand-building a
1874
+ * {@link RemoteWorkflowExecutor}. It wires the standard broker executor — a `RemoteWorkflowExecutor`
1875
+ * over the engine's own transport, dispatching to `opts.group` — for you, so you write
1876
+ * `engine.remote('processing', { group: 'processing' })` instead of
1877
+ * `engine.registerRemote('processing', '1', { group: 'processing', executor: new RemoteWorkflowExecutor(transport, 'processing') })`.
1878
+ *
1879
+ * Defaults the version to `'1'`. All the other {@link registerRemote} options
1880
+ * (`tags` / `singleton` / `executionTimeout` / `validateInput`) pass straight through. Reach for the
1881
+ * low-level {@link registerRemote} when you need a custom {@link WorkflowExecutor} (a different
1882
+ * transport, a fixed `timeoutMs`, a polyglot stub) — `remote()` is the standard wiring on the rails.
1883
+ */
1884
+ remote(name, opts) {
1885
+ const { group, version, ...rest } = opts;
1886
+ const executor = new RemoteWorkflowExecutor(this.pool.primary, group);
1887
+ this.registerRemote(name, version ?? "1", {
1888
+ group,
1889
+ executor,
1890
+ ...rest
1891
+ });
1892
+ }
1893
+ /**
1795
1894
  * Register a flow-control queue referenced by `ctx.call(step, input, { queue })`. Caps concurrent
1796
1895
  * in-flight steps and/or the admission rate; blocked calls re-suspend and retry, so the limit is
1797
1896
  * durable. Per engine instance (see {@link QueueConfig}). Registering the same name replaces it.
@@ -3687,70 +3786,6 @@ function remoteStep(config) {
3687
3786
  }
3688
3787
  __name(remoteStep, "remoteStep");
3689
3788
 
3690
- // src/remote-workflow-executor.ts
3691
- var taskCounter = 0;
3692
- var RemoteWorkflowExecutor = class {
3693
- static {
3694
- __name(this, "RemoteWorkflowExecutor");
3695
- }
3696
- transport;
3697
- group;
3698
- opts;
3699
- pending = /* @__PURE__ */ new Map();
3700
- subscribed = false;
3701
- constructor(transport, group, opts = {}) {
3702
- this.transport = transport;
3703
- this.group = group;
3704
- this.opts = opts;
3705
- }
3706
- ensureSubscribed() {
3707
- if (this.subscribed) return;
3708
- if (!this.transport.onDecision) {
3709
- throw new Error("transport does not support workflow decisions (onDecision)");
3710
- }
3711
- this.subscribed = true;
3712
- this.transport.onDecision(async (decision) => {
3713
- const resolve = this.pending.get(decision.taskId);
3714
- if (resolve) {
3715
- this.pending.delete(decision.taskId);
3716
- resolve(decision);
3717
- }
3718
- });
3719
- }
3720
- async advance(run, history) {
3721
- if (!this.transport.dispatchWorkflowTask) {
3722
- throw new Error("transport does not support workflow tasks (dispatchWorkflowTask)");
3723
- }
3724
- this.ensureSubscribed();
3725
- taskCounter += 1;
3726
- const taskId = `${run.id}:wf:${taskCounter}`;
3727
- const task = {
3728
- taskId,
3729
- runId: run.id,
3730
- workflow: run.workflow,
3731
- workflowVersion: run.workflowVersion,
3732
- input: run.input,
3733
- history,
3734
- group: this.group,
3735
- priority: run.priority,
3736
- attempt: 1
3737
- };
3738
- const decision = new Promise((resolve, reject) => {
3739
- this.pending.set(taskId, resolve);
3740
- const { timeoutMs } = this.opts;
3741
- if (timeoutMs) {
3742
- const timer = setTimeout(() => {
3743
- this.pending.delete(taskId);
3744
- reject(new RemoteWorkflowTimeout(taskId, timeoutMs));
3745
- }, timeoutMs);
3746
- timer.unref?.();
3747
- }
3748
- });
3749
- await this.transport.dispatchWorkflowTask(task);
3750
- return decision;
3751
- }
3752
- };
3753
-
3754
3789
  // src/codec-state-store.ts
3755
3790
  var CodecStateStore = class {
3756
3791
  static {