@dudousxd/nestjs-durable 0.50.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 +169 -129
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -7
- package/dist/index.d.ts +67 -7
- package/dist/index.js +81 -47
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/skills/durable-workflows/SKILL.md +5 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { WorkflowCtx, SearchAttributes, WorkflowClass, StandardSchemaV1, StepError, OnErrorInput, WorkflowRef, SingletonConfig, ConcurrencyConfig, SearchAttributesSchema, StateStore, Transport, NamedTransport, ControlPlane, StalledRunInfo, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowInputOf, StartOptions, RunResult, RunGateway, WorkflowEngine, EntityHandler, DurableTopology, RunDetailOptions, RunDetail, FanPageQuery, FanPage, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, GroupHealth, RunWaiting, EngineEvent, RunRequest, RunReply, StepInvocation, WorkflowRun, TenantEvent } from '@dudousxd/nestjs-durable-core';
|
|
2
|
-
export { AttributeFilter, DynamicWorkflowCtx, EngineEvent, InferSearchAttributes, OnErrorInput, RunDetail, RunGateway, RunListItem, RunQuery, RunStatus, RunWaiting, SearchAttributes, SearchAttributesSchema, StepCheckpoint, StepEvent, StepLogger, WorkflowCtx, WorkflowEngine, WorkflowHandler, WorkflowRun, readSearchAttributes } from '@dudousxd/nestjs-durable-core';
|
|
1
|
+
import { WorkflowCtx, SearchAttributes, WorkflowClass, StandardSchemaV1, StepError, OnErrorInput, WorkflowRef, SingletonConfig, ConcurrencyConfig, SearchAttributesSchema, StateStore, Transport, NamedTransport, ControlPlane, StalledRunInfo, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, TenantVerifier, TenantTokenSource, WorkflowInputOf, StartOptions, RunResult, RunGateway, WorkflowEngine, EntityHandler, DurableTopology, RunDetailOptions, RunDetail, FanPageQuery, FanPage, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, GroupHealth, RunWaiting, EngineEvent, RunRequest, RunReply, StepInvocation, WorkflowRun, TenantEvent } from '@dudousxd/nestjs-durable-core';
|
|
2
|
+
export { AttributeFilter, DynamicWorkflowCtx, EngineEvent, InferSearchAttributes, OnErrorInput, RunDetail, RunGateway, RunListItem, RunQuery, RunSchedulesOptions, RunStatus, RunWaiting, ScheduledWorkflow, SearchAttributes, SearchAttributesSchema, StepCheckpoint, StepEvent, StepLogger, TenantTokenSource, TenantVerifier, VerifiedTenant, WorkflowCtx, WorkflowEngine, WorkflowHandler, WorkflowRun, hmacTenantVerifier, prevCronFireMs, readSearchAttributes, runSchedules, scheduleRunIdAt, scheduledRunId, signTenantToken } from '@dudousxd/nestjs-durable-core';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { ConcurrencyOption, StartRunDeps, RunRedisWorkerOptions, RunningWorker, DurableWorkerRuntime } from '@dudousxd/durable-worker';
|
|
5
5
|
import { DynamicModule, InjectionToken, OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown, Provider } from '@nestjs/common';
|
|
@@ -242,14 +242,16 @@ interface WorkflowOptions {
|
|
|
242
242
|
inputSchema?: IoSchema;
|
|
243
243
|
/**
|
|
244
244
|
* A custom check at `start` (throw to reject) for a rule a schema can't express — a cross-field
|
|
245
|
-
* invariant, an async lookup. It
|
|
245
|
+
* invariant, an async lookup. It runs after `input` parses and receives the parsed value (the input
|
|
246
|
+
* as sent when there is no `input` schema).
|
|
246
247
|
*/
|
|
247
248
|
validateInput?: (input: unknown) => void | Promise<void>;
|
|
248
249
|
/**
|
|
249
250
|
* Validate this workflow's {@link WorkflowCtx.upsertSearchAttributes} writes against a **Standard
|
|
250
251
|
* Schema** (https://standardschema.dev — zod 3.24+, valibot, arktype, …). `ctx.upsertSearchAttributes`
|
|
251
252
|
* validates the MERGED result (existing attributes shallow-merged with the patch) on every call —
|
|
252
|
-
* an invalid merge throws
|
|
253
|
+
* an invalid merge throws a `SchemaValidationError` (code `schema_validation`) naming this workflow,
|
|
254
|
+
* with the schema's issues. The
|
|
253
255
|
* schema's inferred output must be search-attribute-shaped (flat `string`/`number`/`boolean` values
|
|
254
256
|
* only) — a schema whose output has a nested object/array is a compile-time error here. Omit for
|
|
255
257
|
* the prior unvalidated behavior.
|
|
@@ -788,6 +790,26 @@ interface DurableModuleOptions {
|
|
|
788
790
|
/** Timeout for a thin worker's `RunGateway` round-trip over `transport` before it rejects. Defaults
|
|
789
791
|
* to 10_000ms inside `ProxyRunGateway`. Ignored for an operator (bound to `StoreRunGateway`). */
|
|
790
792
|
runGatewayTimeoutMs?: number;
|
|
793
|
+
/**
|
|
794
|
+
* **Operator.** Verifies the signed tenant token a store-less tenant worker presents in the wire
|
|
795
|
+
* `tenant` field of every run request and start-run message, and DERIVES the tenant from it,
|
|
796
|
+
* discarding the wire claim. An invalid, tampered or absent token is rejected: a run request gets
|
|
797
|
+
* an `unauthorized` error reply, a start-run creates nothing. Use `hmacTenantVerifier(secret)`
|
|
798
|
+
* (tokens minted by `signTenantToken`, wire-compatible with Agora) or supply your own.
|
|
799
|
+
*
|
|
800
|
+
* Optional. Absent: the wire `tenant` is trusted verbatim (prefix/network isolation only), exactly
|
|
801
|
+
* as before. An explicit `topology: { role: 'control-plane' }` without a verifier logs a warning
|
|
802
|
+
* at boot; a plain operator (`store` + `transport`, no `topology`) boots silently.
|
|
803
|
+
*/
|
|
804
|
+
verifyTenant?: TenantVerifier;
|
|
805
|
+
/**
|
|
806
|
+
* **Tenant worker.** The signed token (see `signTenantToken`) this worker presents, verbatim, in
|
|
807
|
+
* the `tenant` field of every run request (`ProxyRunGateway`) and start-run (`engine.start`), so
|
|
808
|
+
* an operator with {@link verifyTenant} can authenticate it. A string, or a function called before
|
|
809
|
+
* every request (rotation, short-lived tokens). Optional: absent, the raw {@link partition} is
|
|
810
|
+
* sent, as before. Live-tail stays keyed by the partition, never the token.
|
|
811
|
+
*/
|
|
812
|
+
tenantToken?: TenantTokenSource;
|
|
791
813
|
/**
|
|
792
814
|
* An explicit preset that NAMES the deployment role instead of leaving it to `store`/`connection`
|
|
793
815
|
* inference, and VALIDATES the axes that are otherwise only prose (see the interface doc's role
|
|
@@ -1089,13 +1111,29 @@ declare class ProxyRunGateway implements RunGateway {
|
|
|
1089
1111
|
private readonly tenant;
|
|
1090
1112
|
private readonly timeoutMs;
|
|
1091
1113
|
private readonly capabilityTtlMs;
|
|
1114
|
+
/**
|
|
1115
|
+
* The tenant's signed token (see `signTenantToken`), presented VERBATIM in the `tenant` field of
|
|
1116
|
+
* every {@link RunRequest} so an operator with `verifyTenant` can authenticate it and derive the
|
|
1117
|
+
* tenant from it. A function is called before every request (rotation / short-lived tokens).
|
|
1118
|
+
* Omit to send the raw `tenant` (prefix/network isolation only). The live-tail channel always
|
|
1119
|
+
* stays keyed by `tenant`, never the token: the operator republishes by the run's namespace.
|
|
1120
|
+
*/
|
|
1121
|
+
private readonly tenantToken?;
|
|
1092
1122
|
private readonly pending;
|
|
1093
1123
|
/** Verb → when to ask the control plane for it again, after it answered that it does not know it.
|
|
1094
1124
|
* During a rolling upgrade the control plane is several pods of mixed versions behind one queue,
|
|
1095
1125
|
* and a reply does not say which pod sent it, so the whole control plane is assumed old until the
|
|
1096
1126
|
* entry expires. */
|
|
1097
1127
|
private readonly unsupportedUntil;
|
|
1098
|
-
constructor(transport: Transport, tenant: string, timeoutMs?: number, capabilityTtlMs?: number
|
|
1128
|
+
constructor(transport: Transport, tenant: string, timeoutMs?: number, capabilityTtlMs?: number,
|
|
1129
|
+
/**
|
|
1130
|
+
* The tenant's signed token (see `signTenantToken`), presented VERBATIM in the `tenant` field of
|
|
1131
|
+
* every {@link RunRequest} so an operator with `verifyTenant` can authenticate it and derive the
|
|
1132
|
+
* tenant from it. A function is called before every request (rotation / short-lived tokens).
|
|
1133
|
+
* Omit to send the raw `tenant` (prefix/network isolation only). The live-tail channel always
|
|
1134
|
+
* stays keyed by `tenant`, never the token: the operator republishes by the run's namespace.
|
|
1135
|
+
*/
|
|
1136
|
+
tenantToken?: TenantTokenSource | undefined);
|
|
1099
1137
|
private handleReply;
|
|
1100
1138
|
private request;
|
|
1101
1139
|
topology(): DurableTopology;
|
|
@@ -1163,6 +1201,22 @@ interface RunRequestTransport {
|
|
|
1163
1201
|
onRunRequest(handler: (msg: RunRequest) => Promise<void>): void;
|
|
1164
1202
|
publishRunReply(reply: RunReply): Promise<void>;
|
|
1165
1203
|
}
|
|
1204
|
+
/** Options for {@link RunRequestResponder}. */
|
|
1205
|
+
interface RunRequestResponderOptions {
|
|
1206
|
+
/**
|
|
1207
|
+
* Verifies the signed token a tenant presents in the wire `tenant` field and DERIVES the real
|
|
1208
|
+
* tenant from it (see `hmacTenantVerifier`). Present: an invalid, tampered or absent token is
|
|
1209
|
+
* rejected with an `unauthorized` error reply and the wire claim is discarded in favour of the
|
|
1210
|
+
* verified tenant. Absent: the wire `tenant` is trusted verbatim (prefix/network isolation only).
|
|
1211
|
+
*/
|
|
1212
|
+
verifyTenant?: TenantVerifier | undefined;
|
|
1213
|
+
/**
|
|
1214
|
+
* Warn at construction when no {@link verifyTenant} is set. Default `true`. `DurableModule` passes
|
|
1215
|
+
* `true` only for an explicit `topology: { role: 'control-plane' }`, so a plain operator app that
|
|
1216
|
+
* never serves tenants boots silently.
|
|
1217
|
+
*/
|
|
1218
|
+
warnWithoutVerifier?: boolean | undefined;
|
|
1219
|
+
}
|
|
1166
1220
|
/**
|
|
1167
1221
|
* Operator-side consumer of a tenant's {@link RunRequest}s: answers each one against a
|
|
1168
1222
|
* `RunGateway`, enforcing the tenant boundary before touching the run. For every runId-bearing
|
|
@@ -1171,11 +1225,17 @@ interface RunRequestTransport {
|
|
|
1171
1225
|
* verb, so a tenant can never read or act on another tenant's run. `listRuns` is scoped by
|
|
1172
1226
|
* overwriting the query's `namespace` with the requester's tenant, ignoring whatever the client
|
|
1173
1227
|
* sent. This is the security boundary of the tenant run gateway — do not weaken it.
|
|
1228
|
+
*
|
|
1229
|
+
* With {@link RunRequestResponderOptions.verifyTenant}, every request is authenticated FIRST: the
|
|
1230
|
+
* wire `tenant` is treated as a signed token, the real tenant is derived from it, and an invalid
|
|
1231
|
+
* token short-circuits into an `unauthorized` error reply before any run is touched. A verifier
|
|
1232
|
+
* that throws becomes an error reply too.
|
|
1174
1233
|
*/
|
|
1175
1234
|
declare class RunRequestResponder {
|
|
1176
1235
|
private readonly transport;
|
|
1177
1236
|
private readonly gateway;
|
|
1178
|
-
|
|
1237
|
+
private readonly verifyTenant;
|
|
1238
|
+
constructor(transport: RunRequestTransport, gateway: RunGateway, options?: RunRequestResponderOptions);
|
|
1179
1239
|
/** Register the consumer on the transport. Each request is answered independently; a handler
|
|
1180
1240
|
* failure never throws back into the transport (errors are captured into an error reply). */
|
|
1181
1241
|
start(): void;
|
|
@@ -1373,4 +1433,4 @@ declare class WorkflowService {
|
|
|
1373
1433
|
}): Promise<number>;
|
|
1374
1434
|
}
|
|
1375
1435
|
|
|
1376
|
-
export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_RUNNERS, DURABLE_WORKER_RUNTIME, DeadLetter, type DtoClass, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStartClient, DurableStep, type DurableStepInterceptor, type DurableStepMeta, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, type ErrorClassWithCode, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, type IoSchema, ON_ERROR_METADATA, ON_EVENT_METADATA, On, OnDurableEvent, OnError, type OnErrorMethod, OnEvent, ProxyRunGateway, RUN_GATEWAY, RUN_REDIS_WORKER, type RunLookupStore, type RunRedisWorkerFn, RunRequestResponder, type RunRequestTransport, STEP_INTERCEPTOR_METADATA, Step, StepInterceptor, type StepOptions, StoreRunGateway, TenantEventRepublisher, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, UNSUPPORTED_RUN_REQUEST, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowAttributesOf, type WorkflowMeta, type WorkflowOptions, WorkflowService, attributesOf, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isDrivingOperator, isOperatorRole, isStepInterceptor, onErrorCodesOf, thinWorkerProviders, unavailableRunGateway };
|
|
1436
|
+
export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_RUNNERS, DURABLE_WORKER_RUNTIME, DeadLetter, type DtoClass, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStartClient, DurableStep, type DurableStepInterceptor, type DurableStepMeta, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, type ErrorClassWithCode, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, type IoSchema, ON_ERROR_METADATA, ON_EVENT_METADATA, On, OnDurableEvent, OnError, type OnErrorMethod, OnEvent, ProxyRunGateway, RUN_GATEWAY, RUN_REDIS_WORKER, type RunLookupStore, type RunRedisWorkerFn, RunRequestResponder, type RunRequestResponderOptions, type RunRequestTransport, STEP_INTERCEPTOR_METADATA, Step, StepInterceptor, type StepOptions, StoreRunGateway, TenantEventRepublisher, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, UNSUPPORTED_RUN_REQUEST, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowAttributesOf, type WorkflowMeta, type WorkflowOptions, WorkflowService, attributesOf, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isDrivingOperator, isOperatorRole, isStepInterceptor, onErrorCodesOf, thinWorkerProviders, unavailableRunGateway };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { WorkflowCtx, SearchAttributes, WorkflowClass, StandardSchemaV1, StepError, OnErrorInput, WorkflowRef, SingletonConfig, ConcurrencyConfig, SearchAttributesSchema, StateStore, Transport, NamedTransport, ControlPlane, StalledRunInfo, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowInputOf, StartOptions, RunResult, RunGateway, WorkflowEngine, EntityHandler, DurableTopology, RunDetailOptions, RunDetail, FanPageQuery, FanPage, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, GroupHealth, RunWaiting, EngineEvent, RunRequest, RunReply, StepInvocation, WorkflowRun, TenantEvent } from '@dudousxd/nestjs-durable-core';
|
|
2
|
-
export { AttributeFilter, DynamicWorkflowCtx, EngineEvent, InferSearchAttributes, OnErrorInput, RunDetail, RunGateway, RunListItem, RunQuery, RunStatus, RunWaiting, SearchAttributes, SearchAttributesSchema, StepCheckpoint, StepEvent, StepLogger, WorkflowCtx, WorkflowEngine, WorkflowHandler, WorkflowRun, readSearchAttributes } from '@dudousxd/nestjs-durable-core';
|
|
1
|
+
import { WorkflowCtx, SearchAttributes, WorkflowClass, StandardSchemaV1, StepError, OnErrorInput, WorkflowRef, SingletonConfig, ConcurrencyConfig, SearchAttributesSchema, StateStore, Transport, NamedTransport, ControlPlane, StalledRunInfo, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, TenantVerifier, TenantTokenSource, WorkflowInputOf, StartOptions, RunResult, RunGateway, WorkflowEngine, EntityHandler, DurableTopology, RunDetailOptions, RunDetail, FanPageQuery, FanPage, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, GroupHealth, RunWaiting, EngineEvent, RunRequest, RunReply, StepInvocation, WorkflowRun, TenantEvent } from '@dudousxd/nestjs-durable-core';
|
|
2
|
+
export { AttributeFilter, DynamicWorkflowCtx, EngineEvent, InferSearchAttributes, OnErrorInput, RunDetail, RunGateway, RunListItem, RunQuery, RunSchedulesOptions, RunStatus, RunWaiting, ScheduledWorkflow, SearchAttributes, SearchAttributesSchema, StepCheckpoint, StepEvent, StepLogger, TenantTokenSource, TenantVerifier, VerifiedTenant, WorkflowCtx, WorkflowEngine, WorkflowHandler, WorkflowRun, hmacTenantVerifier, prevCronFireMs, readSearchAttributes, runSchedules, scheduleRunIdAt, scheduledRunId, signTenantToken } from '@dudousxd/nestjs-durable-core';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { ConcurrencyOption, StartRunDeps, RunRedisWorkerOptions, RunningWorker, DurableWorkerRuntime } from '@dudousxd/durable-worker';
|
|
5
5
|
import { DynamicModule, InjectionToken, OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown, Provider } from '@nestjs/common';
|
|
@@ -242,14 +242,16 @@ interface WorkflowOptions {
|
|
|
242
242
|
inputSchema?: IoSchema;
|
|
243
243
|
/**
|
|
244
244
|
* A custom check at `start` (throw to reject) for a rule a schema can't express — a cross-field
|
|
245
|
-
* invariant, an async lookup. It
|
|
245
|
+
* invariant, an async lookup. It runs after `input` parses and receives the parsed value (the input
|
|
246
|
+
* as sent when there is no `input` schema).
|
|
246
247
|
*/
|
|
247
248
|
validateInput?: (input: unknown) => void | Promise<void>;
|
|
248
249
|
/**
|
|
249
250
|
* Validate this workflow's {@link WorkflowCtx.upsertSearchAttributes} writes against a **Standard
|
|
250
251
|
* Schema** (https://standardschema.dev — zod 3.24+, valibot, arktype, …). `ctx.upsertSearchAttributes`
|
|
251
252
|
* validates the MERGED result (existing attributes shallow-merged with the patch) on every call —
|
|
252
|
-
* an invalid merge throws
|
|
253
|
+
* an invalid merge throws a `SchemaValidationError` (code `schema_validation`) naming this workflow,
|
|
254
|
+
* with the schema's issues. The
|
|
253
255
|
* schema's inferred output must be search-attribute-shaped (flat `string`/`number`/`boolean` values
|
|
254
256
|
* only) — a schema whose output has a nested object/array is a compile-time error here. Omit for
|
|
255
257
|
* the prior unvalidated behavior.
|
|
@@ -788,6 +790,26 @@ interface DurableModuleOptions {
|
|
|
788
790
|
/** Timeout for a thin worker's `RunGateway` round-trip over `transport` before it rejects. Defaults
|
|
789
791
|
* to 10_000ms inside `ProxyRunGateway`. Ignored for an operator (bound to `StoreRunGateway`). */
|
|
790
792
|
runGatewayTimeoutMs?: number;
|
|
793
|
+
/**
|
|
794
|
+
* **Operator.** Verifies the signed tenant token a store-less tenant worker presents in the wire
|
|
795
|
+
* `tenant` field of every run request and start-run message, and DERIVES the tenant from it,
|
|
796
|
+
* discarding the wire claim. An invalid, tampered or absent token is rejected: a run request gets
|
|
797
|
+
* an `unauthorized` error reply, a start-run creates nothing. Use `hmacTenantVerifier(secret)`
|
|
798
|
+
* (tokens minted by `signTenantToken`, wire-compatible with Agora) or supply your own.
|
|
799
|
+
*
|
|
800
|
+
* Optional. Absent: the wire `tenant` is trusted verbatim (prefix/network isolation only), exactly
|
|
801
|
+
* as before. An explicit `topology: { role: 'control-plane' }` without a verifier logs a warning
|
|
802
|
+
* at boot; a plain operator (`store` + `transport`, no `topology`) boots silently.
|
|
803
|
+
*/
|
|
804
|
+
verifyTenant?: TenantVerifier;
|
|
805
|
+
/**
|
|
806
|
+
* **Tenant worker.** The signed token (see `signTenantToken`) this worker presents, verbatim, in
|
|
807
|
+
* the `tenant` field of every run request (`ProxyRunGateway`) and start-run (`engine.start`), so
|
|
808
|
+
* an operator with {@link verifyTenant} can authenticate it. A string, or a function called before
|
|
809
|
+
* every request (rotation, short-lived tokens). Optional: absent, the raw {@link partition} is
|
|
810
|
+
* sent, as before. Live-tail stays keyed by the partition, never the token.
|
|
811
|
+
*/
|
|
812
|
+
tenantToken?: TenantTokenSource;
|
|
791
813
|
/**
|
|
792
814
|
* An explicit preset that NAMES the deployment role instead of leaving it to `store`/`connection`
|
|
793
815
|
* inference, and VALIDATES the axes that are otherwise only prose (see the interface doc's role
|
|
@@ -1089,13 +1111,29 @@ declare class ProxyRunGateway implements RunGateway {
|
|
|
1089
1111
|
private readonly tenant;
|
|
1090
1112
|
private readonly timeoutMs;
|
|
1091
1113
|
private readonly capabilityTtlMs;
|
|
1114
|
+
/**
|
|
1115
|
+
* The tenant's signed token (see `signTenantToken`), presented VERBATIM in the `tenant` field of
|
|
1116
|
+
* every {@link RunRequest} so an operator with `verifyTenant` can authenticate it and derive the
|
|
1117
|
+
* tenant from it. A function is called before every request (rotation / short-lived tokens).
|
|
1118
|
+
* Omit to send the raw `tenant` (prefix/network isolation only). The live-tail channel always
|
|
1119
|
+
* stays keyed by `tenant`, never the token: the operator republishes by the run's namespace.
|
|
1120
|
+
*/
|
|
1121
|
+
private readonly tenantToken?;
|
|
1092
1122
|
private readonly pending;
|
|
1093
1123
|
/** Verb → when to ask the control plane for it again, after it answered that it does not know it.
|
|
1094
1124
|
* During a rolling upgrade the control plane is several pods of mixed versions behind one queue,
|
|
1095
1125
|
* and a reply does not say which pod sent it, so the whole control plane is assumed old until the
|
|
1096
1126
|
* entry expires. */
|
|
1097
1127
|
private readonly unsupportedUntil;
|
|
1098
|
-
constructor(transport: Transport, tenant: string, timeoutMs?: number, capabilityTtlMs?: number
|
|
1128
|
+
constructor(transport: Transport, tenant: string, timeoutMs?: number, capabilityTtlMs?: number,
|
|
1129
|
+
/**
|
|
1130
|
+
* The tenant's signed token (see `signTenantToken`), presented VERBATIM in the `tenant` field of
|
|
1131
|
+
* every {@link RunRequest} so an operator with `verifyTenant` can authenticate it and derive the
|
|
1132
|
+
* tenant from it. A function is called before every request (rotation / short-lived tokens).
|
|
1133
|
+
* Omit to send the raw `tenant` (prefix/network isolation only). The live-tail channel always
|
|
1134
|
+
* stays keyed by `tenant`, never the token: the operator republishes by the run's namespace.
|
|
1135
|
+
*/
|
|
1136
|
+
tenantToken?: TenantTokenSource | undefined);
|
|
1099
1137
|
private handleReply;
|
|
1100
1138
|
private request;
|
|
1101
1139
|
topology(): DurableTopology;
|
|
@@ -1163,6 +1201,22 @@ interface RunRequestTransport {
|
|
|
1163
1201
|
onRunRequest(handler: (msg: RunRequest) => Promise<void>): void;
|
|
1164
1202
|
publishRunReply(reply: RunReply): Promise<void>;
|
|
1165
1203
|
}
|
|
1204
|
+
/** Options for {@link RunRequestResponder}. */
|
|
1205
|
+
interface RunRequestResponderOptions {
|
|
1206
|
+
/**
|
|
1207
|
+
* Verifies the signed token a tenant presents in the wire `tenant` field and DERIVES the real
|
|
1208
|
+
* tenant from it (see `hmacTenantVerifier`). Present: an invalid, tampered or absent token is
|
|
1209
|
+
* rejected with an `unauthorized` error reply and the wire claim is discarded in favour of the
|
|
1210
|
+
* verified tenant. Absent: the wire `tenant` is trusted verbatim (prefix/network isolation only).
|
|
1211
|
+
*/
|
|
1212
|
+
verifyTenant?: TenantVerifier | undefined;
|
|
1213
|
+
/**
|
|
1214
|
+
* Warn at construction when no {@link verifyTenant} is set. Default `true`. `DurableModule` passes
|
|
1215
|
+
* `true` only for an explicit `topology: { role: 'control-plane' }`, so a plain operator app that
|
|
1216
|
+
* never serves tenants boots silently.
|
|
1217
|
+
*/
|
|
1218
|
+
warnWithoutVerifier?: boolean | undefined;
|
|
1219
|
+
}
|
|
1166
1220
|
/**
|
|
1167
1221
|
* Operator-side consumer of a tenant's {@link RunRequest}s: answers each one against a
|
|
1168
1222
|
* `RunGateway`, enforcing the tenant boundary before touching the run. For every runId-bearing
|
|
@@ -1171,11 +1225,17 @@ interface RunRequestTransport {
|
|
|
1171
1225
|
* verb, so a tenant can never read or act on another tenant's run. `listRuns` is scoped by
|
|
1172
1226
|
* overwriting the query's `namespace` with the requester's tenant, ignoring whatever the client
|
|
1173
1227
|
* sent. This is the security boundary of the tenant run gateway — do not weaken it.
|
|
1228
|
+
*
|
|
1229
|
+
* With {@link RunRequestResponderOptions.verifyTenant}, every request is authenticated FIRST: the
|
|
1230
|
+
* wire `tenant` is treated as a signed token, the real tenant is derived from it, and an invalid
|
|
1231
|
+
* token short-circuits into an `unauthorized` error reply before any run is touched. A verifier
|
|
1232
|
+
* that throws becomes an error reply too.
|
|
1174
1233
|
*/
|
|
1175
1234
|
declare class RunRequestResponder {
|
|
1176
1235
|
private readonly transport;
|
|
1177
1236
|
private readonly gateway;
|
|
1178
|
-
|
|
1237
|
+
private readonly verifyTenant;
|
|
1238
|
+
constructor(transport: RunRequestTransport, gateway: RunGateway, options?: RunRequestResponderOptions);
|
|
1179
1239
|
/** Register the consumer on the transport. Each request is answered independently; a handler
|
|
1180
1240
|
* failure never throws back into the transport (errors are captured into an error reply). */
|
|
1181
1241
|
start(): void;
|
|
@@ -1373,4 +1433,4 @@ declare class WorkflowService {
|
|
|
1373
1433
|
}): Promise<number>;
|
|
1374
1434
|
}
|
|
1375
1435
|
|
|
1376
|
-
export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_RUNNERS, DURABLE_WORKER_RUNTIME, DeadLetter, type DtoClass, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStartClient, DurableStep, type DurableStepInterceptor, type DurableStepMeta, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, type ErrorClassWithCode, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, type IoSchema, ON_ERROR_METADATA, ON_EVENT_METADATA, On, OnDurableEvent, OnError, type OnErrorMethod, OnEvent, ProxyRunGateway, RUN_GATEWAY, RUN_REDIS_WORKER, type RunLookupStore, type RunRedisWorkerFn, RunRequestResponder, type RunRequestTransport, STEP_INTERCEPTOR_METADATA, Step, StepInterceptor, type StepOptions, StoreRunGateway, TenantEventRepublisher, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, UNSUPPORTED_RUN_REQUEST, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowAttributesOf, type WorkflowMeta, type WorkflowOptions, WorkflowService, attributesOf, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isDrivingOperator, isOperatorRole, isStepInterceptor, onErrorCodesOf, thinWorkerProviders, unavailableRunGateway };
|
|
1436
|
+
export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_RUNNERS, DURABLE_WORKER_RUNTIME, DeadLetter, type DtoClass, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStartClient, DurableStep, type DurableStepInterceptor, type DurableStepMeta, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, type ErrorClassWithCode, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, type IoSchema, ON_ERROR_METADATA, ON_EVENT_METADATA, On, OnDurableEvent, OnError, type OnErrorMethod, OnEvent, ProxyRunGateway, RUN_GATEWAY, RUN_REDIS_WORKER, type RunLookupStore, type RunRedisWorkerFn, RunRequestResponder, type RunRequestResponderOptions, type RunRequestTransport, STEP_INTERCEPTOR_METADATA, Step, StepInterceptor, type StepOptions, StoreRunGateway, TenantEventRepublisher, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, UNSUPPORTED_RUN_REQUEST, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowAttributesOf, type WorkflowMeta, type WorkflowOptions, WorkflowService, attributesOf, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isDrivingOperator, isOperatorRole, isStepInterceptor, onErrorCodesOf, thinWorkerProviders, unavailableRunGateway };
|
package/dist/index.js
CHANGED
|
@@ -264,7 +264,7 @@ function attributesOf(workflow, run) {
|
|
|
264
264
|
__name(attributesOf, "attributesOf");
|
|
265
265
|
|
|
266
266
|
// src/durable-start-client.ts
|
|
267
|
-
import { workflowName } from "@dudousxd/nestjs-durable-core";
|
|
267
|
+
import { resolveTenantToken, workflowName } from "@dudousxd/nestjs-durable-core";
|
|
268
268
|
import { Injectable } from "@nestjs/common";
|
|
269
269
|
|
|
270
270
|
// src/worker-sdk.ts
|
|
@@ -322,7 +322,9 @@ var DurableStartClient = class {
|
|
|
322
322
|
async start(workflow, input, runId = globalThis.crypto.randomUUID(), opts) {
|
|
323
323
|
const name = workflowName(workflow);
|
|
324
324
|
await startRun(this.options.connection, {
|
|
325
|
-
tenant
|
|
325
|
+
// The signed token (when configured) rides in the `tenant` field, as on every run request; an
|
|
326
|
+
// operator with `verifyTenant` derives the run's namespace from it.
|
|
327
|
+
tenant: this.options.tenantToken !== void 0 ? await resolveTenantToken(this.options.tenantToken) : this.tenant,
|
|
326
328
|
workflow: name,
|
|
327
329
|
input,
|
|
328
330
|
runId,
|
|
@@ -393,34 +395,20 @@ import { Inject, Injectable as Injectable2 } from "@nestjs/common";
|
|
|
393
395
|
import { DiscoveryService, MetadataScanner } from "@nestjs/core";
|
|
394
396
|
|
|
395
397
|
// src/schema-parse.ts
|
|
396
|
-
import {
|
|
398
|
+
import { SchemaValidationError } from "@dudousxd/nestjs-durable-core";
|
|
397
399
|
function schemaParser(schema, kind, label) {
|
|
398
400
|
const code = kind === "input" ? "invalid_input" : "invalid_output";
|
|
399
401
|
if (isStandardSchema(schema)) {
|
|
400
402
|
return async (value) => {
|
|
401
403
|
const result = await schema["~standard"].validate(value);
|
|
402
|
-
if (result.issues)
|
|
403
|
-
const issues = result.issues.map((i) => ({
|
|
404
|
-
message: i.message,
|
|
405
|
-
...i.path ? {
|
|
406
|
-
path: i.path.map((p) => String(typeof p === "object" ? p.key : p))
|
|
407
|
-
} : {}
|
|
408
|
-
}));
|
|
409
|
-
throw new FatalError(`invalid ${label}: ${formatIssues(issues)}`, code, issues);
|
|
410
|
-
}
|
|
404
|
+
if (result.issues) throw new SchemaValidationError(label, result.issues, code);
|
|
411
405
|
return result.value;
|
|
412
406
|
};
|
|
413
407
|
}
|
|
414
408
|
if (isZodLike(schema)) {
|
|
415
409
|
return async (value) => {
|
|
416
410
|
const result = schema.safeParse(value);
|
|
417
|
-
if (!result.success)
|
|
418
|
-
const issues = result.error.issues.map((i) => ({
|
|
419
|
-
message: i.message,
|
|
420
|
-
path: i.path.map(String)
|
|
421
|
-
}));
|
|
422
|
-
throw new FatalError(`invalid ${label}: ${formatIssues(issues)}`, code, issues);
|
|
423
|
-
}
|
|
411
|
+
if (!result.success) throw new SchemaValidationError(label, result.error.issues, code);
|
|
424
412
|
return result.data;
|
|
425
413
|
};
|
|
426
414
|
}
|
|
@@ -440,12 +428,11 @@ function classValidatorParser(cls, code, label) {
|
|
|
440
428
|
}
|
|
441
429
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
442
430
|
const got = value === null ? "null" : Array.isArray(value) ? "an array" : typeof value;
|
|
443
|
-
|
|
444
|
-
throw new FatalError(`invalid ${label}: ${message}`, code, [
|
|
431
|
+
throw new SchemaValidationError(label, [
|
|
445
432
|
{
|
|
446
|
-
message
|
|
433
|
+
message: `expected an object, got ${got}`
|
|
447
434
|
}
|
|
448
|
-
]);
|
|
435
|
+
], code);
|
|
449
436
|
}
|
|
450
437
|
const instance = ct.plainToInstance(cls, value);
|
|
451
438
|
const errors = await cv.validate(instance, {
|
|
@@ -460,8 +447,8 @@ function classValidatorParser(cls, code, label) {
|
|
|
460
447
|
String(e.property)
|
|
461
448
|
]
|
|
462
449
|
}));
|
|
463
|
-
const
|
|
464
|
-
throw new
|
|
450
|
+
const summary = issues.map((i) => i.message).join("; ");
|
|
451
|
+
throw new SchemaValidationError(label, issues, code, summary);
|
|
465
452
|
}
|
|
466
453
|
return instance;
|
|
467
454
|
};
|
|
@@ -475,10 +462,6 @@ function isZodLike(schema) {
|
|
|
475
462
|
return typeof schema === "object" && schema !== null && typeof schema.safeParse === "function";
|
|
476
463
|
}
|
|
477
464
|
__name(isZodLike, "isZodLike");
|
|
478
|
-
function formatIssues(issues) {
|
|
479
|
-
return issues.map((i) => i.path && i.path.length > 0 ? `${i.path.join(".")}: ${i.message}` : i.message).join("; ");
|
|
480
|
-
}
|
|
481
|
-
__name(formatIssues, "formatIssues");
|
|
482
465
|
|
|
483
466
|
// src/discovery-helpers.ts
|
|
484
467
|
function scanWorkflows(discovery, register) {
|
|
@@ -558,8 +541,8 @@ function workflowIo(meta) {
|
|
|
558
541
|
const validateInput = meta.validateInput;
|
|
559
542
|
return {
|
|
560
543
|
validateAtStart: parseInput || validateInput ? async (input) => {
|
|
561
|
-
|
|
562
|
-
await validateInput?.(
|
|
544
|
+
const parsed = parseInput ? await parseInput(input) : input;
|
|
545
|
+
await validateInput?.(parsed);
|
|
563
546
|
} : void 0,
|
|
564
547
|
wrap: /* @__PURE__ */ __name((body) => !parseInput && !parseOutput ? body : async (ctx, input) => {
|
|
565
548
|
const output = await body(ctx, parseInput ? await parseInput(input) : input);
|
|
@@ -1178,10 +1161,11 @@ function inAppWorkerProviders() {
|
|
|
1178
1161
|
__name(inAppWorkerProviders, "inAppWorkerProviders");
|
|
1179
1162
|
|
|
1180
1163
|
// src/proxy-run-gateway.ts
|
|
1181
|
-
import { SUMMARY_CHILD_LIMIT, childIdsOf, pageFan, summarizeTimeline } from "@dudousxd/nestjs-durable-core";
|
|
1164
|
+
import { SUMMARY_CHILD_LIMIT, childIdsOf, pageFan, resolveTenantToken as resolveTenantToken2, summarizeTimeline } from "@dudousxd/nestjs-durable-core";
|
|
1182
1165
|
import { Injectable as Injectable6 } from "@nestjs/common";
|
|
1183
1166
|
|
|
1184
1167
|
// src/run-request-responder.ts
|
|
1168
|
+
import { resolveWireTenant } from "@dudousxd/nestjs-durable-core";
|
|
1185
1169
|
var UNSUPPORTED_RUN_REQUEST = "unsupported-request";
|
|
1186
1170
|
var KNOWN_KINDS = /* @__PURE__ */ new Set([
|
|
1187
1171
|
"getRunDetail",
|
|
@@ -1203,9 +1187,14 @@ var RunRequestResponder = class {
|
|
|
1203
1187
|
}
|
|
1204
1188
|
transport;
|
|
1205
1189
|
gateway;
|
|
1206
|
-
|
|
1190
|
+
verifyTenant;
|
|
1191
|
+
constructor(transport, gateway, options = {}) {
|
|
1207
1192
|
this.transport = transport;
|
|
1208
1193
|
this.gateway = gateway;
|
|
1194
|
+
this.verifyTenant = options.verifyTenant;
|
|
1195
|
+
if (!this.verifyTenant && options.warnWithoutVerifier !== false) {
|
|
1196
|
+
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.");
|
|
1197
|
+
}
|
|
1209
1198
|
}
|
|
1210
1199
|
/** Register the consumer on the transport. Each request is answered independently; a handler
|
|
1211
1200
|
* failure never throws back into the transport (errors are captured into an error reply). */
|
|
@@ -1228,7 +1217,24 @@ var RunRequestResponder = class {
|
|
|
1228
1217
|
await this.transport.publishRunReply(reply);
|
|
1229
1218
|
});
|
|
1230
1219
|
}
|
|
1231
|
-
async handle(
|
|
1220
|
+
async handle(wire) {
|
|
1221
|
+
const tenant = await resolveWireTenant(wire.tenant, this.verifyTenant);
|
|
1222
|
+
if (tenant === null) {
|
|
1223
|
+
return {
|
|
1224
|
+
requestId: wire.requestId,
|
|
1225
|
+
result: {
|
|
1226
|
+
ok: false,
|
|
1227
|
+
error: {
|
|
1228
|
+
message: "invalid or unauthorized tenant token",
|
|
1229
|
+
code: "unauthorized"
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
const msg = {
|
|
1235
|
+
...wire,
|
|
1236
|
+
tenant
|
|
1237
|
+
};
|
|
1232
1238
|
const { body } = msg;
|
|
1233
1239
|
if (!KNOWN_KINDS.has(body.kind)) {
|
|
1234
1240
|
return {
|
|
@@ -1421,17 +1427,19 @@ var ProxyRunGateway = class {
|
|
|
1421
1427
|
tenant;
|
|
1422
1428
|
timeoutMs;
|
|
1423
1429
|
capabilityTtlMs;
|
|
1430
|
+
tenantToken;
|
|
1424
1431
|
pending = /* @__PURE__ */ new Map();
|
|
1425
1432
|
/** Verb → when to ask the control plane for it again, after it answered that it does not know it.
|
|
1426
1433
|
* During a rolling upgrade the control plane is several pods of mixed versions behind one queue,
|
|
1427
1434
|
* and a reply does not say which pod sent it, so the whole control plane is assumed old until the
|
|
1428
1435
|
* entry expires. */
|
|
1429
1436
|
unsupportedUntil = /* @__PURE__ */ new Map();
|
|
1430
|
-
constructor(transport, tenant, timeoutMs = 1e4, capabilityTtlMs = 6e4) {
|
|
1437
|
+
constructor(transport, tenant, timeoutMs = 1e4, capabilityTtlMs = 6e4, tenantToken) {
|
|
1431
1438
|
this.transport = transport;
|
|
1432
1439
|
this.tenant = tenant;
|
|
1433
1440
|
this.timeoutMs = timeoutMs;
|
|
1434
1441
|
this.capabilityTtlMs = capabilityTtlMs;
|
|
1442
|
+
this.tenantToken = tenantToken;
|
|
1435
1443
|
this.transport.onRunReply?.((reply) => this.handleReply(reply));
|
|
1436
1444
|
}
|
|
1437
1445
|
handleReply(reply) {
|
|
@@ -1444,7 +1452,10 @@ var ProxyRunGateway = class {
|
|
|
1444
1452
|
} else if (reply.result.error.code === UNSUPPORTED_RUN_REQUEST) {
|
|
1445
1453
|
pending.reject(new UnsupportedRunRequestError(reply.result.error.message));
|
|
1446
1454
|
} else {
|
|
1447
|
-
|
|
1455
|
+
const { message, code } = reply.result.error;
|
|
1456
|
+
pending.reject(code !== void 0 ? Object.assign(new Error(message), {
|
|
1457
|
+
code
|
|
1458
|
+
}) : new Error(message));
|
|
1448
1459
|
}
|
|
1449
1460
|
}
|
|
1450
1461
|
request(body) {
|
|
@@ -1459,11 +1470,17 @@ var ProxyRunGateway = class {
|
|
|
1459
1470
|
reject,
|
|
1460
1471
|
timer
|
|
1461
1472
|
});
|
|
1462
|
-
this.
|
|
1473
|
+
const source = this.tenantToken;
|
|
1474
|
+
const dispatched = typeof source === "function" ? resolveTenantToken2(source).then((tenant) => this.transport.dispatchRunRequest?.({
|
|
1463
1475
|
requestId,
|
|
1464
|
-
tenant
|
|
1476
|
+
tenant,
|
|
1465
1477
|
body
|
|
1466
|
-
})
|
|
1478
|
+
})) : this.transport.dispatchRunRequest?.({
|
|
1479
|
+
requestId,
|
|
1480
|
+
tenant: source ?? this.tenant,
|
|
1481
|
+
body
|
|
1482
|
+
});
|
|
1483
|
+
dispatched?.catch((error) => {
|
|
1467
1484
|
const stillPending = this.pending.get(requestId);
|
|
1468
1485
|
if (!stillPending) return;
|
|
1469
1486
|
clearTimeout(stillPending.timer);
|
|
@@ -1621,7 +1638,8 @@ ProxyRunGateway = _ts_decorate6([
|
|
|
1621
1638
|
typeof Transport === "undefined" ? Object : Transport,
|
|
1622
1639
|
String,
|
|
1623
1640
|
void 0,
|
|
1624
|
-
void 0
|
|
1641
|
+
void 0,
|
|
1642
|
+
typeof TenantTokenSource === "undefined" ? Object : TenantTokenSource
|
|
1625
1643
|
])
|
|
1626
1644
|
], ProxyRunGateway);
|
|
1627
1645
|
|
|
@@ -2076,7 +2094,7 @@ var TenantEventRepublisher = class {
|
|
|
2076
2094
|
};
|
|
2077
2095
|
|
|
2078
2096
|
// src/timer-poller.ts
|
|
2079
|
-
import { DURABLE_OPTIONS_CANONICAL as DURABLE_OPTIONS_CANONICAL5, WorkflowEngine as WorkflowEngine3, runSchedules } from "@dudousxd/nestjs-durable-core";
|
|
2097
|
+
import { DURABLE_OPTIONS_CANONICAL as DURABLE_OPTIONS_CANONICAL5, WorkflowEngine as WorkflowEngine3, runSchedules, workflowName as workflowName3 } from "@dudousxd/nestjs-durable-core";
|
|
2080
2098
|
import { Inject as Inject6, Injectable as Injectable9 } from "@nestjs/common";
|
|
2081
2099
|
function _ts_decorate9(decorators, target, key, desc) {
|
|
2082
2100
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -2120,6 +2138,7 @@ var TimerPoller = class {
|
|
|
2120
2138
|
this.options = options;
|
|
2121
2139
|
}
|
|
2122
2140
|
async onApplicationBootstrap() {
|
|
2141
|
+
for (const s of this.options.schedules ?? []) workflowName3(s.workflow);
|
|
2123
2142
|
if (!isDrivingOperator(this.options)) return;
|
|
2124
2143
|
this.unsubscribeEnqueued = this.engine.onEnqueued((runId) => {
|
|
2125
2144
|
void this.engine.runOne(runId).catch((error) => {
|
|
@@ -2221,7 +2240,7 @@ var CONTEXT_ACCESSOR = Symbol.for("@dudousxd/nestjs-context:accessor");
|
|
|
2221
2240
|
var RUN_GATEWAY = RunGateway;
|
|
2222
2241
|
|
|
2223
2242
|
// src/workflow.registrar.ts
|
|
2224
|
-
import { DURABLE_OPTIONS_CANONICAL as DURABLE_OPTIONS_CANONICAL6, RemoteWorkflowExecutor, STATE_STORE_CANONICAL as STATE_STORE_CANONICAL3, WorkflowEngine as WorkflowEngine4, bindWorkflowClass, parseDuration as parseDuration2, sanitizeQueueToken, tenantGroup, workflowName as
|
|
2243
|
+
import { DURABLE_OPTIONS_CANONICAL as DURABLE_OPTIONS_CANONICAL6, RemoteWorkflowExecutor, STATE_STORE_CANONICAL as STATE_STORE_CANONICAL3, WorkflowEngine as WorkflowEngine4, bindWorkflowClass, parseDuration as parseDuration2, sanitizeQueueToken, tenantGroup, workflowName as workflowName4 } from "@dudousxd/nestjs-durable-core";
|
|
2225
2244
|
import { Inject as Inject7, Injectable as Injectable10 } from "@nestjs/common";
|
|
2226
2245
|
import { DiscoveryService as DiscoveryService4, MetadataScanner as MetadataScanner4 } from "@nestjs/core";
|
|
2227
2246
|
|
|
@@ -2388,7 +2407,7 @@ var WorkflowRegistrar = class {
|
|
|
2388
2407
|
});
|
|
2389
2408
|
deadLetterByWorkflow.set(meta.name, dlqName);
|
|
2390
2409
|
} else if (meta.deadLetterWorkflow) {
|
|
2391
|
-
deadLetterByWorkflow.set(meta.name,
|
|
2410
|
+
deadLetterByWorkflow.set(meta.name, workflowName4(meta.deadLetterWorkflow));
|
|
2392
2411
|
}
|
|
2393
2412
|
});
|
|
2394
2413
|
this.reportUnattributed(unattributed);
|
|
@@ -2436,7 +2455,7 @@ var WorkflowRegistrar = class {
|
|
|
2436
2455
|
* a `dlq:<runId>` id, so re-recovery never double-dispatches.
|
|
2437
2456
|
*/
|
|
2438
2457
|
installDeadLetterRouting(byWorkflow) {
|
|
2439
|
-
const fallback = this.options.deadLetterWorkflow ?
|
|
2458
|
+
const fallback = this.options.deadLetterWorkflow ? workflowName4(this.options.deadLetterWorkflow) : void 0;
|
|
2440
2459
|
if (byWorkflow.size === 0 && !fallback) return;
|
|
2441
2460
|
this.engine.onDead((run) => {
|
|
2442
2461
|
const target = byWorkflow.get(run.workflow) ?? fallback;
|
|
@@ -2745,7 +2764,15 @@ var RunGatewayBootstrap = class RunGatewayBootstrap2 {
|
|
|
2745
2764
|
onRunRequest: onRunRequest.bind(this.transport),
|
|
2746
2765
|
publishRunReply: publishRunReply.bind(this.transport)
|
|
2747
2766
|
};
|
|
2748
|
-
new RunRequestResponder(runRequestTransport, this.gateway
|
|
2767
|
+
new RunRequestResponder(runRequestTransport, this.gateway, {
|
|
2768
|
+
verifyTenant: this.options.verifyTenant,
|
|
2769
|
+
// Mirrors Agora's rule (`warnWithoutVerifier: role === 'control-plane'`): only a deployment
|
|
2770
|
+
// that EXPLICITLY names itself the control plane is told it runs without tenant auth. A plain
|
|
2771
|
+
// operator (role inferred from `store`) is Agora's `standalone`: anyone with broker access
|
|
2772
|
+
// can already enqueue steps and results there, so the warning would be noise on every boot
|
|
2773
|
+
// of an app that never serves tenants.
|
|
2774
|
+
warnWithoutVerifier: this.options.topology?.role === "control-plane"
|
|
2775
|
+
}).start();
|
|
2749
2776
|
}
|
|
2750
2777
|
if (typeof publishTenantEvent === "function") {
|
|
2751
2778
|
const republisher = new TenantEventRepublisher(store, publishTenantEvent.bind(this.transport));
|
|
@@ -2897,6 +2924,7 @@ var DurableModule = class _DurableModule {
|
|
|
2897
2924
|
context,
|
|
2898
2925
|
rehydrate: rehydrate || void 0,
|
|
2899
2926
|
compensationRetries: options.compensationRetries,
|
|
2927
|
+
verifyTenant: options.verifyTenant,
|
|
2900
2928
|
// A non-driving (dashboard/API) operator must not run workflows: enqueue-only, leaving
|
|
2901
2929
|
// each `pending` run in the store for a DRIVING instance's poll. A driving operator gets
|
|
2902
2930
|
// the engine's default in-process dispatcher: for a body registered inline, it runs
|
|
@@ -2937,7 +2965,7 @@ var DurableModule = class _DurableModule {
|
|
|
2937
2965
|
}
|
|
2938
2966
|
return new StoreRunGateway(store, engine);
|
|
2939
2967
|
}
|
|
2940
|
-
return options.transport ? new ProxyRunGateway(options.transport, options.partition ?? "default", options.runGatewayTimeoutMs) : unavailableRunGateway();
|
|
2968
|
+
return options.transport ? new ProxyRunGateway(options.transport, options.partition ?? "default", options.runGatewayTimeoutMs, void 0, options.tenantToken) : unavailableRunGateway();
|
|
2941
2969
|
}, "useFactory"),
|
|
2942
2970
|
inject: [
|
|
2943
2971
|
DURABLE_OPTIONS_CANONICAL7,
|
|
@@ -2972,7 +3000,7 @@ DurableModule = _ts_decorate12([
|
|
|
2972
3000
|
], DurableModule);
|
|
2973
3001
|
|
|
2974
3002
|
// src/index.ts
|
|
2975
|
-
import { readSearchAttributes as readSearchAttributes2, RunGateway as RunGateway3, WorkflowEngine as WorkflowEngine7 } from "@dudousxd/nestjs-durable-core";
|
|
3003
|
+
import { hmacTenantVerifier, prevCronFireMs, readSearchAttributes as readSearchAttributes2, RunGateway as RunGateway3, runSchedules as runSchedules2, scheduledRunId, scheduleRunIdAt, signTenantToken, WorkflowEngine as WorkflowEngine7 } from "@dudousxd/nestjs-durable-core";
|
|
2976
3004
|
export {
|
|
2977
3005
|
CONTEXT_ACCESSOR,
|
|
2978
3006
|
DEAD_LETTER_METADATA,
|
|
@@ -3022,13 +3050,19 @@ export {
|
|
|
3022
3050
|
getEntityMeta,
|
|
3023
3051
|
getOnEvents,
|
|
3024
3052
|
getWorkflowMeta,
|
|
3053
|
+
hmacTenantVerifier,
|
|
3025
3054
|
inAppWorkerProviders,
|
|
3026
3055
|
isDeadLetterHandler,
|
|
3027
3056
|
isDrivingOperator,
|
|
3028
3057
|
isOperatorRole,
|
|
3029
3058
|
isStepInterceptor,
|
|
3030
3059
|
onErrorCodesOf,
|
|
3060
|
+
prevCronFireMs,
|
|
3031
3061
|
readSearchAttributes2 as readSearchAttributes,
|
|
3062
|
+
runSchedules2 as runSchedules,
|
|
3063
|
+
scheduleRunIdAt,
|
|
3064
|
+
scheduledRunId,
|
|
3065
|
+
signTenantToken,
|
|
3032
3066
|
thinWorkerProviders,
|
|
3033
3067
|
unavailableRunGateway
|
|
3034
3068
|
};
|