@dudousxd/nestjs-durable-core 0.83.0 → 0.84.1

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
@@ -4067,6 +4067,90 @@ interface FindStalledRunsOptions {
4067
4067
  */
4068
4068
  declare function findStalledRuns(store: Pick<StateStore, 'listRuns' | 'listCheckpoints'>, options?: FindStalledRunsOptions): Promise<StalledRunInfo[]>;
4069
4069
 
4070
+ /**
4071
+ * Layered tenant auth for the store-less cluster. On a tenant worker the `tenant` on a
4072
+ * {@link import('./interfaces').RunRequest} / {@link import('./interfaces').StartRunMessage} is only
4073
+ * a CLAIM: without a signed proof, any broker client can act as any tenant. This module is the
4074
+ * default defense in depth on top of prefix/network isolation: a symmetric HMAC token the tenant
4075
+ * worker presents IN the existing `tenant` wire field, which the operator's {@link TenantVerifier}
4076
+ * checks and DERIVES the real tenant from, never trusting the body.
4077
+ *
4078
+ * Wire-compatible with Agora (`@adonis-agora/durable`) byte for byte: the token is
4079
+ * `<claim>.<base64url(HMAC-SHA256(secret, claim))>`, where `claim` is the tenant name, optionally
4080
+ * followed by `.exp<epochMs>`. It fits the `tenant: string` field with NO envelope change, so an
4081
+ * operator that does not verify simply treats the whole string as the tenant name (and finds no
4082
+ * runs, a safe failure), while an operator configured with {@link hmacTenantVerifier} verifies the
4083
+ * signature and scopes to the embedded tenant. Agora and Aviary tokens are interchangeable.
4084
+ *
4085
+ * HMAC (shared secret) is the zero-infra default; a deployment that prefers asymmetric or issued
4086
+ * tokens supplies its own {@link TenantVerifier} instead.
4087
+ */
4088
+ /** The identity a {@link TenantVerifier} derives from a tenant's signed claim. */
4089
+ interface VerifiedTenant {
4090
+ /** The tenant the token authenticates as. The responder trusts THIS, never the request body. */
4091
+ tenant: string;
4092
+ /**
4093
+ * Capabilities the token grants, if the issuer scopes them. Carried for custom verifiers and for
4094
+ * wire parity with Agora; the built-in responder does NOT enforce them yet. A verified tenant can
4095
+ * call every verb, scoped to its own namespace.
4096
+ */
4097
+ capabilities?: string[] | undefined;
4098
+ }
4099
+ /**
4100
+ * Verifies a tenant's signed claim on the **operator** side, returning the {@link VerifiedTenant} it
4101
+ * authenticates as, or `null` (or throwing) to reject a tampered/invalid/absent token. The signed
4102
+ * token travels in the wire `tenant` field, so the responder passes that value as both `token` and
4103
+ * the advisory `tenant`.
4104
+ */
4105
+ type TenantVerifier = (input: {
4106
+ /** The signed token presented on the request. */
4107
+ token?: string | undefined;
4108
+ /** The tenant the request *claims* to be. Advisory only: the verifier derives the real one. */
4109
+ tenant?: string | undefined;
4110
+ }) => VerifiedTenant | null | Promise<VerifiedTenant | null>;
4111
+ /**
4112
+ * Where the tenant side gets the token it presents: a static string, or a function called before
4113
+ * every request (so a short-lived token from {@link signTenantToken} with `ttlMs` can be re-minted
4114
+ * or fetched from a secret store without restarting the worker).
4115
+ */
4116
+ type TenantTokenSource = string | (() => string | Promise<string>);
4117
+ /**
4118
+ * Mint the signed token a tenant worker presents:
4119
+ * `` `${tenant}.${base64url(HMAC-SHA256(secret, tenant))}` ``. The worker carries only the token
4120
+ * (never the secret); the operator verifies it with the SAME `secret` via {@link hmacTenantVerifier}.
4121
+ */
4122
+ declare function signTenantToken(tenant: string, secret: string, opts?: {
4123
+ /**
4124
+ * Optional lifetime: the claim gains a `.exp<epochMs>` suffix, signed together with the tenant,
4125
+ * and {@link hmacTenantVerifier} rejects the token once that instant passes. Without it the
4126
+ * token never expires. Expiring and non-expiring tokens verify side by side. Tenant names
4127
+ * ending in `.exp<digits>` are reserved by this scheme.
4128
+ */
4129
+ ttlMs?: number;
4130
+ /** Injectable clock for tests. */
4131
+ now?: number;
4132
+ }): string;
4133
+ /**
4134
+ * Build the operator-side {@link TenantVerifier} for {@link signTenantToken} tokens under `secret`.
4135
+ * It recomputes the HMAC over the embedded claim and compares it in constant time, so a tampered
4136
+ * tenant, a forged/absent signature, a token signed with another secret, or an expired token all
4137
+ * return `null`. The tenant is DERIVED from the token's own claim.
4138
+ *
4139
+ * A LIST of secrets makes rotation a two-step deploy: verify with `[next, current]` everywhere first,
4140
+ * then re-mint tenant tokens with `next` at leisure. `capabilities`, if given, is a static grant
4141
+ * stamped onto every {@link VerifiedTenant} this verifier authenticates (informational: the
4142
+ * responder does not enforce it yet, see {@link VerifiedTenant.capabilities}).
4143
+ */
4144
+ declare function hmacTenantVerifier(secret: string | string[], capabilities?: string[]): TenantVerifier;
4145
+ /**
4146
+ * Resolve the tenant a wire message is ALLOWED to act as. With a verifier, the wire `tenant` is the
4147
+ * signed token: it is verified and the real tenant derived from it (`null` on reject). Without one,
4148
+ * the wire value is trusted verbatim (prefix/network isolation only, today's behaviour).
4149
+ */
4150
+ declare function resolveWireTenant(wireTenant: string, verifyTenant: TenantVerifier | undefined): Promise<string | null>;
4151
+ /** Resolve a {@link TenantTokenSource} to the token string to put on the wire. */
4152
+ declare function resolveTenantToken(source: TenantTokenSource): Promise<string>;
4153
+
4070
4154
  type WorkflowFn = (ctx: InternalWorkflowCtx, input: unknown) => Promise<unknown>;
4071
4155
  /**
4072
4156
  * Options for {@link WorkflowEngine.start}.
@@ -4210,6 +4294,13 @@ interface WorkflowEngineDeps {
4210
4294
  * plane: "ver tudo = ausência de namespace".
4211
4295
  */
4212
4296
  namespace?: string | undefined;
4297
+ /**
4298
+ * Verifies the signed tenant token a store-less tenant worker presents in the `tenant` field of a
4299
+ * {@link StartRunMessage}, and DERIVES the run's namespace from it (see `hmacTenantVerifier`).
4300
+ * A message whose token is rejected (or whose verifier throws) is dropped without creating a run.
4301
+ * Absent: the wire `tenant` is trusted verbatim, as before.
4302
+ */
4303
+ verifyTenant?: TenantVerifier | undefined;
4213
4304
  /** Recovery lease duration in ms — how long this instance owns a run it picked up. Default 30s. */
4214
4305
  leaseMs?: number | undefined;
4215
4306
  /**
@@ -7188,4 +7279,4 @@ declare function singletonAdmissionDenialPatch(runs: WorkflowRun[], runId: strin
7188
7279
  updatedAt: Date;
7189
7280
  } | undefined;
7190
7281
 
7191
- export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AllOptions, type AllSettledOptions, type AllStepsOptions, type AllStepsSettledOptions, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CHILD_EDGE_PREFIXES, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type CheckpointAggregatingStore, type CheckpointNameKind, type CheckpointQuery, type CheckpointStat, type ChildCallOptions, type ChildWait, CodecStateStore, type CodecStateStoreOptions, type ConcurrencyConfig, ConcurrencyLimitError, type ConcurrencyQuota, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_CONCURRENCY_STATUSES, DEFAULT_PARTITION, DEFAULT_STALLED_AFTER_MS, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type Disagreement, type DispatchDiagnostics, type DispatchPlan, type DurableExecution, type DurableExecutionWrapper, type DurableTopology, type DurableWebhook, DurableWorkflow, type DynamicWorkflowCtx, ENGINE_MINTED_TAG_PREFIXES, ENTITY_WORKFLOW, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, type EntityWorkflowHost, EventAccumulators, type EventBatchConfig, FAN_SUMMARY_FAILURES, type FanJoin, type FanPage, type FanPageQuery, type FanSummary, type FanWait, FatalError, type FindStalledRunsOptions, GatherError, type GatherItemFailure, type GroupHealth, HANDOFF_SEQ_BASE, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type ListStalledRunsOptions, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NestedWorkflowCallError, NonDeterminismError, type OnErrorInput, type OnErrorRoute, type OwnedLeaseReclaim, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, RUN_HISTORY_FIXTURE_VERSION, RUN_VALUE_FACET_LIMIT, RUN_VALUE_FACET_SCAN, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDetailOptions, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunScope, type RunStatus, type RunValueAxis, type RunValueFacetOptions, type RunValueFacetOrder, type RunValueFacetRow, type RunWaiting, SINGLETON_ACTIVE_STATUSES, SINGLETON_ADMITTED_TAG, SINGLETON_RESERVED_TAGS, SINGLETON_TRACKED_TAG, STATE_STORE, STATE_STORE_CANONICAL, SUMMARY_CHILD_LIMIT, type ScalarAttributeFilter, ScheduleAlreadyExistsError, ScheduleClient, type ScheduleClientOptions, type ScheduleDescription, type ScheduleHost, type ScheduleListQuery, ScheduleNotFoundError, type ScheduleOptions, type ScheduleQuery, type ScheduleRecord, type ScheduledWorkflow, type SchemaIssue, type SchemaValidationCode, SchemaValidationError, type SearchAttributes, type SearchAttributesSchema, type Settled, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, type StalePendingStep, type StalledRunInfo, StandardSchemaV1, type StartOptions, type StartRunMessage, type StateStore, type StepCheckpoint, type StepConfig, type StepDef, type StepDispatchOpts, type StepError, type StepEvent, type StepHandler, type StepInterceptor, type StepInvocation, type StepKind, type StepLogger, type StepOptions, type StepRef, type StepResult, type StepScope, type StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, VERSION_UNDECLARED_TAG, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerDescriptor, type WorkerHeartbeat, type WorkerLifecycle, type WorkerStatus, type WorkflowAnnouncement, WorkflowBlocked, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, type WorkflowDirectory, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRegistration, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, aggregateAnnouncements, aggregatesCheckpoints, announcementsOf, applyAttributeQuery, assertConcurrency, assertRoutes, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, checkpointNameKind, checkpointStatsOf, childIdsOf, classifyWaiterToken, clearDurableExecutionWrappers, clearTerminalSingletonAdmission, codeAndDetails, codeOf, collectMetrics, concurrencyTag, controlPlaneDescriptor, countRuns, coveredTokens, createStepLogger, currentStep, currentStepScope, currentWorkflowCtx, debug, describeWorker, descriptorHash, detailsOf, error, etagMatches, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, fanPageBounds, fanPageEtag, findStalledRuns, foldedCount, handoffHandlerId, handoffName, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isFailedMember, isLegacyDescriptor, isNonEmptyRunScope, isWorkflowControlFlowSignal, legacySingletonHolders, listSignalWaitersOfRuns, liveHandoff, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, nextCronFireMs, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, onErrorRunId, pageFan, pageFanFromStore, parentRunIdOf, parseDuration, parseWebhookToken, partitionOfToken, planDispatch, poolNamespace, prevCronFireMs, queryCheckpointsOf, readSearchAttributes, requiredCapabilities, resolveConcurrency, resolveRouting, resolveRunWaiting, retiredHandoffName, routeFor, runDetailEtag, runDurableExecution, runInStepLogger, runInStepScope, runInWorkflowCtx, runOutsideWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduleRunIdAt, scheduledRunId, singletonAdmissionDenialPatch, singletonAdmissionTags, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, summarizeFan, summarizeRunFromStore, summarizeTimeline, tenantGroup, useDurableExecution, warn, withSingletonTracked, withoutSingletonMarkers, workflowName };
7282
+ export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AllOptions, type AllSettledOptions, type AllStepsOptions, type AllStepsSettledOptions, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CHILD_EDGE_PREFIXES, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type CheckpointAggregatingStore, type CheckpointNameKind, type CheckpointQuery, type CheckpointStat, type ChildCallOptions, type ChildWait, CodecStateStore, type CodecStateStoreOptions, type ConcurrencyConfig, ConcurrencyLimitError, type ConcurrencyQuota, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_CONCURRENCY_STATUSES, DEFAULT_PARTITION, DEFAULT_STALLED_AFTER_MS, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type Disagreement, type DispatchDiagnostics, type DispatchPlan, type DurableExecution, type DurableExecutionWrapper, type DurableTopology, type DurableWebhook, DurableWorkflow, type DynamicWorkflowCtx, ENGINE_MINTED_TAG_PREFIXES, ENTITY_WORKFLOW, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, type EntityWorkflowHost, EventAccumulators, type EventBatchConfig, FAN_SUMMARY_FAILURES, type FanJoin, type FanPage, type FanPageQuery, type FanSummary, type FanWait, FatalError, type FindStalledRunsOptions, GatherError, type GatherItemFailure, type GroupHealth, HANDOFF_SEQ_BASE, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type ListStalledRunsOptions, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NestedWorkflowCallError, NonDeterminismError, type OnErrorInput, type OnErrorRoute, type OwnedLeaseReclaim, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, RUN_HISTORY_FIXTURE_VERSION, RUN_VALUE_FACET_LIMIT, RUN_VALUE_FACET_SCAN, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDetailOptions, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunScope, type RunStatus, type RunValueAxis, type RunValueFacetOptions, type RunValueFacetOrder, type RunValueFacetRow, type RunWaiting, SINGLETON_ACTIVE_STATUSES, SINGLETON_ADMITTED_TAG, SINGLETON_RESERVED_TAGS, SINGLETON_TRACKED_TAG, STATE_STORE, STATE_STORE_CANONICAL, SUMMARY_CHILD_LIMIT, type ScalarAttributeFilter, ScheduleAlreadyExistsError, ScheduleClient, type ScheduleClientOptions, type ScheduleDescription, type ScheduleHost, type ScheduleListQuery, ScheduleNotFoundError, type ScheduleOptions, type ScheduleQuery, type ScheduleRecord, type ScheduledWorkflow, type SchemaIssue, type SchemaValidationCode, SchemaValidationError, type SearchAttributes, type SearchAttributesSchema, type Settled, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, type StalePendingStep, type StalledRunInfo, StandardSchemaV1, type StartOptions, type StartRunMessage, type StateStore, type StepCheckpoint, type StepConfig, type StepDef, type StepDispatchOpts, type StepError, type StepEvent, type StepHandler, type StepInterceptor, type StepInvocation, type StepKind, type StepLogger, type StepOptions, type StepRef, type StepResult, type StepScope, type StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type TenantTokenSource, type TenantVerifier, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, VERSION_UNDECLARED_TAG, type VerifiedTenant, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerDescriptor, type WorkerHeartbeat, type WorkerLifecycle, type WorkerStatus, type WorkflowAnnouncement, WorkflowBlocked, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, type WorkflowDirectory, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRegistration, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, aggregateAnnouncements, aggregatesCheckpoints, announcementsOf, applyAttributeQuery, assertConcurrency, assertRoutes, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, checkpointNameKind, checkpointStatsOf, childIdsOf, classifyWaiterToken, clearDurableExecutionWrappers, clearTerminalSingletonAdmission, codeAndDetails, codeOf, collectMetrics, concurrencyTag, controlPlaneDescriptor, countRuns, coveredTokens, createStepLogger, currentStep, currentStepScope, currentWorkflowCtx, debug, describeWorker, descriptorHash, detailsOf, error, etagMatches, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, fanPageBounds, fanPageEtag, findStalledRuns, foldedCount, handoffHandlerId, handoffName, hasDurableExecutionWrappers, heartbeatStatus, hmacTenantVerifier, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isFailedMember, isLegacyDescriptor, isNonEmptyRunScope, isWorkflowControlFlowSignal, legacySingletonHolders, listSignalWaitersOfRuns, liveHandoff, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, nextCronFireMs, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, onErrorRunId, pageFan, pageFanFromStore, parentRunIdOf, parseDuration, parseWebhookToken, partitionOfToken, planDispatch, poolNamespace, prevCronFireMs, queryCheckpointsOf, readSearchAttributes, requiredCapabilities, resolveConcurrency, resolveRouting, resolveRunWaiting, resolveTenantToken, resolveWireTenant, retiredHandoffName, routeFor, runDetailEtag, runDurableExecution, runInStepLogger, runInStepScope, runInWorkflowCtx, runOutsideWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduleRunIdAt, scheduledRunId, signTenantToken, singletonAdmissionDenialPatch, singletonAdmissionTags, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, summarizeFan, summarizeRunFromStore, summarizeTimeline, tenantGroup, useDurableExecution, warn, withSingletonTracked, withoutSingletonMarkers, workflowName };
package/dist/index.d.ts CHANGED
@@ -4067,6 +4067,90 @@ interface FindStalledRunsOptions {
4067
4067
  */
4068
4068
  declare function findStalledRuns(store: Pick<StateStore, 'listRuns' | 'listCheckpoints'>, options?: FindStalledRunsOptions): Promise<StalledRunInfo[]>;
4069
4069
 
4070
+ /**
4071
+ * Layered tenant auth for the store-less cluster. On a tenant worker the `tenant` on a
4072
+ * {@link import('./interfaces').RunRequest} / {@link import('./interfaces').StartRunMessage} is only
4073
+ * a CLAIM: without a signed proof, any broker client can act as any tenant. This module is the
4074
+ * default defense in depth on top of prefix/network isolation: a symmetric HMAC token the tenant
4075
+ * worker presents IN the existing `tenant` wire field, which the operator's {@link TenantVerifier}
4076
+ * checks and DERIVES the real tenant from, never trusting the body.
4077
+ *
4078
+ * Wire-compatible with Agora (`@adonis-agora/durable`) byte for byte: the token is
4079
+ * `<claim>.<base64url(HMAC-SHA256(secret, claim))>`, where `claim` is the tenant name, optionally
4080
+ * followed by `.exp<epochMs>`. It fits the `tenant: string` field with NO envelope change, so an
4081
+ * operator that does not verify simply treats the whole string as the tenant name (and finds no
4082
+ * runs, a safe failure), while an operator configured with {@link hmacTenantVerifier} verifies the
4083
+ * signature and scopes to the embedded tenant. Agora and Aviary tokens are interchangeable.
4084
+ *
4085
+ * HMAC (shared secret) is the zero-infra default; a deployment that prefers asymmetric or issued
4086
+ * tokens supplies its own {@link TenantVerifier} instead.
4087
+ */
4088
+ /** The identity a {@link TenantVerifier} derives from a tenant's signed claim. */
4089
+ interface VerifiedTenant {
4090
+ /** The tenant the token authenticates as. The responder trusts THIS, never the request body. */
4091
+ tenant: string;
4092
+ /**
4093
+ * Capabilities the token grants, if the issuer scopes them. Carried for custom verifiers and for
4094
+ * wire parity with Agora; the built-in responder does NOT enforce them yet. A verified tenant can
4095
+ * call every verb, scoped to its own namespace.
4096
+ */
4097
+ capabilities?: string[] | undefined;
4098
+ }
4099
+ /**
4100
+ * Verifies a tenant's signed claim on the **operator** side, returning the {@link VerifiedTenant} it
4101
+ * authenticates as, or `null` (or throwing) to reject a tampered/invalid/absent token. The signed
4102
+ * token travels in the wire `tenant` field, so the responder passes that value as both `token` and
4103
+ * the advisory `tenant`.
4104
+ */
4105
+ type TenantVerifier = (input: {
4106
+ /** The signed token presented on the request. */
4107
+ token?: string | undefined;
4108
+ /** The tenant the request *claims* to be. Advisory only: the verifier derives the real one. */
4109
+ tenant?: string | undefined;
4110
+ }) => VerifiedTenant | null | Promise<VerifiedTenant | null>;
4111
+ /**
4112
+ * Where the tenant side gets the token it presents: a static string, or a function called before
4113
+ * every request (so a short-lived token from {@link signTenantToken} with `ttlMs` can be re-minted
4114
+ * or fetched from a secret store without restarting the worker).
4115
+ */
4116
+ type TenantTokenSource = string | (() => string | Promise<string>);
4117
+ /**
4118
+ * Mint the signed token a tenant worker presents:
4119
+ * `` `${tenant}.${base64url(HMAC-SHA256(secret, tenant))}` ``. The worker carries only the token
4120
+ * (never the secret); the operator verifies it with the SAME `secret` via {@link hmacTenantVerifier}.
4121
+ */
4122
+ declare function signTenantToken(tenant: string, secret: string, opts?: {
4123
+ /**
4124
+ * Optional lifetime: the claim gains a `.exp<epochMs>` suffix, signed together with the tenant,
4125
+ * and {@link hmacTenantVerifier} rejects the token once that instant passes. Without it the
4126
+ * token never expires. Expiring and non-expiring tokens verify side by side. Tenant names
4127
+ * ending in `.exp<digits>` are reserved by this scheme.
4128
+ */
4129
+ ttlMs?: number;
4130
+ /** Injectable clock for tests. */
4131
+ now?: number;
4132
+ }): string;
4133
+ /**
4134
+ * Build the operator-side {@link TenantVerifier} for {@link signTenantToken} tokens under `secret`.
4135
+ * It recomputes the HMAC over the embedded claim and compares it in constant time, so a tampered
4136
+ * tenant, a forged/absent signature, a token signed with another secret, or an expired token all
4137
+ * return `null`. The tenant is DERIVED from the token's own claim.
4138
+ *
4139
+ * A LIST of secrets makes rotation a two-step deploy: verify with `[next, current]` everywhere first,
4140
+ * then re-mint tenant tokens with `next` at leisure. `capabilities`, if given, is a static grant
4141
+ * stamped onto every {@link VerifiedTenant} this verifier authenticates (informational: the
4142
+ * responder does not enforce it yet, see {@link VerifiedTenant.capabilities}).
4143
+ */
4144
+ declare function hmacTenantVerifier(secret: string | string[], capabilities?: string[]): TenantVerifier;
4145
+ /**
4146
+ * Resolve the tenant a wire message is ALLOWED to act as. With a verifier, the wire `tenant` is the
4147
+ * signed token: it is verified and the real tenant derived from it (`null` on reject). Without one,
4148
+ * the wire value is trusted verbatim (prefix/network isolation only, today's behaviour).
4149
+ */
4150
+ declare function resolveWireTenant(wireTenant: string, verifyTenant: TenantVerifier | undefined): Promise<string | null>;
4151
+ /** Resolve a {@link TenantTokenSource} to the token string to put on the wire. */
4152
+ declare function resolveTenantToken(source: TenantTokenSource): Promise<string>;
4153
+
4070
4154
  type WorkflowFn = (ctx: InternalWorkflowCtx, input: unknown) => Promise<unknown>;
4071
4155
  /**
4072
4156
  * Options for {@link WorkflowEngine.start}.
@@ -4210,6 +4294,13 @@ interface WorkflowEngineDeps {
4210
4294
  * plane: "ver tudo = ausência de namespace".
4211
4295
  */
4212
4296
  namespace?: string | undefined;
4297
+ /**
4298
+ * Verifies the signed tenant token a store-less tenant worker presents in the `tenant` field of a
4299
+ * {@link StartRunMessage}, and DERIVES the run's namespace from it (see `hmacTenantVerifier`).
4300
+ * A message whose token is rejected (or whose verifier throws) is dropped without creating a run.
4301
+ * Absent: the wire `tenant` is trusted verbatim, as before.
4302
+ */
4303
+ verifyTenant?: TenantVerifier | undefined;
4213
4304
  /** Recovery lease duration in ms — how long this instance owns a run it picked up. Default 30s. */
4214
4305
  leaseMs?: number | undefined;
4215
4306
  /**
@@ -7188,4 +7279,4 @@ declare function singletonAdmissionDenialPatch(runs: WorkflowRun[], runId: strin
7188
7279
  updatedAt: Date;
7189
7280
  } | undefined;
7190
7281
 
7191
- export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AllOptions, type AllSettledOptions, type AllStepsOptions, type AllStepsSettledOptions, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CHILD_EDGE_PREFIXES, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type CheckpointAggregatingStore, type CheckpointNameKind, type CheckpointQuery, type CheckpointStat, type ChildCallOptions, type ChildWait, CodecStateStore, type CodecStateStoreOptions, type ConcurrencyConfig, ConcurrencyLimitError, type ConcurrencyQuota, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_CONCURRENCY_STATUSES, DEFAULT_PARTITION, DEFAULT_STALLED_AFTER_MS, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type Disagreement, type DispatchDiagnostics, type DispatchPlan, type DurableExecution, type DurableExecutionWrapper, type DurableTopology, type DurableWebhook, DurableWorkflow, type DynamicWorkflowCtx, ENGINE_MINTED_TAG_PREFIXES, ENTITY_WORKFLOW, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, type EntityWorkflowHost, EventAccumulators, type EventBatchConfig, FAN_SUMMARY_FAILURES, type FanJoin, type FanPage, type FanPageQuery, type FanSummary, type FanWait, FatalError, type FindStalledRunsOptions, GatherError, type GatherItemFailure, type GroupHealth, HANDOFF_SEQ_BASE, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type ListStalledRunsOptions, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NestedWorkflowCallError, NonDeterminismError, type OnErrorInput, type OnErrorRoute, type OwnedLeaseReclaim, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, RUN_HISTORY_FIXTURE_VERSION, RUN_VALUE_FACET_LIMIT, RUN_VALUE_FACET_SCAN, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDetailOptions, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunScope, type RunStatus, type RunValueAxis, type RunValueFacetOptions, type RunValueFacetOrder, type RunValueFacetRow, type RunWaiting, SINGLETON_ACTIVE_STATUSES, SINGLETON_ADMITTED_TAG, SINGLETON_RESERVED_TAGS, SINGLETON_TRACKED_TAG, STATE_STORE, STATE_STORE_CANONICAL, SUMMARY_CHILD_LIMIT, type ScalarAttributeFilter, ScheduleAlreadyExistsError, ScheduleClient, type ScheduleClientOptions, type ScheduleDescription, type ScheduleHost, type ScheduleListQuery, ScheduleNotFoundError, type ScheduleOptions, type ScheduleQuery, type ScheduleRecord, type ScheduledWorkflow, type SchemaIssue, type SchemaValidationCode, SchemaValidationError, type SearchAttributes, type SearchAttributesSchema, type Settled, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, type StalePendingStep, type StalledRunInfo, StandardSchemaV1, type StartOptions, type StartRunMessage, type StateStore, type StepCheckpoint, type StepConfig, type StepDef, type StepDispatchOpts, type StepError, type StepEvent, type StepHandler, type StepInterceptor, type StepInvocation, type StepKind, type StepLogger, type StepOptions, type StepRef, type StepResult, type StepScope, type StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, VERSION_UNDECLARED_TAG, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerDescriptor, type WorkerHeartbeat, type WorkerLifecycle, type WorkerStatus, type WorkflowAnnouncement, WorkflowBlocked, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, type WorkflowDirectory, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRegistration, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, aggregateAnnouncements, aggregatesCheckpoints, announcementsOf, applyAttributeQuery, assertConcurrency, assertRoutes, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, checkpointNameKind, checkpointStatsOf, childIdsOf, classifyWaiterToken, clearDurableExecutionWrappers, clearTerminalSingletonAdmission, codeAndDetails, codeOf, collectMetrics, concurrencyTag, controlPlaneDescriptor, countRuns, coveredTokens, createStepLogger, currentStep, currentStepScope, currentWorkflowCtx, debug, describeWorker, descriptorHash, detailsOf, error, etagMatches, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, fanPageBounds, fanPageEtag, findStalledRuns, foldedCount, handoffHandlerId, handoffName, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isFailedMember, isLegacyDescriptor, isNonEmptyRunScope, isWorkflowControlFlowSignal, legacySingletonHolders, listSignalWaitersOfRuns, liveHandoff, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, nextCronFireMs, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, onErrorRunId, pageFan, pageFanFromStore, parentRunIdOf, parseDuration, parseWebhookToken, partitionOfToken, planDispatch, poolNamespace, prevCronFireMs, queryCheckpointsOf, readSearchAttributes, requiredCapabilities, resolveConcurrency, resolveRouting, resolveRunWaiting, retiredHandoffName, routeFor, runDetailEtag, runDurableExecution, runInStepLogger, runInStepScope, runInWorkflowCtx, runOutsideWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduleRunIdAt, scheduledRunId, singletonAdmissionDenialPatch, singletonAdmissionTags, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, summarizeFan, summarizeRunFromStore, summarizeTimeline, tenantGroup, useDurableExecution, warn, withSingletonTracked, withoutSingletonMarkers, workflowName };
7282
+ export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AllOptions, type AllSettledOptions, type AllStepsOptions, type AllStepsSettledOptions, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CHILD_EDGE_PREFIXES, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type CheckpointAggregatingStore, type CheckpointNameKind, type CheckpointQuery, type CheckpointStat, type ChildCallOptions, type ChildWait, CodecStateStore, type CodecStateStoreOptions, type ConcurrencyConfig, ConcurrencyLimitError, type ConcurrencyQuota, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_CONCURRENCY_STATUSES, DEFAULT_PARTITION, DEFAULT_STALLED_AFTER_MS, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type Disagreement, type DispatchDiagnostics, type DispatchPlan, type DurableExecution, type DurableExecutionWrapper, type DurableTopology, type DurableWebhook, DurableWorkflow, type DynamicWorkflowCtx, ENGINE_MINTED_TAG_PREFIXES, ENTITY_WORKFLOW, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, type EntityWorkflowHost, EventAccumulators, type EventBatchConfig, FAN_SUMMARY_FAILURES, type FanJoin, type FanPage, type FanPageQuery, type FanSummary, type FanWait, FatalError, type FindStalledRunsOptions, GatherError, type GatherItemFailure, type GroupHealth, HANDOFF_SEQ_BASE, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type ListStalledRunsOptions, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NestedWorkflowCallError, NonDeterminismError, type OnErrorInput, type OnErrorRoute, type OwnedLeaseReclaim, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, RUN_HISTORY_FIXTURE_VERSION, RUN_VALUE_FACET_LIMIT, RUN_VALUE_FACET_SCAN, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDetailOptions, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunScope, type RunStatus, type RunValueAxis, type RunValueFacetOptions, type RunValueFacetOrder, type RunValueFacetRow, type RunWaiting, SINGLETON_ACTIVE_STATUSES, SINGLETON_ADMITTED_TAG, SINGLETON_RESERVED_TAGS, SINGLETON_TRACKED_TAG, STATE_STORE, STATE_STORE_CANONICAL, SUMMARY_CHILD_LIMIT, type ScalarAttributeFilter, ScheduleAlreadyExistsError, ScheduleClient, type ScheduleClientOptions, type ScheduleDescription, type ScheduleHost, type ScheduleListQuery, ScheduleNotFoundError, type ScheduleOptions, type ScheduleQuery, type ScheduleRecord, type ScheduledWorkflow, type SchemaIssue, type SchemaValidationCode, SchemaValidationError, type SearchAttributes, type SearchAttributesSchema, type Settled, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, type StalePendingStep, type StalledRunInfo, StandardSchemaV1, type StartOptions, type StartRunMessage, type StateStore, type StepCheckpoint, type StepConfig, type StepDef, type StepDispatchOpts, type StepError, type StepEvent, type StepHandler, type StepInterceptor, type StepInvocation, type StepKind, type StepLogger, type StepOptions, type StepRef, type StepResult, type StepScope, type StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type TenantTokenSource, type TenantVerifier, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, VERSION_UNDECLARED_TAG, type VerifiedTenant, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerDescriptor, type WorkerHeartbeat, type WorkerLifecycle, type WorkerStatus, type WorkflowAnnouncement, WorkflowBlocked, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, type WorkflowDirectory, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRegistration, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, aggregateAnnouncements, aggregatesCheckpoints, announcementsOf, applyAttributeQuery, assertConcurrency, assertRoutes, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, checkpointNameKind, checkpointStatsOf, childIdsOf, classifyWaiterToken, clearDurableExecutionWrappers, clearTerminalSingletonAdmission, codeAndDetails, codeOf, collectMetrics, concurrencyTag, controlPlaneDescriptor, countRuns, coveredTokens, createStepLogger, currentStep, currentStepScope, currentWorkflowCtx, debug, describeWorker, descriptorHash, detailsOf, error, etagMatches, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, fanPageBounds, fanPageEtag, findStalledRuns, foldedCount, handoffHandlerId, handoffName, hasDurableExecutionWrappers, heartbeatStatus, hmacTenantVerifier, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isFailedMember, isLegacyDescriptor, isNonEmptyRunScope, isWorkflowControlFlowSignal, legacySingletonHolders, listSignalWaitersOfRuns, liveHandoff, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, nextCronFireMs, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, onErrorRunId, pageFan, pageFanFromStore, parentRunIdOf, parseDuration, parseWebhookToken, partitionOfToken, planDispatch, poolNamespace, prevCronFireMs, queryCheckpointsOf, readSearchAttributes, requiredCapabilities, resolveConcurrency, resolveRouting, resolveRunWaiting, resolveTenantToken, resolveWireTenant, retiredHandoffName, routeFor, runDetailEtag, runDurableExecution, runInStepLogger, runInStepScope, runInWorkflowCtx, runOutsideWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduleRunIdAt, scheduledRunId, signTenantToken, singletonAdmissionDenialPatch, singletonAdmissionTags, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, summarizeFan, summarizeRunFromStore, summarizeTimeline, tenantGroup, useDurableExecution, warn, withSingletonTracked, withoutSingletonMarkers, workflowName };
package/dist/index.js CHANGED
@@ -2940,6 +2940,73 @@ async function stalledInfo(store, run, now, thresholdMs, ageMs) {
2940
2940
  }
2941
2941
  __name(stalledInfo, "stalledInfo");
2942
2942
 
2943
+ // src/tenant-auth.ts
2944
+ import { createHmac, timingSafeEqual } from "node:crypto";
2945
+ var TOKEN_SEP = ".";
2946
+ var EXP_SUFFIX = /\.exp(\d+)$/;
2947
+ function sign(claim, secret) {
2948
+ return createHmac("sha256", secret).update(claim).digest("base64url");
2949
+ }
2950
+ __name(sign, "sign");
2951
+ function signTenantToken(tenant, secret, opts) {
2952
+ const claim = opts?.ttlMs !== void 0 ? `${tenant}${TOKEN_SEP}exp${(opts.now ?? Date.now()) + opts.ttlMs}` : tenant;
2953
+ return `${claim}${TOKEN_SEP}${sign(claim, secret)}`;
2954
+ }
2955
+ __name(signTenantToken, "signTenantToken");
2956
+ function hmacTenantVerifier(secret, capabilities) {
2957
+ const secrets = Array.isArray(secret) ? secret : [
2958
+ secret
2959
+ ];
2960
+ return ({ token }) => {
2961
+ if (typeof token !== "string" || token.length === 0) return null;
2962
+ const sep = token.lastIndexOf(TOKEN_SEP);
2963
+ if (sep <= 0 || sep === token.length - 1) return null;
2964
+ const claim = token.slice(0, sep);
2965
+ const presented = token.slice(sep + 1);
2966
+ if (!secrets.some((s) => constantTimeEquals(presented, sign(claim, s)))) return null;
2967
+ const exp = EXP_SUFFIX.exec(claim);
2968
+ if (exp) {
2969
+ const expiresAt = Number(exp[1]);
2970
+ if (!Number.isFinite(expiresAt) || Date.now() > expiresAt) return null;
2971
+ const tenant = claim.slice(0, claim.length - (exp[0]?.length ?? 0));
2972
+ if (tenant.length === 0) return null;
2973
+ return capabilities !== void 0 ? {
2974
+ tenant,
2975
+ capabilities
2976
+ } : {
2977
+ tenant
2978
+ };
2979
+ }
2980
+ return capabilities !== void 0 ? {
2981
+ tenant: claim,
2982
+ capabilities
2983
+ } : {
2984
+ tenant: claim
2985
+ };
2986
+ };
2987
+ }
2988
+ __name(hmacTenantVerifier, "hmacTenantVerifier");
2989
+ async function resolveWireTenant(wireTenant, verifyTenant) {
2990
+ if (!verifyTenant) return wireTenant;
2991
+ const verified = await verifyTenant({
2992
+ token: wireTenant,
2993
+ tenant: wireTenant
2994
+ });
2995
+ return verified ? verified.tenant : null;
2996
+ }
2997
+ __name(resolveWireTenant, "resolveWireTenant");
2998
+ async function resolveTenantToken(source) {
2999
+ return typeof source === "function" ? source() : source;
3000
+ }
3001
+ __name(resolveTenantToken, "resolveTenantToken");
3002
+ function constantTimeEquals(a, b) {
3003
+ const ab = Buffer.from(a);
3004
+ const bb = Buffer.from(b);
3005
+ if (ab.length !== bb.length) return false;
3006
+ return timingSafeEqual(ab, bb);
3007
+ }
3008
+ __name(constantTimeEquals, "constantTimeEquals");
3009
+
2943
3010
  // src/transport-pool.ts
2944
3011
  var TransportPool = class {
2945
3012
  static {
@@ -4416,9 +4483,20 @@ var WorkflowEngine = class {
4416
4483
  await this.completeRemoteDecision(decision);
4417
4484
  }
4418
4485
  );
4486
+ const verifyTenant = deps.verifyTenant;
4419
4487
  this.pool.onStartRun(async (message) => {
4488
+ let tenant;
4489
+ try {
4490
+ tenant = await resolveWireTenant(message.tenant, verifyTenant);
4491
+ } catch {
4492
+ tenant = null;
4493
+ }
4494
+ if (tenant === null) {
4495
+ console.warn(`[nestjs-durable] dropped a start-run for "${message.workflow}": invalid or unauthorized tenant token`);
4496
+ return;
4497
+ }
4420
4498
  await this.start(message.workflow, message.input, message.runId ?? globalThis.crypto.randomUUID(), {
4421
- namespace: message.tenant,
4499
+ namespace: tenant,
4422
4500
  tags: message.tags,
4423
4501
  searchAttributes: message.searchAttributes
4424
4502
  });
@@ -10857,6 +10935,7 @@ export {
10857
10935
  handoffName,
10858
10936
  hasDurableExecutionWrappers,
10859
10937
  heartbeatStatus,
10938
+ hmacTenantVerifier,
10860
10939
  indexWaitersByRun,
10861
10940
  info,
10862
10941
  isEngineMintedTag,
@@ -10894,6 +10973,8 @@ export {
10894
10973
  resolveConcurrency,
10895
10974
  resolveRouting,
10896
10975
  resolveRunWaiting,
10976
+ resolveTenantToken,
10977
+ resolveWireTenant,
10897
10978
  retiredHandoffName,
10898
10979
  routeFor,
10899
10980
  runDetailEtag,
@@ -10908,6 +10989,7 @@ export {
10908
10989
  sanitizeQueueToken,
10909
10990
  scheduleRunIdAt,
10910
10991
  scheduledRunId,
10992
+ signTenantToken,
10911
10993
  singletonAdmissionDenialPatch,
10912
10994
  singletonAdmissionTags,
10913
10995
  sqlComparator,