@dudousxd/nestjs-durable-core 0.62.0 → 0.63.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.d.cts CHANGED
@@ -627,6 +627,24 @@ interface WorkflowRun {
627
627
  * store persists it as `'default'`. Read paths (dashboard, `getRun`) are NOT namespace-scoped.
628
628
  */
629
629
  namespace?: string | undefined;
630
+ /**
631
+ * The npm package that DECLARED this run's workflow — e.g. `@dudousxd/nestjs-catalog-pipeline` for
632
+ * a workflow shipped by a library, or the host app's own `package.json` `name` for one written in
633
+ * the app. This is a CODE-PROVENANCE axis ("which lib owns this body"), NOT a tenancy axis — for
634
+ * that, see {@link namespace}.
635
+ *
636
+ * Stamped at creation from the workflow's registration, exactly as {@link namespace} is stamped
637
+ * from the creating engine. It is DERIVED, never caller input: `StartOptions` has no `origin`, so
638
+ * nothing a caller passes to `start` can make a run claim another lib's name.
639
+ *
640
+ * `undefined` means UNKNOWN — never "the app". It is what you get for a run created before this
641
+ * field existed, for a registration path that carries no origin (`registerRemote`, convention
642
+ * routing, a synthesized remote child, or a bare `engine.register` with no `origin` option), and
643
+ * for a workflow whose declaring package could not be resolved with confidence. A wrong origin is
644
+ * worse than an absent one: a filter that silently drops runs looks exactly like runs that never
645
+ * existed, so callers must render unknown as unknown and never fold it into a real package.
646
+ */
647
+ origin?: string | undefined;
630
648
  /**
631
649
  * Dispatch priority for a REMOTE run (one advanced by a {@link WorkflowExecutor} over a broker):
632
650
  * carried onto each {@link WorkflowTask} so an urgent child workflow can jump ahead of enqueued
@@ -1045,6 +1063,15 @@ interface RunQuery {
1045
1063
  attributes?: AttributeFilter[] | undefined;
1046
1064
  /** Restrict to runs in this namespace (exact match), ANDed with the other predicates. */
1047
1065
  namespace?: string | undefined;
1066
+ /**
1067
+ * Restrict to runs whose workflow was declared by this package (exact match against
1068
+ * {@link WorkflowRun.origin}), ANDed with the other predicates.
1069
+ *
1070
+ * A run with NO origin (unknown — see the field) matches no `origin` value at all, so a UI facet
1071
+ * built on this must keep an "all origins" option: filtering by any single package silently hides
1072
+ * every unattributed run, which reads to an operator as "those runs do not exist".
1073
+ */
1074
+ origin?: string | undefined;
1048
1075
  limit?: number | undefined;
1049
1076
  offset?: number | undefined;
1050
1077
  }
@@ -2262,7 +2289,14 @@ declare class EventAccumulators {
2262
2289
  }
2263
2290
 
2264
2291
  type WorkflowFn = (ctx: InternalWorkflowCtx, input: unknown) => Promise<unknown>;
2265
- /** Options for {@link WorkflowEngine.start}. */
2292
+ /**
2293
+ * Options for {@link WorkflowEngine.start}.
2294
+ *
2295
+ * Note the absence of `origin`: {@link WorkflowRun.origin} says which PACKAGE declared the workflow,
2296
+ * which is a property of the registered code, not of whoever started it. It is taken from the
2297
+ * registration and nothing here can override it — otherwise one caller could label its runs as
2298
+ * another lib's, and an origin filter would quietly lie.
2299
+ */
2266
2300
  interface StartOptions {
2267
2301
  /** Run-scoped tags, merged with the workflow's static `@Workflow({ tags })` onto the run. */
2268
2302
  tags?: string[] | undefined;
@@ -2596,6 +2630,12 @@ declare class WorkflowEngine {
2596
2630
  /** Capabilities a live worker must advertise to run this workflow's turns (handshake §7.5).
2597
2631
  * Only meaningful with `group`/`executor` (a remote/group-served workflow). Absent = runs anywhere. */
2598
2632
  requires?: string[] | undefined;
2633
+ /** The package that DECLARED this workflow, stamped onto every run started from it (see
2634
+ * {@link WorkflowRun.origin}). Supplied by the registering integration — `@dudousxd/nestjs-durable`
2635
+ * derives it from the `@Workflow` class's declaring file — never by whoever calls `start`. Omit
2636
+ * when it cannot be derived with confidence: absent means UNKNOWN, and an absent origin is far
2637
+ * cheaper to live with than a wrong one. */
2638
+ origin?: string | undefined;
2599
2639
  }): void;
2600
2640
  /**
2601
2641
  * The retained in-process body for `name@version`, for an IN-APP worker that consumes this engine's
package/dist/index.d.ts CHANGED
@@ -627,6 +627,24 @@ interface WorkflowRun {
627
627
  * store persists it as `'default'`. Read paths (dashboard, `getRun`) are NOT namespace-scoped.
628
628
  */
629
629
  namespace?: string | undefined;
