@dudousxd/nestjs-durable 0.51.0 → 0.52.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
@@ -58,7 +58,7 @@ __export(index_exports, {
58
58
  ProxyRunGateway: () => ProxyRunGateway,
59
59
  RUN_GATEWAY: () => RUN_GATEWAY,
60
60
  RUN_REDIS_WORKER: () => RUN_REDIS_WORKER,
61
- RunGateway: () => import_nestjs_durable_core18.RunGateway,
61
+ RunGateway: () => import_nestjs_durable_core19.RunGateway,
62
62
  RunRequestResponder: () => RunRequestResponder,
63
63
  STEP_INTERCEPTOR_METADATA: () => STEP_INTERCEPTOR_METADATA,
64
64
  Step: () => Step,
@@ -71,7 +71,7 @@ __export(index_exports, {
71
71
  UNSUPPORTED_RUN_REQUEST: () => UNSUPPORTED_RUN_REQUEST,
72
72
  WORKFLOW_METADATA: () => WORKFLOW_METADATA,
73
73
  Workflow: () => Workflow,
74
- WorkflowEngine: () => import_nestjs_durable_core18.WorkflowEngine,
74
+ WorkflowEngine: () => import_nestjs_durable_core19.WorkflowEngine,
75
75
  WorkflowService: () => WorkflowService,
76
76
  attributesOf: () => attributesOf,
77
77
  entityConfigFor: () => entityConfigFor,
@@ -79,17 +79,19 @@ __export(index_exports, {
79
79
  getEntityMeta: () => getEntityMeta,
80
80
  getOnEvents: () => getOnEvents,
81
81
  getWorkflowMeta: () => getWorkflowMeta,
82
+ hmacTenantVerifier: () => import_nestjs_durable_core19.hmacTenantVerifier,
82
83
  inAppWorkerProviders: () => inAppWorkerProviders,
83
84
  isDeadLetterHandler: () => isDeadLetterHandler,
84
85
  isDrivingOperator: () => isDrivingOperator,
85
86
  isOperatorRole: () => isOperatorRole,
86
87
  isStepInterceptor: () => isStepInterceptor,
87
88
  onErrorCodesOf: () => onErrorCodesOf,
88
- prevCronFireMs: () => import_nestjs_durable_core18.prevCronFireMs,
89
- readSearchAttributes: () => import_nestjs_durable_core18.readSearchAttributes,
90
- runSchedules: () => import_nestjs_durable_core18.runSchedules,
91
- scheduleRunIdAt: () => import_nestjs_durable_core18.scheduleRunIdAt,
92
- scheduledRunId: () => import_nestjs_durable_core18.scheduledRunId,
89
+ prevCronFireMs: () => import_nestjs_durable_core19.prevCronFireMs,
90
+ readSearchAttributes: () => import_nestjs_durable_core19.readSearchAttributes,
91
+ runSchedules: () => import_nestjs_durable_core19.runSchedules,
92
+ scheduleRunIdAt: () => import_nestjs_durable_core19.scheduleRunIdAt,
93
+ scheduledRunId: () => import_nestjs_durable_core19.scheduledRunId,
94
+ signTenantToken: () => import_nestjs_durable_core19.signTenantToken,
93
95
  thinWorkerProviders: () => thinWorkerProviders,
94
96
  unavailableRunGateway: () => unavailableRunGateway
95
97
  });
@@ -416,7 +418,9 @@ var DurableStartClient = class {
416
418
  async start(workflow, input, runId = globalThis.crypto.randomUUID(), opts) {
417
419
  const name = (0, import_nestjs_durable_core3.workflowName)(workflow);
418
420
  await startRun(this.options.connection, {
419
- tenant: this.tenant,
421
+ // The signed token (when configured) rides in the `tenant` field, as on every run request; an
422
+ // operator with `verifyTenant` derives the run's namespace from it.
423
+ tenant: this.options.tenantToken !== void 0 ? await (0, import_nestjs_durable_core3.resolveTenantToken)(this.options.tenantToken) : this.tenant,
420
424
  workflow: name,
421
425
  input,
422
426
  runId,
@@ -917,7 +921,7 @@ function unavailableRunGateway() {
917
921
  __name(unavailableRunGateway, "unavailableRunGateway");
918
922
 
919
923
  // src/durable.module.ts
920
- var import_nestjs_durable_core17 = require("@dudousxd/nestjs-durable-core");
924
+ var import_nestjs_durable_core18 = require("@dudousxd/nestjs-durable-core");
921
925
  var import_common12 = require("@nestjs/common");
922
926
  var import_core5 = require("@nestjs/core");
923
927
 
@@ -1253,10 +1257,11 @@ function inAppWorkerProviders() {
1253
1257
  __name(inAppWorkerProviders, "inAppWorkerProviders");
1254
1258
 
1255
1259
  // src/proxy-run-gateway.ts
1256
- var import_nestjs_durable_core10 = require("@dudousxd/nestjs-durable-core");
1260
+ var import_nestjs_durable_core11 = require("@dudousxd/nestjs-durable-core");
1257
1261
  var import_common6 = require("@nestjs/common");
1258
1262
 
1259
1263
  // src/run-request-responder.ts
1264
+ var import_nestjs_durable_core10 = require("@dudousxd/nestjs-durable-core");
1260
1265
  var UNSUPPORTED_RUN_REQUEST = "unsupported-request";
1261
1266
  var KNOWN_KINDS = /* @__PURE__ */ new Set([
1262
1267
  "getRunDetail",
@@ -1278,9 +1283,14 @@ var RunRequestResponder = class {
1278
1283
  }
1279
1284
  transport;
1280
1285
  gateway;
1281
- constructor(transport, gateway) {
1286
+ verifyTenant;
1287
+ constructor(transport, gateway, options = {}) {
1282
1288
  this.transport = transport;
1283
1289
  this.gateway = gateway;
1290
+ this.verifyTenant = options.verifyTenant;
1291
+ if (!this.verifyTenant && options.warnWithoutVerifier !== false) {
1292
+ console.warn("[nestjs-durable] run-request responder started WITHOUT a tenant verifier: the wire `tenant` claim is trusted verbatim (prefix/network isolation only). Any broker client can act as any tenant. Configure `verifyTenant` (e.g. hmacTenantVerifier(secret)) and signed tenant tokens unless your broker is fully isolated per tenant.");
1293
+ }
1284
1294
  }
1285
1295
  /** Register the consumer on the transport. Each request is answered independently; a handler
1286
1296
  * failure never throws back into the transport (errors are captured into an error reply). */
@@ -1303,7 +1313,24 @@ var RunRequestResponder = class {
1303
1313
  await this.transport.publishRunReply(reply);
1304
1314
  });
1305
1315
  }
1306
- async handle(msg) {
1316
+ async handle(wire) {
1317
+ const tenant = await (0, import_nestjs_durable_core10.resolveWireTenant)(wire.tenant, this.verifyTenant);
1318
+ if (tenant === null) {
1319
+ return {
1320
+ requestId: wire.requestId,
1321
+ result: {
1322
+ ok: false,
1323
+ error: {
1324
+ message: "invalid or unauthorized tenant token",
1325
+ code: "unauthorized"
1326
+ }
1327
+ }
1328
+ };
1329
+ }
1330
+ const msg = {
1331
+ ...wire,
1332
+ tenant
1333
+ };
1307
1334
  const { body } = msg;
1308
1335
  if (!KNOWN_KINDS.has(body.kind)) {
1309
1336
  return {
@@ -1496,17 +1523,19 @@ var ProxyRunGateway = class {
1496
1523
  tenant;
1497
1524
  timeoutMs;
1498
1525
  capabilityTtlMs;
1526
+ tenantToken;
1499
1527
  pending = /* @__PURE__ */ new Map();
1500
1528
  /** Verb → when to ask the control plane for it again, after it answered that it does not know it.
1501
1529
  * During a rolling upgrade the control plane is several pods of mixed versions behind one queue,
1502
1530
  * and a reply does not say which pod sent it, so the whole control plane is assumed old until the
1503
1531
  * entry expires. */
1504
1532
  unsupportedUntil = /* @__PURE__ */ new Map();
1505
- constructor(transport, tenant, timeoutMs = 1e4, capabilityTtlMs = 6e4) {
1533
+ constructor(transport, tenant, timeoutMs = 1e4, capabilityTtlMs = 6e4, tenantToken) {
1506
1534
  this.transport = transport;
1507
1535
  this.tenant = tenant;
1508
1536
  this.timeoutMs = timeoutMs;
1509
1537
  this.capabilityTtlMs = capabilityTtlMs;
1538
+ this.tenantToken = tenantToken;
1510
1539
  this.transport.onRunReply?.((reply) => this.handleReply(reply));
1511
1540
  }
1512
1541
  handleReply(reply) {
@@ -1519,7 +1548,10 @@ var ProxyRunGateway = class {
1519
1548
  } else if (reply.result.error.code === UNSUPPORTED_RUN_REQUEST) {
1520
1549
  pending.reject(new UnsupportedRunRequestError(reply.result.error.message));
1521
1550
  } else {
1522
- pending.reject(new Error(reply.result.error.message));
1551
+ const { message, code } = reply.result.error;
1552
+ pending.reject(code !== void 0 ? Object.assign(new Error(message), {
1553
+ code
1554
+ }) : new Error(message));
1523
1555
  }
1524
1556
  }
1525
1557
  request(body) {
@@ -1534,11 +1566,17 @@ var ProxyRunGateway = class {
1534
1566
  reject,
1535
1567
  timer
1536
1568
  });
1537
- this.transport.dispatchRunRequest?.({
1569
+ const source = this.tenantToken;
1570
+ const dispatched = typeof source === "function" ? (0, import_nestjs_durable_core11.resolveTenantToken)(source).then((tenant) => this.transport.dispatchRunRequest?.({
1571
+ requestId,
1572
+ tenant,
1573
+ body
1574
+ })) : this.transport.dispatchRunRequest?.({
1538
1575
  requestId,
1539
- tenant: this.tenant,
1576
+ tenant: source ?? this.tenant,
1540
1577
  body
1541
- }).catch((error) => {
1578
+ });
1579
+ dispatched?.catch((error) => {
1542
1580
  const stillPending = this.pending.get(requestId);
1543
1581
  if (!stillPending) return;
1544
1582
  clearTimeout(stillPending.timer);
@@ -1568,12 +1606,12 @@ var ProxyRunGateway = class {
1568
1606
  });
1569
1607
  const over = options?.summarizeFansOver;
1570
1608
  if (over === void 0 || !detail || detail.fans !== void 0) return detail;
1571
- const { timeline, fans } = (0, import_nestjs_durable_core10.summarizeTimeline)(detail.timeline, over);
1572
- const ids = (0, import_nestjs_durable_core10.childIdsOf)(detail.timeline);
1609
+ const { timeline, fans } = (0, import_nestjs_durable_core11.summarizeTimeline)(detail.timeline, over);
1610
+ const ids = (0, import_nestjs_durable_core11.childIdsOf)(detail.timeline);
1573
1611
  return {
1574
1612
  ...detail,
1575
1613
  timeline,
1576
- children: ids.slice(0, import_nestjs_durable_core10.SUMMARY_CHILD_LIMIT),
1614
+ children: ids.slice(0, import_nestjs_durable_core11.SUMMARY_CHILD_LIMIT),
1577
1615
  fans,
1578
1616
  childCount: ids.length
1579
1617
  };
@@ -1598,7 +1636,7 @@ var ProxyRunGateway = class {
1598
1636
  kind: "getRunDetail",
1599
1637
  runId
1600
1638
  });
1601
- return detail ? (0, import_nestjs_durable_core10.pageFan)(detail.timeline, group, query) : null;
1639
+ return detail ? (0, import_nestjs_durable_core11.pageFan)(detail.timeline, group, query) : null;
1602
1640
  }
1603
1641
  knownUnsupported(kind) {
1604
1642
  const until = this.unsupportedUntil.get(kind);
@@ -1696,12 +1734,13 @@ ProxyRunGateway = _ts_decorate6([
1696
1734
  typeof Transport === "undefined" ? Object : Transport,
1697
1735
  String,
1698
1736
  void 0,
1699
- void 0
1737
+ void 0,
1738
+ typeof TenantTokenSource === "undefined" ? Object : TenantTokenSource
1700
1739
  ])
1701
1740
  ], ProxyRunGateway);
1702
1741
 
1703
1742
  // src/retention-poller.ts
1704
- var import_nestjs_durable_core11 = require("@dudousxd/nestjs-durable-core");
1743
+ var import_nestjs_durable_core12 = require("@dudousxd/nestjs-durable-core");
1705
1744
  var import_common7 = require("@nestjs/common");
1706
1745
 
1707
1746
  // src/settle-within.ts
@@ -1767,10 +1806,10 @@ function validateRetention(retention) {
1767
1806
  if (policy.maxAge == null && policy.maxCount == null) {
1768
1807
  throw new Error("durable retention: each policy must set maxAge and/or maxCount");
1769
1808
  }
1770
- if (policy.maxAge != null) (0, import_nestjs_durable_core11.parseDuration)(policy.maxAge);
1809
+ if (policy.maxAge != null) (0, import_nestjs_durable_core12.parseDuration)(policy.maxAge);
1771
1810
  for (const status of policy.statuses) {
1772
- if (!import_nestjs_durable_core11.TERMINAL_RUN_STATUSES.includes(status)) {
1773
- throw new Error(`durable retention: status "${status}" is not terminal; only ${import_nestjs_durable_core11.TERMINAL_RUN_STATUSES.join(", ")} can be pruned`);
1811
+ if (!import_nestjs_durable_core12.TERMINAL_RUN_STATUSES.includes(status)) {
1812
+ throw new Error(`durable retention: status "${status}" is not terminal; only ${import_nestjs_durable_core12.TERMINAL_RUN_STATUSES.join(", ")} can be pruned`);
1774
1813
  }
1775
1814
  const key = `${scopeKey}|${status}`;
1776
1815
  if (seen.has(key)) {
@@ -1822,7 +1861,7 @@ var RetentionPoller = class {
1822
1861
  return;
1823
1862
  }
1824
1863
  await this.sweep();
1825
- const intervalMs = retention.sweepInterval != null ? (0, import_nestjs_durable_core11.parseDuration)(retention.sweepInterval) : DEFAULT_SWEEP_INTERVAL_MS;
1864
+ const intervalMs = retention.sweepInterval != null ? (0, import_nestjs_durable_core12.parseDuration)(retention.sweepInterval) : DEFAULT_SWEEP_INTERVAL_MS;
1826
1865
  if (intervalMs > 0) {
1827
1866
  this.timer = setInterval(() => void this.sweep(), intervalMs);
1828
1867
  this.timer.unref?.();
@@ -1884,8 +1923,8 @@ var RetentionPoller = class {
1884
1923
  };
1885
1924
  RetentionPoller = _ts_decorate7([
1886
1925
  (0, import_common7.Injectable)(),
1887
- _ts_param4(0, (0, import_common7.Inject)(import_nestjs_durable_core11.STATE_STORE_CANONICAL)),
1888
- _ts_param4(1, (0, import_common7.Inject)(import_nestjs_durable_core11.DURABLE_OPTIONS_CANONICAL)),
1926
+ _ts_param4(0, (0, import_common7.Inject)(import_nestjs_durable_core12.STATE_STORE_CANONICAL)),
1927
+ _ts_param4(1, (0, import_common7.Inject)(import_nestjs_durable_core12.DURABLE_OPTIONS_CANONICAL)),
1889
1928
  _ts_metadata7("design:type", Function),
1890
1929
  _ts_metadata7("design:paramtypes", [
1891
1930
  Object,
@@ -1894,7 +1933,7 @@ RetentionPoller = _ts_decorate7([
1894
1933
  ], RetentionPoller);
1895
1934
 
1896
1935
  // src/store-run-gateway.ts
1897
- var import_nestjs_durable_core12 = require("@dudousxd/nestjs-durable-core");
1936
+ var import_nestjs_durable_core13 = require("@dudousxd/nestjs-durable-core");
1898
1937
  var import_common8 = require("@nestjs/common");
1899
1938
  function _ts_decorate8(decorators, target, key, desc) {
1900
1939
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -1952,10 +1991,10 @@ var StoreRunGateway = class {
1952
1991
  children
1953
1992
  };
1954
1993
  }
1955
- if ((0, import_nestjs_durable_core12.aggregatesCheckpoints)(this.store)) {
1994
+ if ((0, import_nestjs_durable_core13.aggregatesCheckpoints)(this.store)) {
1956
1995
  const stats = await this.store.checkpointStats(runId);
1957
- const etag = (0, import_nestjs_durable_core12.runDetailEtag)(run, stats, over);
1958
- if ((0, import_nestjs_durable_core12.etagMatches)(options?.ifNoneMatch, etag)) {
1996
+ const etag = (0, import_nestjs_durable_core13.runDetailEtag)(run, stats, over);
1997
+ if ((0, import_nestjs_durable_core13.etagMatches)(options?.ifNoneMatch, etag)) {
1959
1998
  return {
1960
1999
  run,
1961
2000
  timeline: [],
@@ -1966,17 +2005,17 @@ var StoreRunGateway = class {
1966
2005
  }
1967
2006
  return {
1968
2007
  run,
1969
- ...await (0, import_nestjs_durable_core12.summarizeRunFromStore)(this.store, runId, over, stats),
2008
+ ...await (0, import_nestjs_durable_core13.summarizeRunFromStore)(this.store, runId, over, stats),
1970
2009
  etag
1971
2010
  };
1972
2011
  }
1973
2012
  const full = await this.store.listCheckpoints(runId);
1974
- const { timeline, fans } = (0, import_nestjs_durable_core12.summarizeTimeline)(full, over);
1975
- const ids = (0, import_nestjs_durable_core12.childIdsOf)(full);
2013
+ const { timeline, fans } = (0, import_nestjs_durable_core13.summarizeTimeline)(full, over);
2014
+ const ids = (0, import_nestjs_durable_core13.childIdsOf)(full);
1976
2015
  return {
1977
2016
  run,
1978
2017
  timeline,
1979
- children: ids.slice(0, import_nestjs_durable_core12.SUMMARY_CHILD_LIMIT),
2018
+ children: ids.slice(0, import_nestjs_durable_core13.SUMMARY_CHILD_LIMIT),
1980
2019
  fans,
1981
2020
  childCount: ids.length
1982
2021
  };
@@ -1986,12 +2025,12 @@ var StoreRunGateway = class {
1986
2025
  }
1987
2026
  async getFanMembers(runId, group, query) {
1988
2027
  if (!await this.store.getRun(runId)) return null;
1989
- if ((0, import_nestjs_durable_core12.aggregatesCheckpoints)(this.store)) {
2028
+ if ((0, import_nestjs_durable_core13.aggregatesCheckpoints)(this.store)) {
1990
2029
  const stats = await this.store.checkpointStats(runId, {
1991
2030
  group
1992
2031
  });
1993
- const etag = (0, import_nestjs_durable_core12.fanPageEtag)(group, stats, query);
1994
- if ((0, import_nestjs_durable_core12.etagMatches)(query.ifNoneMatch, etag)) {
2032
+ const etag = (0, import_nestjs_durable_core13.fanPageEtag)(group, stats, query);
2033
+ if ((0, import_nestjs_durable_core13.etagMatches)(query.ifNoneMatch, etag)) {
1995
2034
  return {
1996
2035
  items: [],
1997
2036
  total: 0,
@@ -2000,17 +2039,17 @@ var StoreRunGateway = class {
2000
2039
  };
2001
2040
  }
2002
2041
  return {
2003
- ...await (0, import_nestjs_durable_core12.pageFanFromStore)(this.store, runId, group, query, stats),
2042
+ ...await (0, import_nestjs_durable_core13.pageFanFromStore)(this.store, runId, group, query, stats),
2004
2043
  etag
2005
2044
  };
2006
2045
  }
2007
- return (0, import_nestjs_durable_core12.pageFan)(await this.store.listCheckpoints(runId), group, query);
2046
+ return (0, import_nestjs_durable_core13.pageFan)(await this.store.listCheckpoints(runId), group, query);
2008
2047
  }
2009
2048
  async listRuns(query) {
2010
2049
  const runs = await this.store.listRuns(query);
2011
- const waiterByRun = (0, import_nestjs_durable_core12.indexWaitersByRun)(await (0, import_nestjs_durable_core12.listSignalWaitersOfRuns)(this.store, runs.filter((run) => run.status === "suspended").map((run) => run.id)));
2050
+ const waiterByRun = (0, import_nestjs_durable_core13.indexWaitersByRun)(await (0, import_nestjs_durable_core13.listSignalWaitersOfRuns)(this.store, runs.filter((run) => run.status === "suspended").map((run) => run.id)));
2012
2051
  return runs.map((run) => {
2013
- const waiting = (0, import_nestjs_durable_core12.resolveRunWaiting)(run, waiterByRun);
2052
+ const waiting = (0, import_nestjs_durable_core13.resolveRunWaiting)(run, waiterByRun);
2014
2053
  return waiting ? {
2015
2054
  ...run,
2016
2055
  waiting
@@ -2026,7 +2065,7 @@ var StoreRunGateway = class {
2026
2065
  async runFacets(query) {
2027
2066
  if (this.store.runFacets) return this.store.runFacets(query);
2028
2067
  const runs = await this.store.listRuns(query);
2029
- return (0, import_nestjs_durable_core12.mergeRunFacetRows)(runs.map((r) => ({
2068
+ return (0, import_nestjs_durable_core13.mergeRunFacetRows)(runs.map((r) => ({
2030
2069
  status: r.status,
2031
2070
  origin: r.origin,
2032
2071
  count: 1
@@ -2061,13 +2100,13 @@ var StoreRunGateway = class {
2061
2100
  "suspended"
2062
2101
  ]
2063
2102
  }),
2064
- (0, import_nestjs_durable_core12.listSignalWaitersOfRuns)(this.store, runIds)
2103
+ (0, import_nestjs_durable_core13.listSignalWaitersOfRuns)(this.store, runIds)
2065
2104
  ]);
2066
- const waiterByRun = (0, import_nestjs_durable_core12.indexWaitersByRun)(waiters);
2105
+ const waiterByRun = (0, import_nestjs_durable_core13.indexWaitersByRun)(waiters);
2067
2106
  const result = {};
2068
2107
  for (const run of suspended) {
2069
2108
  if (!idSet.has(run.id)) continue;
2070
- const waiting = (0, import_nestjs_durable_core12.resolveRunWaiting)(run, waiterByRun);
2109
+ const waiting = (0, import_nestjs_durable_core13.resolveRunWaiting)(run, waiterByRun);
2071
2110
  if (waiting) result[run.id] = waiting;
2072
2111
  }
2073
2112
  return result;
@@ -2101,11 +2140,11 @@ var StoreRunGateway = class {
2101
2140
  };
2102
2141
  StoreRunGateway = _ts_decorate8([
2103
2142
  (0, import_common8.Injectable)(),
2104
- _ts_param5(0, (0, import_common8.Inject)(import_nestjs_durable_core12.STATE_STORE_CANONICAL)),
2143
+ _ts_param5(0, (0, import_common8.Inject)(import_nestjs_durable_core13.STATE_STORE_CANONICAL)),
2105
2144
  _ts_metadata8("design:type", Function),
2106
2145
  _ts_metadata8("design:paramtypes", [
2107
2146
  typeof StateStore === "undefined" ? Object : StateStore,
2108
- typeof import_nestjs_durable_core12.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core12.WorkflowEngine
2147
+ typeof import_nestjs_durable_core13.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core13.WorkflowEngine
2109
2148
  ])
2110
2149
  ], StoreRunGateway);
2111
2150
 
@@ -2151,7 +2190,7 @@ var TenantEventRepublisher = class {
2151
2190
  };
2152
2191
 
2153
2192
  // src/timer-poller.ts
2154
- var import_nestjs_durable_core13 = require("@dudousxd/nestjs-durable-core");
2193
+ var import_nestjs_durable_core14 = require("@dudousxd/nestjs-durable-core");
2155
2194
  var import_common9 = require("@nestjs/common");
2156
2195
  function _ts_decorate9(decorators, target, key, desc) {
2157
2196
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -2195,7 +2234,7 @@ var TimerPoller = class {
2195
2234
  this.options = options;
2196
2235
  }
2197
2236
  async onApplicationBootstrap() {
2198
- for (const s of this.options.schedules ?? []) (0, import_nestjs_durable_core13.workflowName)(s.workflow);
2237
+ for (const s of this.options.schedules ?? []) (0, import_nestjs_durable_core14.workflowName)(s.workflow);
2199
2238
  if (!isDrivingOperator(this.options)) return;
2200
2239
  this.unsubscribeEnqueued = this.engine.onEnqueued((runId) => {
2201
2240
  void this.engine.runOne(runId).catch((error) => {
@@ -2265,7 +2304,7 @@ var TimerPoller = class {
2265
2304
  await this.sweep("sweepStalled", async () => this.engine.sweepStalled?.());
2266
2305
  const schedules = this.options.schedules;
2267
2306
  if (schedules && schedules.length > 0) {
2268
- await this.sweep("schedules", () => (0, import_nestjs_durable_core13.runSchedules)(this.engine, schedules, Date.now()));
2307
+ await this.sweep("schedules", () => (0, import_nestjs_durable_core14.runSchedules)(this.engine, schedules, Date.now()));
2269
2308
  }
2270
2309
  if (this.options.persistedSchedules) {
2271
2310
  await this.sweep("persistedSchedules", () => this.engine.schedules.tick());
@@ -2283,21 +2322,21 @@ var TimerPoller = class {
2283
2322
  };
2284
2323
  TimerPoller = _ts_decorate9([
2285
2324
  (0, import_common9.Injectable)(),
2286
- _ts_param6(1, (0, import_common9.Inject)(import_nestjs_durable_core13.DURABLE_OPTIONS_CANONICAL)),
2325
+ _ts_param6(1, (0, import_common9.Inject)(import_nestjs_durable_core14.DURABLE_OPTIONS_CANONICAL)),
2287
2326
  _ts_metadata9("design:type", Function),
2288
2327
  _ts_metadata9("design:paramtypes", [
2289
- typeof import_nestjs_durable_core13.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core13.WorkflowEngine,
2328
+ typeof import_nestjs_durable_core14.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core14.WorkflowEngine,
2290
2329
  typeof DurableModuleOptions === "undefined" ? Object : DurableModuleOptions
2291
2330
  ])
2292
2331
  ], TimerPoller);
2293
2332
 
2294
2333
  // src/tokens.ts
2295
- var import_nestjs_durable_core14 = require("@dudousxd/nestjs-durable-core");
2334
+ var import_nestjs_durable_core15 = require("@dudousxd/nestjs-durable-core");
2296
2335
  var CONTEXT_ACCESSOR = Symbol.for("@dudousxd/nestjs-context:accessor");
2297
- var RUN_GATEWAY = import_nestjs_durable_core14.RunGateway;
2336
+ var RUN_GATEWAY = import_nestjs_durable_core15.RunGateway;
2298
2337
 
2299
2338
  // src/workflow.registrar.ts
2300
- var import_nestjs_durable_core15 = require("@dudousxd/nestjs-durable-core");
2339
+ var import_nestjs_durable_core16 = require("@dudousxd/nestjs-durable-core");
2301
2340
  var import_common10 = require("@nestjs/common");
2302
2341
  var import_core4 = require("@nestjs/core");
2303
2342
 
@@ -2407,11 +2446,11 @@ var WorkflowRegistrar = class {
2407
2446
  const body = io.wrap((ctx, input) => workflow.run(ctx, input));
2408
2447
  const eventBatch = meta.debounce ? {
2409
2448
  mode: "debounce",
2410
- windowMs: (0, import_nestjs_durable_core15.parseDuration)(meta.debounce)
2449
+ windowMs: (0, import_nestjs_durable_core16.parseDuration)(meta.debounce)
2411
2450
  } : meta.batch ? {
2412
2451
  mode: "batch",
2413
2452
  maxSize: meta.batch.maxSize,
2414
- windowMs: (0, import_nestjs_durable_core15.parseDuration)(meta.batch.within)
2453
+ windowMs: (0, import_nestjs_durable_core16.parseDuration)(meta.batch.within)
2415
2454
  } : void 0;
2416
2455
  const workflowCtor = workflow.constructor;
2417
2456
  const onError = onErrorHandlersOf(meta, workflow, this.metadataScanner);
@@ -2445,11 +2484,11 @@ var WorkflowRegistrar = class {
2445
2484
  // so a turn dispatched under the wrong token would never be consumed. Absent → the inline fast
2446
2485
  // path (unchanged).
2447
2486
  ...this.inAppWorker ? {
2448
- group: (0, import_nestjs_durable_core15.tenantGroup)((0, import_nestjs_durable_core15.sanitizeQueueToken)(meta.name), this.inAppWorker.partition),
2449
- executor: new import_nestjs_durable_core15.RemoteWorkflowExecutor(this.inAppWorker.transport, meta.name, this.inAppWorker.partition)
2487
+ group: (0, import_nestjs_durable_core16.tenantGroup)((0, import_nestjs_durable_core16.sanitizeQueueToken)(meta.name), this.inAppWorker.partition),
2488
+ executor: new import_nestjs_durable_core16.RemoteWorkflowExecutor(this.inAppWorker.transport, meta.name, this.inAppWorker.partition)
2450
2489
  } : {}
2451
2490
  });
2452
- (0, import_nestjs_durable_core15.bindWorkflowClass)(workflowCtor, {
2491
+ (0, import_nestjs_durable_core16.bindWorkflowClass)(workflowCtor, {
2453
2492
  start: /* @__PURE__ */ __name((name, input, runId, opts) => this.engine.start(name, input, runId, opts), "start"),
2454
2493
  waitForRun: /* @__PURE__ */ __name((runId, opts) => this.engine.waitForRun(runId, opts), "waitForRun")
2455
2494
  });
@@ -2464,7 +2503,7 @@ var WorkflowRegistrar = class {
2464
2503
  });
2465
2504
  deadLetterByWorkflow.set(meta.name, dlqName);
2466
2505
  } else if (meta.deadLetterWorkflow) {
2467
- deadLetterByWorkflow.set(meta.name, (0, import_nestjs_durable_core15.workflowName)(meta.deadLetterWorkflow));
2506
+ deadLetterByWorkflow.set(meta.name, (0, import_nestjs_durable_core16.workflowName)(meta.deadLetterWorkflow));
2468
2507
  }
2469
2508
  });
2470
2509
  this.reportUnattributed(unattributed);
@@ -2512,7 +2551,7 @@ var WorkflowRegistrar = class {
2512
2551
  * a `dlq:<runId>` id, so re-recovery never double-dispatches.
2513
2552
  */
2514
2553
  installDeadLetterRouting(byWorkflow) {
2515
- const fallback = this.options.deadLetterWorkflow ? (0, import_nestjs_durable_core15.workflowName)(this.options.deadLetterWorkflow) : void 0;
2554
+ const fallback = this.options.deadLetterWorkflow ? (0, import_nestjs_durable_core16.workflowName)(this.options.deadLetterWorkflow) : void 0;
2516
2555
  if (byWorkflow.size === 0 && !fallback) return;
2517
2556
  this.engine.onDead((run) => {
2518
2557
  const target = byWorkflow.get(run.workflow) ?? fallback;
@@ -2537,14 +2576,14 @@ var WorkflowRegistrar = class {
2537
2576
  };
2538
2577
  WorkflowRegistrar = _ts_decorate10([
2539
2578
  (0, import_common10.Injectable)(),
2540
- _ts_param7(3, (0, import_common10.Inject)(import_nestjs_durable_core15.STATE_STORE_CANONICAL)),
2541
- _ts_param7(4, (0, import_common10.Inject)(import_nestjs_durable_core15.DURABLE_OPTIONS_CANONICAL)),
2579
+ _ts_param7(3, (0, import_common10.Inject)(import_nestjs_durable_core16.STATE_STORE_CANONICAL)),
2580
+ _ts_param7(4, (0, import_common10.Inject)(import_nestjs_durable_core16.DURABLE_OPTIONS_CANONICAL)),
2542
2581
  _ts_param7(5, (0, import_common10.Inject)(IN_APP_WORKER_BINDING)),
2543
2582
  _ts_metadata10("design:type", Function),
2544
2583
  _ts_metadata10("design:paramtypes", [
2545
2584
  typeof import_core4.DiscoveryService === "undefined" ? Object : import_core4.DiscoveryService,
2546
2585
  typeof import_core4.MetadataScanner === "undefined" ? Object : import_core4.MetadataScanner,
2547
- typeof import_nestjs_durable_core15.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core15.WorkflowEngine,
2586
+ typeof import_nestjs_durable_core16.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core16.WorkflowEngine,
2548
2587
  Object,
2549
2588
  typeof DurableModuleOptions === "undefined" ? Object : DurableModuleOptions,
2550
2589
  Object
@@ -2553,7 +2592,7 @@ WorkflowRegistrar = _ts_decorate10([
2553
2592
 
2554
2593
  // src/workflow.service.ts
2555
2594
  var import_node_crypto = require("crypto");
2556
- var import_nestjs_durable_core16 = require("@dudousxd/nestjs-durable-core");
2595
+ var import_nestjs_durable_core17 = require("@dudousxd/nestjs-durable-core");
2557
2596
  var import_common11 = require("@nestjs/common");
2558
2597
  function _ts_decorate11(decorators, target, key, desc) {
2559
2598
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -2624,7 +2663,7 @@ WorkflowService = _ts_decorate11([
2624
2663
  (0, import_common11.Injectable)(),
2625
2664
  _ts_metadata11("design:type", Function),
2626
2665
  _ts_metadata11("design:paramtypes", [
2627
- typeof import_nestjs_durable_core16.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core16.WorkflowEngine
2666
+ typeof import_nestjs_durable_core17.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core17.WorkflowEngine
2628
2667
  ])
2629
2668
  ], WorkflowService);
2630
2669
 
@@ -2821,7 +2860,15 @@ var RunGatewayBootstrap = class RunGatewayBootstrap2 {
2821
2860
  onRunRequest: onRunRequest.bind(this.transport),
2822
2861
  publishRunReply: publishRunReply.bind(this.transport)
2823
2862
  };
2824
- new RunRequestResponder(runRequestTransport, this.gateway).start();
2863
+ new RunRequestResponder(runRequestTransport, this.gateway, {
2864
+ verifyTenant: this.options.verifyTenant,
2865
+ // Mirrors Agora's rule (`warnWithoutVerifier: role === 'control-plane'`): only a deployment
2866
+ // that EXPLICITLY names itself the control plane is told it runs without tenant auth. A plain
2867
+ // operator (role inferred from `store`) is Agora's `standalone`: anyone with broker access
2868
+ // can already enqueue steps and results there, so the warning would be noise on every boot
2869
+ // of an app that never serves tenants.
2870
+ warnWithoutVerifier: this.options.topology?.role === "control-plane"
2871
+ }).start();
2825
2872
  }
2826
2873
  if (typeof publishTenantEvent === "function") {
2827
2874
  const republisher = new TenantEventRepublisher(store, publishTenantEvent.bind(this.transport));
@@ -2836,14 +2883,14 @@ var RunGatewayBootstrap = class RunGatewayBootstrap2 {
2836
2883
  };
2837
2884
  RunGatewayBootstrap = _ts_decorate12([
2838
2885
  (0, import_common12.Injectable)(),
2839
- _ts_param8(1, (0, import_common12.Inject)(import_nestjs_durable_core17.TRANSPORT_CANONICAL)),
2840
- _ts_param8(3, (0, import_common12.Inject)(import_nestjs_durable_core17.STATE_STORE_CANONICAL)),
2841
- _ts_param8(4, (0, import_common12.Inject)(import_nestjs_durable_core17.DURABLE_OPTIONS_CANONICAL)),
2886
+ _ts_param8(1, (0, import_common12.Inject)(import_nestjs_durable_core18.TRANSPORT_CANONICAL)),
2887
+ _ts_param8(3, (0, import_common12.Inject)(import_nestjs_durable_core18.STATE_STORE_CANONICAL)),
2888
+ _ts_param8(4, (0, import_common12.Inject)(import_nestjs_durable_core18.DURABLE_OPTIONS_CANONICAL)),
2842
2889
  _ts_metadata12("design:type", Function),
2843
2890
  _ts_metadata12("design:paramtypes", [
2844
- typeof import_nestjs_durable_core17.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core17.WorkflowEngine,
2891
+ typeof import_nestjs_durable_core18.WorkflowEngine === "undefined" ? Object : import_nestjs_durable_core18.WorkflowEngine,
2845
2892
  Object,
2846
- typeof import_nestjs_durable_core17.RunGateway === "undefined" ? Object : import_nestjs_durable_core17.RunGateway,
2893
+ typeof import_nestjs_durable_core18.RunGateway === "undefined" ? Object : import_nestjs_durable_core18.RunGateway,
2847
2894
  Object,
2848
2895
  typeof DurableModuleOptions === "undefined" ? Object : DurableModuleOptions
2849
2896
  ])
@@ -2855,13 +2902,13 @@ var DurableModule = class _DurableModule {
2855
2902
  static forRoot(options) {
2856
2903
  _DurableModule.assertValid(options);
2857
2904
  return _DurableModule.build({
2858
- provide: import_nestjs_durable_core17.DURABLE_OPTIONS_CANONICAL,
2905
+ provide: import_nestjs_durable_core18.DURABLE_OPTIONS_CANONICAL,
2859
2906
  useValue: resolveTopology(options)
2860
2907
  });
2861
2908
  }
2862
2909
  static forRootAsync(options) {
2863
2910
  return _DurableModule.build({
2864
- provide: import_nestjs_durable_core17.DURABLE_OPTIONS_CANONICAL,
2911
+ provide: import_nestjs_durable_core18.DURABLE_OPTIONS_CANONICAL,
2865
2912
  useFactory: /* @__PURE__ */ __name(async (...args) => {
2866
2913
  const resolved = await options.useFactory(...args);
2867
2914
  _DurableModule.assertValid(resolved);
@@ -2894,41 +2941,41 @@ var DurableModule = class _DurableModule {
2894
2941
  providers: [
2895
2942
  optionsProvider,
2896
2943
  {
2897
- provide: import_nestjs_durable_core17.STATE_STORE_CANONICAL,
2944
+ provide: import_nestjs_durable_core18.STATE_STORE_CANONICAL,
2898
2945
  useFactory: /* @__PURE__ */ __name((options) => options.store !== void 0 ? scopedStore(options.store, options) : null, "useFactory"),
2899
2946
  inject: [
2900
- import_nestjs_durable_core17.DURABLE_OPTIONS_CANONICAL
2947
+ import_nestjs_durable_core18.DURABLE_OPTIONS_CANONICAL
2901
2948
  ]
2902
2949
  },
2903
2950
  {
2904
- provide: import_nestjs_durable_core17.TRANSPORT_CANONICAL,
2951
+ provide: import_nestjs_durable_core18.TRANSPORT_CANONICAL,
2905
2952
  // With a POOL (`transports`) and no singular `transport`, the canonical transport is the
2906
2953
  // pool's PRIMARY — the same one the engine dispatches on first. Leaving it null starved
2907
2954
  // the step registrar / in-app worker of a transport, so a pool-configured operator
2908
2955
  // registered NO step handlers and its own steps parked in `wait` with no consumer.
2909
2956
  useFactory: /* @__PURE__ */ __name((options) => options.transport ?? options.transports?.[0]?.transport ?? null, "useFactory"),
2910
2957
  inject: [
2911
- import_nestjs_durable_core17.DURABLE_OPTIONS_CANONICAL
2958
+ import_nestjs_durable_core18.DURABLE_OPTIONS_CANONICAL
2912
2959
  ]
2913
2960
  },
2914
2961
  // Legacy back-compat aliases (deprecated tokens still resolve to the same instances):
2915
2962
  {
2916
- provide: import_nestjs_durable_core17.STATE_STORE,
2917
- useExisting: import_nestjs_durable_core17.STATE_STORE_CANONICAL
2963
+ provide: import_nestjs_durable_core18.STATE_STORE,
2964
+ useExisting: import_nestjs_durable_core18.STATE_STORE_CANONICAL
2918
2965
  },
2919
2966
  {
2920
- provide: import_nestjs_durable_core17.TRANSPORT,
2921
- useExisting: import_nestjs_durable_core17.TRANSPORT_CANONICAL
2967
+ provide: import_nestjs_durable_core18.TRANSPORT,
2968
+ useExisting: import_nestjs_durable_core18.TRANSPORT_CANONICAL
2922
2969
  },
2923
2970
  {
2924
- provide: import_nestjs_durable_core17.DURABLE_OPTIONS,
2925
- useExisting: import_nestjs_durable_core17.DURABLE_OPTIONS_CANONICAL
2971
+ provide: import_nestjs_durable_core18.DURABLE_OPTIONS,
2972
+ useExisting: import_nestjs_durable_core18.DURABLE_OPTIONS_CANONICAL
2926
2973
  },
2927
2974
  {
2928
2975
  // Shared token, bound EXACTLY once: a real engine for the operator role, or a store-less
2929
2976
  // `DurableStartClient` facade for a thin worker (no `store`) — either way, `WorkflowService`
2930
2977
  // and app code call `engine.start(...)` unchanged.
2931
- provide: import_nestjs_durable_core17.WorkflowEngine,
2978
+ provide: import_nestjs_durable_core18.WorkflowEngine,
2932
2979
  useFactory: /* @__PURE__ */ __name(async (options, store, transport, moduleRef) => {
2933
2980
  if (options.store === void 0) {
2934
2981
  return new DurableStartClient(options);
@@ -2949,7 +2996,7 @@ var DurableModule = class _DurableModule {
2949
2996
  if (t) deferTransportConsumers(t);
2950
2997
  }
2951
2998
  }
2952
- const engine = new import_nestjs_durable_core17.WorkflowEngine({
2999
+ const engine = new import_nestjs_durable_core18.WorkflowEngine({
2953
3000
  store,
2954
3001
  transport: transport ?? void 0,
2955
3002
  transports: options.transports,
@@ -2973,6 +3020,7 @@ var DurableModule = class _DurableModule {
2973
3020
  context,
2974
3021
  rehydrate: rehydrate || void 0,
2975
3022
  compensationRetries: options.compensationRetries,
3023
+ verifyTenant: options.verifyTenant,
2976
3024
  // A non-driving (dashboard/API) operator must not run workflows: enqueue-only, leaving
2977
3025
  // each `pending` run in the store for a DRIVING instance's poll. A driving operator gets
2978
3026
  // the engine's default in-process dispatcher: for a body registered inline, it runs
@@ -2989,9 +3037,9 @@ var DurableModule = class _DurableModule {
2989
3037
  return engine;
2990
3038
  }, "useFactory"),
2991
3039
  inject: [
2992
- import_nestjs_durable_core17.DURABLE_OPTIONS_CANONICAL,
2993
- import_nestjs_durable_core17.STATE_STORE_CANONICAL,
2994
- import_nestjs_durable_core17.TRANSPORT_CANONICAL,
3040
+ import_nestjs_durable_core18.DURABLE_OPTIONS_CANONICAL,
3041
+ import_nestjs_durable_core18.STATE_STORE_CANONICAL,
3042
+ import_nestjs_durable_core18.TRANSPORT_CANONICAL,
2995
3043
  import_core5.ModuleRef
2996
3044
  ]
2997
3045
  },
@@ -3005,7 +3053,7 @@ var DurableModule = class _DurableModule {
3005
3053
  // or (for a thin worker, no `store`) a `ProxyRunGateway` over `transport` when given, else a
3006
3054
  // gateway whose every method rejects with a clear tenant error.
3007
3055
  {
3008
- provide: import_nestjs_durable_core17.RunGateway,
3056
+ provide: import_nestjs_durable_core18.RunGateway,
3009
3057
  useFactory: /* @__PURE__ */ __name((options, store, engine) => {
3010
3058
  if (options.store !== void 0) {
3011
3059
  if (!store) {
@@ -3013,12 +3061,12 @@ var DurableModule = class _DurableModule {
3013
3061
  }
3014
3062
  return new StoreRunGateway(store, engine);
3015
3063
  }
3016
- return options.transport ? new ProxyRunGateway(options.transport, options.partition ?? "default", options.runGatewayTimeoutMs) : unavailableRunGateway();
3064
+ return options.transport ? new ProxyRunGateway(options.transport, options.partition ?? "default", options.runGatewayTimeoutMs, void 0, options.tenantToken) : unavailableRunGateway();
3017
3065
  }, "useFactory"),
3018
3066
  inject: [
3019
- import_nestjs_durable_core17.DURABLE_OPTIONS_CANONICAL,
3020
- import_nestjs_durable_core17.STATE_STORE_CANONICAL,
3021
- import_nestjs_durable_core17.WorkflowEngine
3067
+ import_nestjs_durable_core18.DURABLE_OPTIONS_CANONICAL,
3068
+ import_nestjs_durable_core18.STATE_STORE_CANONICAL,
3069
+ import_nestjs_durable_core18.WorkflowEngine
3022
3070
  ]
3023
3071
  },
3024
3072
  RunGatewayBootstrap,
@@ -3032,13 +3080,13 @@ var DurableModule = class _DurableModule {
3032
3080
  exports: [
3033
3081
  WorkflowService,
3034
3082
  EntityService,
3035
- import_nestjs_durable_core17.WorkflowEngine,
3036
- import_nestjs_durable_core17.STATE_STORE,
3037
- import_nestjs_durable_core17.STATE_STORE_CANONICAL,
3038
- import_nestjs_durable_core17.TRANSPORT,
3039
- import_nestjs_durable_core17.TRANSPORT_CANONICAL,
3040
- import_nestjs_durable_core17.DURABLE_OPTIONS_CANONICAL,
3041
- import_nestjs_durable_core17.RunGateway
3083
+ import_nestjs_durable_core18.WorkflowEngine,
3084
+ import_nestjs_durable_core18.STATE_STORE,
3085
+ import_nestjs_durable_core18.STATE_STORE_CANONICAL,
3086
+ import_nestjs_durable_core18.TRANSPORT,
3087
+ import_nestjs_durable_core18.TRANSPORT_CANONICAL,
3088
+ import_nestjs_durable_core18.DURABLE_OPTIONS_CANONICAL,
3089
+ import_nestjs_durable_core18.RunGateway
3042
3090
  ]
3043
3091
  };
3044
3092
  }
@@ -3048,7 +3096,7 @@ DurableModule = _ts_decorate12([
3048
3096
  ], DurableModule);
3049
3097
 
3050
3098
  // src/index.ts
3051
- var import_nestjs_durable_core18 = require("@dudousxd/nestjs-durable-core");
3099
+ var import_nestjs_durable_core19 = require("@dudousxd/nestjs-durable-core");
3052
3100
  // Annotate the CommonJS export names for ESM import in node:
3053
3101
  0 && (module.exports = {
3054
3102
  CONTEXT_ACCESSOR,
@@ -3099,6 +3147,7 @@ var import_nestjs_durable_core18 = require("@dudousxd/nestjs-durable-core");
3099
3147
  getEntityMeta,
3100
3148
  getOnEvents,
3101
3149
  getWorkflowMeta,
3150
+ hmacTenantVerifier,
3102
3151
  inAppWorkerProviders,
3103
3152
  isDeadLetterHandler,
3104
3153
  isDrivingOperator,
@@ -3110,6 +3159,7 @@ var import_nestjs_durable_core18 = require("@dudousxd/nestjs-durable-core");
3110
3159
  runSchedules,
3111
3160
  scheduleRunIdAt,
3112
3161
  scheduledRunId,
3162
+ signTenantToken,
3113
3163
  thinWorkerProviders,
3114
3164
  unavailableRunGateway
3115
3165
  });