630
+ /**
631
+ * The npm package that DECLARED this run's workflow — e.g. `@dudousxd/nestjs-catalog-pipeline` for
632
+ * a workflow shipped by a library, or the host app's own `package.json` `name` for one written in
633
+ * the app. This is a CODE-PROVENANCE axis ("which lib owns this body"), NOT a tenancy axis — for
634
+ * that, see {@link namespace}.
635
+ *
636
+ * Stamped at creation from the workflow's registration, exactly as {@link namespace} is stamped
637
+ * from the creating engine. It is DERIVED, never caller input: `StartOptions` has no `origin`, so
638
+ * nothing a caller passes to `start` can make a run claim another lib's name.
639
+ *
640
+ * `undefined` means UNKNOWN — never "the app". It is what you get for a run created before this
641
+ * field existed, for a registration path that carries no origin (`registerRemote`, convention
642
+ * routing, a synthesized remote child, or a bare `engine.register` with no `origin` option), and
643
+ * for a workflow whose declaring package could not be resolved with confidence. A wrong origin is
644
+ * worse than an absent one: a filter that silently drops runs looks exactly like runs that never
645
+ * existed, so callers must render unknown as unknown and never fold it into a real package.
646
+ */
647
+ origin?: string | undefined;
630
648
  /**
631
649
  * Dispatch priority for a REMOTE run (one advanced by a {@link WorkflowExecutor} over a broker):
632
650
  * carried onto each {@link WorkflowTask} so an urgent child workflow can jump ahead of enqueued
@@ -1045,6 +1063,15 @@ interface RunQuery {
1045
1063
  attributes?: AttributeFilter[] | undefined;
1046
1064
  /** Restrict to runs in this namespace (exact match), ANDed with the other predicates. */
1047
1065
  namespace?: string | undefined;
1066
+ /**
1067
+ * Restrict to runs whose workflow was declared by this package (exact match against
1068
+ * {@link WorkflowRun.origin}), ANDed with the other predicates.
1069
+ *
1070
+ * A run with NO origin (unknown — see the field) matches no `origin` value at all, so a UI facet
1071
+ * built on this must keep an "all origins" option: filtering by any single package silently hides
1072
+ * every unattributed run, which reads to an operator as "those runs do not exist".
1073
+ */
1074
+ origin?: string | undefined;
1048
1075
  limit?: number | undefined;
1049
1076
  offset?: number | undefined;
1050
1077
  }
@@ -2262,7 +2289,14 @@ declare class EventAccumulators {
2262
2289
  }
2263
2290
 
2264
2291
  type WorkflowFn = (ctx: InternalWorkflowCtx, input: unknown) => Promise<unknown>;
2265
- /** Options for {@link WorkflowEngine.start}. */
2292
+ /**
2293
+ * Options for {@link WorkflowEngine.start}.
2294
+ *
2295
+ * Note the absence of `origin`: {@link WorkflowRun.origin} says which PACKAGE declared the workflow,
2296
+ * which is a property of the registered code, not of whoever started it. It is taken from the
2297
+ * registration and nothing here can override it — otherwise one caller could label its runs as
2298
+ * another lib's, and an origin filter would quietly lie.
2299
+ */
2266
2300
  interface StartOptions {
2267
2301
  /** Run-scoped tags, merged with the workflow's static `@Workflow({ tags })` onto the run. */
2268
2302
  tags?: string[] | undefined;
@@ -2596,6 +2630,12 @@ declare class WorkflowEngine {
2596
2630
  /** Capabilities a live worker must advertise to run this workflow's turns (handshake §7.5).
2597
2631
  * Only meaningful with `group`/`executor` (a remote/group-served workflow). Absent = runs anywhere. */
2598
2632
  requires?: string[] | undefined;
2633
+ /** The package that DECLARED this workflow, stamped onto every run started from it (see
2634
+ * {@link WorkflowRun.origin}). Supplied by the registering integration — `@dudousxd/nestjs-durable`
2635
+ * derives it from the `@Workflow` class's declaring file — never by whoever calls `start`. Omit
2636
+ * when it cannot be derived with confidence: absent means UNKNOWN, and an absent origin is far
2637
+ * cheaper to live with than a wrong one. */
2638
+ origin?: string | undefined;
2599
2639
  }): void;
2600
2640
  /**
2601
2641
  * The retained in-process body for `name@version`, for an IN-APP worker that consumes this engine's
package/dist/index.js CHANGED
@@ -2558,6 +2558,7 @@ var WorkflowEngine = class {
2558
2558
  onEvent: opts?.onEvent,
2559
2559
  eventBatch: opts?.eventBatch,
2560
2560
  requires: opts?.requires,
2561
+ origin: opts?.origin,
2561
2562
  // A real, retained in-process body — so `workflowBody` can hand it to an in-app worker, and so
2562
2563
  // it is NOT confused with the throwing stub `registerRemote` installs for a body-less remote.
2563
2564
  hasBody: true
@@ -2784,6 +2785,11 @@ var WorkflowEngine = class {
2784
2785
  workflowVersion: registered.version,
2785
2786
  status: "pending",
2786
2787
  namespace: opts?.namespace ?? this.namespace,
2788
+ // DERIVED from the registration, exactly like `namespace` is derived from this engine — there is
2789
+ // deliberately no `opts.origin`, so a caller cannot label its run as another package's work.
2790
+ // `undefined` when the registration carried none (remote/convention/synthesized child, or a
2791
+ // registrar that could not resolve the declaring package): unknown, not "the app".
2792
+ origin: registered.origin,
2787
2793
  input,
2788
2794
  tags,
2789
2795
  searchAttributes: opts?.searchAttributes,
@@ -5658,6 +5664,43 @@ __name(collectMetrics, "collectMetrics");
5658
5664
 
5659
5665
  // src/scheduler.ts
5660
5666
  import { createRequire } from "node:module";
5667
+
5668
+ // src/cron-compat.ts
5669
+ function isIndexable(value) {
5670
+ return typeof value === "object" && value !== null || typeof value === "function";
5671
+ }
5672
+ __name(isIndexable, "isIndexable");
5673
+ function unwrapDefault(module_) {
5674
+ if (!isIndexable(module_)) return module_;
5675
+ if (Reflect.get(module_, "parseExpression") !== void 0) return module_;
5676
+ if (Reflect.get(module_, "CronExpressionParser") !== void 0) return module_;
5677
+ const inner = Reflect.get(module_, "default");
5678
+ return inner === void 0 ? module_ : inner;
5679
+ }
5680
+ __name(unwrapDefault, "unwrapDefault");
5681
+ function v4Entry(module_) {
5682
+ if (!isIndexable(module_)) return void 0;
5683
+ const parse = Reflect.get(module_, "parseExpression");
5684
+ if (typeof parse !== "function") return void 0;
5685
+ return (expr, options) => parse.call(module_, expr, options);
5686
+ }
5687
+ __name(v4Entry, "v4Entry");
5688
+ function v5Entry(module_) {
5689
+ if (!isIndexable(module_)) return void 0;
5690
+ const parser = Reflect.get(module_, "CronExpressionParser");
5691
+ if (!isIndexable(parser)) return void 0;
5692
+ const parse = Reflect.get(parser, "parse");
5693
+ if (typeof parse !== "function") return void 0;
5694
+ return (expr, options) => parse.call(parser, expr, options);
5695
+ }
5696
+ __name(v5Entry, "v5Entry");
5697
+ function resolveCronParse(module_) {
5698
+ const resolved = unwrapDefault(module_);
5699
+ return v4Entry(resolved) ?? v5Entry(resolved);
5700
+ }
5701
+ __name(resolveCronParse, "resolveCronParse");
5702
+
5703
+ // src/scheduler.ts
5661
5704
  var nodeRequire = createRequire(import.meta.url);
5662
5705
  var defaultSleep = /* @__PURE__ */ __name((ms) => new Promise((r) => setTimeout(r, ms)), "defaultSleep");
5663
5706
  function scheduledRunId(key, everyMs, nowMs) {
@@ -5666,7 +5709,7 @@ function scheduledRunId(key, everyMs, nowMs) {
5666
5709
  __name(scheduledRunId, "scheduledRunId");
5667
5710
  var cronParser;
5668
5711
  function loadCronParser() {
5669
- if (cronParser) return cronParser;
5712
+ if (cronParser !== void 0) return cronParser;
5670
5713
  try {
5671
5714
  cronParser = nodeRequire("cron-parser");
5672
5715
  } catch {
@@ -5676,12 +5719,14 @@ function loadCronParser() {
5676
5719
  }
5677
5720
  __name(loadCronParser, "loadCronParser");
5678
5721
  function prevCronFireMs(expr, nowMs, timezone = "UTC") {
5679
- const parser = loadCronParser();
5680
- const it = parser.parseExpression(expr, {
5722
+ const parse = resolveCronParse(loadCronParser());
5723
+ if (!parse) {
5724
+ throw new Error(`the installed "cron-parser" exposes neither v4's parseExpression nor v5's CronExpressionParser.parse \u2014 the supported range is ^4.0.0 || ^5.0.0.`);
5725
+ }
5726
+ return parse(expr, {
5681
5727
  currentDate: new Date(nowMs + 1),
5682
5728
  tz: timezone
5683
- });
5684
- return it.prev().toDate().getTime();
5729
+ }).prev().toDate().getTime();
5685
5730
  }
5686
5731
  __name(prevCronFireMs, "prevCronFireMs");
5687
5732
  function scheduleRunIdAt(s, nowMs) {
@@ -6090,6 +6135,7 @@ var InMemoryStateStore = class {
6090
6135
  if (query.statuses) runs = runs.filter((r) => query.statuses?.includes(r.status));
6091
6136
  if (query.tag) runs = runs.filter((r) => r.tags?.includes(query.tag));
6092
6137
  if (query.namespace !== void 0) runs = runs.filter((r) => r.namespace === query.namespace);
6138
+ if (query.origin !== void 0) runs = runs.filter((r) => r.origin === query.origin);
6093
6139
  if (query.attributes?.length) {
6094
6140
  let candidates = null;
6095
6141
  for (const f of query.attributes) {