@dudousxd/nestjs-durable-core 0.66.0 → 0.67.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.cjs +60 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -4
- package/dist/index.d.ts +73 -4
- package/dist/index.js +58 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1032,6 +1032,16 @@ interface StateStore {
|
|
|
1032
1032
|
*/
|
|
1033
1033
|
transaction?<T>(work: (tx: StoreTransaction) => Promise<T>): Promise<T>;
|
|
1034
1034
|
listRuns(query: RunQuery): Promise<WorkflowRun[]>;
|
|
1035
|
+
/**
|
|
1036
|
+
* Count the runs matching `query`, grouped by `(status, origin)` — the totals behind a console's
|
|
1037
|
+
* status and origin chips, in ONE aggregate instead of a full listing the caller counts in memory.
|
|
1038
|
+
* This is what lets a run list be paginated at all: `listRuns` can return 100 rows while the chips
|
|
1039
|
+
* still say how many of the 9,000 are failed.
|
|
1040
|
+
*
|
|
1041
|
+
* Cells with a zero count are simply absent. Optional: a store that omits it still works — callers
|
|
1042
|
+
* fall back to counting a {@link listRuns} result, which is correct but unbounded.
|
|
1043
|
+
*/
|
|
1044
|
+
runFacets?(query: RunFacetQuery): Promise<RunFacetRow[]>;
|
|
1035
1045
|
listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
|
|
1036
1046
|
/**
|
|
1037
1047
|
* The LATEST checkpoint for `runId` whose `name` equals `name` exactly (highest `seq` wins), or
|
|
@@ -1143,14 +1153,34 @@ interface RunQuery {
|
|
|
1143
1153
|
* Restrict to runs whose workflow was declared by this package (exact match against
|
|
1144
1154
|
* {@link WorkflowRun.origin}), ANDed with the other predicates.
|
|
1145
1155
|
*
|
|
1146
|
-
* A run with NO origin (unknown — see the field) matches no `origin`
|
|
1156
|
+
* A run with NO origin (unknown — see the field) matches no `origin` VALUE at all, so a UI facet
|
|
1147
1157
|
* built on this must keep an "all origins" option: filtering by any single package silently hides
|
|
1148
|
-
* every unattributed run, which reads to an operator as "those runs do not exist".
|
|
1158
|
+
* every unattributed run, which reads to an operator as "those runs do not exist". `null` selects
|
|
1159
|
+
* exactly that absent bucket (`origin IS NULL`), so a paginated console can offer an "unknown"
|
|
1160
|
+
* facet without having to hold every run in the browser to find them.
|
|
1149
1161
|
*/
|
|
1150
|
-
origin?: string | undefined;
|
|
1162
|
+
origin?: string | null | undefined;
|
|
1151
1163
|
limit?: number | undefined;
|
|
1152
1164
|
offset?: number | undefined;
|
|
1153
1165
|
}
|
|
1166
|
+
/**
|
|
1167
|
+
* The predicates a {@link RunFacetRow} count is taken over — a {@link RunQuery} minus the axes the
|
|
1168
|
+
* facets THEMSELVES report (`status`/`origin`) and minus paging. Keeping them out of the type is
|
|
1169
|
+
* what makes the counts answerable in one query: a console narrows by tag/tenant/attribute, and the
|
|
1170
|
+
* one call back tells it how the matching runs split across every status and every origin at once.
|
|
1171
|
+
*/
|
|
1172
|
+
type RunFacetQuery = Omit<RunQuery, 'status' | 'statuses' | 'origin' | 'limit' | 'offset'>;
|
|
1173
|
+
/**
|
|
1174
|
+
* One `(status, origin)` cell of {@link StateStore.runFacets} — a `GROUP BY` row, not a page of runs.
|
|
1175
|
+
* A console pivots these into its status chips and its origin chips, so both stay exact while the
|
|
1176
|
+
* list itself is paginated. `origin` is `null` for runs carrying none (see {@link WorkflowRun.origin});
|
|
1177
|
+
* that bucket is a real, countable answer here rather than the absence a value-match cannot express.
|
|
1178
|
+
*/
|
|
1179
|
+
interface RunFacetRow {
|
|
1180
|
+
status: RunStatus;
|
|
1181
|
+
origin: string | null;
|
|
1182
|
+
count: number;
|
|
1183
|
+
}
|
|
1154
1184
|
/** The transaction handle `StateStore.transaction` hands to its work callback. */
|
|
1155
1185
|
interface StoreTransaction {
|
|
1156
1186
|
/** The store-native transaction handle (TypeORM `EntityManager`, Prisma tx client, MikroORM `EntityManager`,
|
|
@@ -1214,6 +1244,9 @@ type RunRequestKind = {
|
|
|
1214
1244
|
} | {
|
|
1215
1245
|
kind: 'listRuns';
|
|
1216
1246
|
query: RunQuery;
|
|
1247
|
+
} | {
|
|
1248
|
+
kind: 'runFacets';
|
|
1249
|
+
query: RunFacetQuery;
|
|
1217
1250
|
} | {
|
|
1218
1251
|
kind: 'workerHealth';
|
|
1219
1252
|
} | {
|
|
@@ -4344,6 +4377,25 @@ declare class RemoteWorkflowExecutor implements WorkflowExecutor {
|
|
|
4344
4377
|
dispatch(run: WorkflowRun, history: HistoryEvent[], taskId: string, pendingSignals?: WorkflowTask['pendingSignals']): Promise<void>;
|
|
4345
4378
|
}
|
|
4346
4379
|
|
|
4380
|
+
/**
|
|
4381
|
+
* The origin a facet cell is filed under. An origin that is absent, null, or blank is all the same
|
|
4382
|
+
* thing to an operator — a run no package claims — so they collapse to `null` here. Without this the
|
|
4383
|
+
* "unknown" chip would count only one of those spellings while `origin IS NULL` paging returned
|
|
4384
|
+
* another, and the chip's number would not match the page it opens.
|
|
4385
|
+
*/
|
|
4386
|
+
declare function facetOrigin(origin: string | null | undefined): string | null;
|
|
4387
|
+
/**
|
|
4388
|
+
* Fold `(status, origin)` counts into one cell per pair, normalising origins via {@link facetOrigin}.
|
|
4389
|
+
* Store adapters group in SQL and pipe their rows through this, so every adapter — and the in-memory
|
|
4390
|
+
* store the tests run against — agrees on what lands in the unattributed bucket instead of each
|
|
4391
|
+
* collapsing blanks its own way.
|
|
4392
|
+
*/
|
|
4393
|
+
declare function mergeRunFacetRows(rows: readonly {
|
|
4394
|
+
status: RunStatus;
|
|
4395
|
+
origin: string | null | undefined;
|
|
4396
|
+
count: number;
|
|
4397
|
+
}[]): RunFacetRow[];
|
|
4398
|
+
|
|
4347
4399
|
/** A run as returned by the gateway's list — the durable run plus an optional {@link RunWaiting}
|
|
4348
4400
|
* descriptor the control plane resolves (what a suspended run is parked on), so the dashboard can
|
|
4349
4401
|
* name the wait in a list row without fetching each run's timeline. Additive: `waiting` is absent
|
|
@@ -4401,6 +4453,12 @@ declare abstract class RunGateway {
|
|
|
4401
4453
|
* parked on). The store-backed gateway resolves `waiting`; a proxy relays whatever the control
|
|
4402
4454
|
* plane sent. */
|
|
4403
4455
|
abstract listRuns(query: RunQuery): Promise<RunListItem[]>;
|
|
4456
|
+
/**
|
|
4457
|
+
* Counts of the runs matching `query`, grouped by `(status, origin)` — what a console's status and
|
|
4458
|
+
* origin chips display. Separate from {@link listRuns} precisely so the list can be PAGINATED: the
|
|
4459
|
+
* page bounds what is rendered, these counts stay whole-set exact. Zero-count cells are absent.
|
|
4460
|
+
*/
|
|
4461
|
+
abstract runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
|
|
4404
4462
|
/**
|
|
4405
4463
|
* Bulk-resolve {@link RunWaiting} for an arbitrary set of run ids — for a consumer with its OWN
|
|
4406
4464
|
* filtered/paginated run listing (so it isn't just `listRuns` under another name) that needs to know
|
|
@@ -4479,6 +4537,13 @@ interface PayloadCodec {
|
|
|
4479
4537
|
declare class CodecStateStore implements StateStore {
|
|
4480
4538
|
private readonly inner;
|
|
4481
4539
|
private readonly codec;
|
|
4540
|
+
/**
|
|
4541
|
+
* Forwarded verbatim — a facet cell counts `status`/`origin`, neither of which the codec touches
|
|
4542
|
+
* (it encodes payloads: input/output/error). Bound as a PROPERTY, and only when the inner store
|
|
4543
|
+
* actually aggregates, so `store.runFacets?.()` still reports absence through the wrapper instead
|
|
4544
|
+
* of resolving to a silently wrong empty result.
|
|
4545
|
+
*/
|
|
4546
|
+
readonly runFacets?: (query: RunFacetQuery) => Promise<RunFacetRow[]>;
|
|
4482
4547
|
constructor(inner: StateStore, codec: PayloadCodec);
|
|
4483
4548
|
private enc;
|
|
4484
4549
|
private dec;
|
|
@@ -4932,7 +4997,11 @@ declare class InMemoryStateStore implements StateStore {
|
|
|
4932
4997
|
* scan `strValue` rows. This is the in-memory analog of the SQL EXISTS on `durable_run_attributes`.
|
|
4933
4998
|
*/
|
|
4934
4999
|
private candidatesForFilter;
|
|
5000
|
+
/** Every run satisfying `query`'s predicates, unsorted and unpaged — the shared body of
|
|
5001
|
+
* {@link listRuns} (which then sorts + pages it) and {@link runFacets} (which groups it). */
|
|
5002
|
+
private matching;
|
|
4935
5003
|
listRuns(query: RunQuery): Promise<WorkflowRun[]>;
|
|
5004
|
+
runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
|
|
4936
5005
|
listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
|
|
4937
5006
|
getLatestCheckpointByName(runId: string, name: string): Promise<StepCheckpoint | undefined>;
|
|
4938
5007
|
listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]>;
|
|
@@ -4964,4 +5033,4 @@ declare class InMemoryTransport implements Transport, ControlPlane {
|
|
|
4964
5033
|
onControl(handler: (msg: ControlMessage) => void): void;
|
|
4965
5034
|
}
|
|
4966
5035
|
|
|
4967
|
-
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_PARTITION, 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, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NonDeterminismError, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDispatcher, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, type ScheduledWorkflow, type SearchAttributes, type SearchAttributesSchema, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, 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 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, announcementsOf, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, classifyWaiterToken, clearDurableExecutionWrappers, collectMetrics, controlPlaneDescriptor, coveredTokens, createStepLogger, currentStep, currentWorkflowCtx, debug, describeWorker, descriptorHash, error, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEventToken, isLegacyDescriptor, isWorkflowControlFlowSignal, log, matchesAttributes, missingCapabilities, negotiate, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, parseDuration, partitionOfToken, planDispatch, prevCronFireMs, readSearchAttributes, requiredCapabilities, resolveRouting, resolveRunWaiting, runDurableExecution, runInStepLogger, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, tenantGroup, useDurableExecution, warn, workflowName };
|
|
5036
|
+
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_PARTITION, 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, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NonDeterminismError, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, type ScheduledWorkflow, type SearchAttributes, type SearchAttributesSchema, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, 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 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, announcementsOf, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, classifyWaiterToken, clearDurableExecutionWrappers, collectMetrics, controlPlaneDescriptor, coveredTokens, createStepLogger, currentStep, currentWorkflowCtx, debug, describeWorker, descriptorHash, error, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEventToken, isLegacyDescriptor, isWorkflowControlFlowSignal, log, matchesAttributes, mergeRunFacetRows, missingCapabilities, negotiate, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, parseDuration, partitionOfToken, planDispatch, prevCronFireMs, readSearchAttributes, requiredCapabilities, resolveRouting, resolveRunWaiting, runDurableExecution, runInStepLogger, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, tenantGroup, useDurableExecution, warn, workflowName };
|
package/dist/index.d.ts
CHANGED
|
@@ -1032,6 +1032,16 @@ interface StateStore {
|
|
|
1032
1032
|
*/
|
|
1033
1033
|
transaction?<T>(work: (tx: StoreTransaction) => Promise<T>): Promise<T>;
|
|
1034
1034
|
listRuns(query: RunQuery): Promise<WorkflowRun[]>;
|
|
1035
|
+
/**
|
|
1036
|
+
* Count the runs matching `query`, grouped by `(status, origin)` — the totals behind a console's
|
|
1037
|
+
* status and origin chips, in ONE aggregate instead of a full listing the caller counts in memory.
|
|
1038
|
+
* This is what lets a run list be paginated at all: `listRuns` can return 100 rows while the chips
|
|
1039
|
+
* still say how many of the 9,000 are failed.
|
|
1040
|
+
*
|
|
1041
|
+
* Cells with a zero count are simply absent. Optional: a store that omits it still works — callers
|
|
1042
|
+
* fall back to counting a {@link listRuns} result, which is correct but unbounded.
|
|
1043
|
+
*/
|
|
1044
|
+
runFacets?(query: RunFacetQuery): Promise<RunFacetRow[]>;
|
|
1035
1045
|
listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
|
|
1036
1046
|
/**
|
|
1037
1047
|
* The LATEST checkpoint for `runId` whose `name` equals `name` exactly (highest `seq` wins), or
|
|
@@ -1143,14 +1153,34 @@ interface RunQuery {
|
|
|
1143
1153
|
* Restrict to runs whose workflow was declared by this package (exact match against
|
|
1144
1154
|
* {@link WorkflowRun.origin}), ANDed with the other predicates.
|
|
1145
1155
|
*
|
|
1146
|
-
* A run with NO origin (unknown — see the field) matches no `origin`
|
|
1156
|
+
* A run with NO origin (unknown — see the field) matches no `origin` VALUE at all, so a UI facet
|
|
1147
1157
|
* built on this must keep an "all origins" option: filtering by any single package silently hides
|
|
1148
|
-
* every unattributed run, which reads to an operator as "those runs do not exist".
|
|
1158
|
+
* every unattributed run, which reads to an operator as "those runs do not exist". `null` selects
|
|
1159
|
+
* exactly that absent bucket (`origin IS NULL`), so a paginated console can offer an "unknown"
|
|
1160
|
+
* facet without having to hold every run in the browser to find them.
|
|
1149
1161
|
*/
|
|
1150
|
-
origin?: string | undefined;
|
|
1162
|
+
origin?: string | null | undefined;
|
|
1151
1163
|
limit?: number | undefined;
|
|
1152
1164
|
offset?: number | undefined;
|
|
1153
1165
|
}
|
|
1166
|
+
/**
|
|
1167
|
+
* The predicates a {@link RunFacetRow} count is taken over — a {@link RunQuery} minus the axes the
|
|
1168
|
+
* facets THEMSELVES report (`status`/`origin`) and minus paging. Keeping them out of the type is
|
|
1169
|
+
* what makes the counts answerable in one query: a console narrows by tag/tenant/attribute, and the
|
|
1170
|
+
* one call back tells it how the matching runs split across every status and every origin at once.
|
|
1171
|
+
*/
|
|
1172
|
+
type RunFacetQuery = Omit<RunQuery, 'status' | 'statuses' | 'origin' | 'limit' | 'offset'>;
|
|
1173
|
+
/**
|
|
1174
|
+
* One `(status, origin)` cell of {@link StateStore.runFacets} — a `GROUP BY` row, not a page of runs.
|
|
1175
|
+
* A console pivots these into its status chips and its origin chips, so both stay exact while the
|
|
1176
|
+
* list itself is paginated. `origin` is `null` for runs carrying none (see {@link WorkflowRun.origin});
|
|
1177
|
+
* that bucket is a real, countable answer here rather than the absence a value-match cannot express.
|
|
1178
|
+
*/
|
|
1179
|
+
interface RunFacetRow {
|
|
1180
|
+
status: RunStatus;
|
|
1181
|
+
origin: string | null;
|
|
1182
|
+
count: number;
|
|
1183
|
+
}
|
|
1154
1184
|
/** The transaction handle `StateStore.transaction` hands to its work callback. */
|
|
1155
1185
|
interface StoreTransaction {
|
|
1156
1186
|
/** The store-native transaction handle (TypeORM `EntityManager`, Prisma tx client, MikroORM `EntityManager`,
|
|
@@ -1214,6 +1244,9 @@ type RunRequestKind = {
|
|
|
1214
1244
|
} | {
|
|
1215
1245
|
kind: 'listRuns';
|
|
1216
1246
|
query: RunQuery;
|
|
1247
|
+
} | {
|
|
1248
|
+
kind: 'runFacets';
|
|
1249
|
+
query: RunFacetQuery;
|
|
1217
1250
|
} | {
|
|
1218
1251
|
kind: 'workerHealth';
|
|
1219
1252
|
} | {
|
|
@@ -4344,6 +4377,25 @@ declare class RemoteWorkflowExecutor implements WorkflowExecutor {
|
|
|
4344
4377
|
dispatch(run: WorkflowRun, history: HistoryEvent[], taskId: string, pendingSignals?: WorkflowTask['pendingSignals']): Promise<void>;
|
|
4345
4378
|
}
|
|
4346
4379
|
|
|
4380
|
+
/**
|
|
4381
|
+
* The origin a facet cell is filed under. An origin that is absent, null, or blank is all the same
|
|
4382
|
+
* thing to an operator — a run no package claims — so they collapse to `null` here. Without this the
|
|
4383
|
+
* "unknown" chip would count only one of those spellings while `origin IS NULL` paging returned
|
|
4384
|
+
* another, and the chip's number would not match the page it opens.
|
|
4385
|
+
*/
|
|
4386
|
+
declare function facetOrigin(origin: string | null | undefined): string | null;
|
|
4387
|
+
/**
|
|
4388
|
+
* Fold `(status, origin)` counts into one cell per pair, normalising origins via {@link facetOrigin}.
|
|
4389
|
+
* Store adapters group in SQL and pipe their rows through this, so every adapter — and the in-memory
|
|
4390
|
+
* store the tests run against — agrees on what lands in the unattributed bucket instead of each
|
|
4391
|
+
* collapsing blanks its own way.
|
|
4392
|
+
*/
|
|
4393
|
+
declare function mergeRunFacetRows(rows: readonly {
|
|
4394
|
+
status: RunStatus;
|
|
4395
|
+
origin: string | null | undefined;
|
|
4396
|
+
count: number;
|
|
4397
|
+
}[]): RunFacetRow[];
|
|
4398
|
+
|
|
4347
4399
|
/** A run as returned by the gateway's list — the durable run plus an optional {@link RunWaiting}
|
|
4348
4400
|
* descriptor the control plane resolves (what a suspended run is parked on), so the dashboard can
|
|
4349
4401
|
* name the wait in a list row without fetching each run's timeline. Additive: `waiting` is absent
|
|
@@ -4401,6 +4453,12 @@ declare abstract class RunGateway {
|
|
|
4401
4453
|
* parked on). The store-backed gateway resolves `waiting`; a proxy relays whatever the control
|
|
4402
4454
|
* plane sent. */
|
|
4403
4455
|
abstract listRuns(query: RunQuery): Promise<RunListItem[]>;
|
|
4456
|
+
/**
|
|
4457
|
+
* Counts of the runs matching `query`, grouped by `(status, origin)` — what a console's status and
|
|
4458
|
+
* origin chips display. Separate from {@link listRuns} precisely so the list can be PAGINATED: the
|
|
4459
|
+
* page bounds what is rendered, these counts stay whole-set exact. Zero-count cells are absent.
|
|
4460
|
+
*/
|
|
4461
|
+
abstract runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
|
|
4404
4462
|
/**
|
|
4405
4463
|
* Bulk-resolve {@link RunWaiting} for an arbitrary set of run ids — for a consumer with its OWN
|
|
4406
4464
|
* filtered/paginated run listing (so it isn't just `listRuns` under another name) that needs to know
|
|
@@ -4479,6 +4537,13 @@ interface PayloadCodec {
|
|
|
4479
4537
|
declare class CodecStateStore implements StateStore {
|
|
4480
4538
|
private readonly inner;
|
|
4481
4539
|
private readonly codec;
|
|
4540
|
+
/**
|
|
4541
|
+
* Forwarded verbatim — a facet cell counts `status`/`origin`, neither of which the codec touches
|
|
4542
|
+
* (it encodes payloads: input/output/error). Bound as a PROPERTY, and only when the inner store
|
|
4543
|
+
* actually aggregates, so `store.runFacets?.()` still reports absence through the wrapper instead
|
|
4544
|
+
* of resolving to a silently wrong empty result.
|
|
4545
|
+
*/
|
|
4546
|
+
readonly runFacets?: (query: RunFacetQuery) => Promise<RunFacetRow[]>;
|
|
4482
4547
|
constructor(inner: StateStore, codec: PayloadCodec);
|
|
4483
4548
|
private enc;
|
|
4484
4549
|
private dec;
|
|
@@ -4932,7 +4997,11 @@ declare class InMemoryStateStore implements StateStore {
|
|
|
4932
4997
|
* scan `strValue` rows. This is the in-memory analog of the SQL EXISTS on `durable_run_attributes`.
|
|
4933
4998
|
*/
|
|
4934
4999
|
private candidatesForFilter;
|
|
5000
|
+
/** Every run satisfying `query`'s predicates, unsorted and unpaged — the shared body of
|
|
5001
|
+
* {@link listRuns} (which then sorts + pages it) and {@link runFacets} (which groups it). */
|
|
5002
|
+
private matching;
|
|
4935
5003
|
listRuns(query: RunQuery): Promise<WorkflowRun[]>;
|
|
5004
|
+
runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
|
|
4936
5005
|
listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
|
|
4937
5006
|
getLatestCheckpointByName(runId: string, name: string): Promise<StepCheckpoint | undefined>;
|
|
4938
5007
|
listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]>;
|
|
@@ -4964,4 +5033,4 @@ declare class InMemoryTransport implements Transport, ControlPlane {
|
|
|
4964
5033
|
onControl(handler: (msg: ControlMessage) => void): void;
|
|
4965
5034
|
}
|
|
4966
5035
|
|
|
4967
|
-
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_PARTITION, 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, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NonDeterminismError, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDispatcher, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, type ScheduledWorkflow, type SearchAttributes, type SearchAttributesSchema, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, 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 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, announcementsOf, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, classifyWaiterToken, clearDurableExecutionWrappers, collectMetrics, controlPlaneDescriptor, coveredTokens, createStepLogger, currentStep, currentWorkflowCtx, debug, describeWorker, descriptorHash, error, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEventToken, isLegacyDescriptor, isWorkflowControlFlowSignal, log, matchesAttributes, missingCapabilities, negotiate, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, parseDuration, partitionOfToken, planDispatch, prevCronFireMs, readSearchAttributes, requiredCapabilities, resolveRouting, resolveRunWaiting, runDurableExecution, runInStepLogger, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, tenantGroup, useDurableExecution, warn, workflowName };
|
|
5036
|
+
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_PARTITION, 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, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NonDeterminismError, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, type ScheduledWorkflow, type SearchAttributes, type SearchAttributesSchema, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, 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 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, announcementsOf, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, classifyWaiterToken, clearDurableExecutionWrappers, collectMetrics, controlPlaneDescriptor, coveredTokens, createStepLogger, currentStep, currentWorkflowCtx, debug, describeWorker, descriptorHash, error, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEventToken, isLegacyDescriptor, isWorkflowControlFlowSignal, log, matchesAttributes, mergeRunFacetRows, missingCapabilities, negotiate, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, parseDuration, partitionOfToken, planDispatch, prevCronFireMs, readSearchAttributes, requiredCapabilities, resolveRouting, resolveRunWaiting, runDurableExecution, runInStepLogger, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, tenantGroup, useDurableExecution, warn, workflowName };
|
package/dist/index.js
CHANGED
|
@@ -1752,12 +1752,10 @@ var SingletonGate = class {
|
|
|
1752
1752
|
]
|
|
1753
1753
|
})).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime() || a.id.localeCompare(b.id));
|
|
1754
1754
|
for (const next of gated.slice(0, cfg.limit ?? 1)) {
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
}).catch(() => void 0);
|
|
1760
|
-
}
|
|
1755
|
+
await this.deps.store.updateRun(next.id, {
|
|
1756
|
+
wakeAt: this.deps.clock(),
|
|
1757
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1758
|
+
}).catch(() => void 0);
|
|
1761
1759
|
this.deps.dispatch(next.id);
|
|
1762
1760
|
}
|
|
1763
1761
|
}
|
|
@@ -5975,6 +5973,33 @@ var TERMINAL_RUN_STATUSES = [
|
|
|
5975
5973
|
"dead"
|
|
5976
5974
|
];
|
|
5977
5975
|
|
|
5976
|
+
// src/run-facets.ts
|
|
5977
|
+
function facetOrigin(origin) {
|
|
5978
|
+
return origin?.trim() ? origin : null;
|
|
5979
|
+
}
|
|
5980
|
+
__name(facetOrigin, "facetOrigin");
|
|
5981
|
+
function mergeRunFacetRows(rows) {
|
|
5982
|
+
const cells = /* @__PURE__ */ new Map();
|
|
5983
|
+
for (const row of rows) {
|
|
5984
|
+
const origin = facetOrigin(row.origin);
|
|
5985
|
+
const key = JSON.stringify([
|
|
5986
|
+
row.status,
|
|
5987
|
+
origin
|
|
5988
|
+
]);
|
|
5989
|
+
const cell = cells.get(key);
|
|
5990
|
+
if (cell) cell.count += row.count;
|
|
5991
|
+
else cells.set(key, {
|
|
5992
|
+
status: row.status,
|
|
5993
|
+
origin,
|
|
5994
|
+
count: row.count
|
|
5995
|
+
});
|
|
5996
|
+
}
|
|
5997
|
+
return [
|
|
5998
|
+
...cells.values()
|
|
5999
|
+
];
|
|
6000
|
+
}
|
|
6001
|
+
__name(mergeRunFacetRows, "mergeRunFacetRows");
|
|
6002
|
+
|
|
5978
6003
|
// src/run-gateway.ts
|
|
5979
6004
|
var RunGateway = class {
|
|
5980
6005
|
static {
|
|
@@ -5989,9 +6014,18 @@ var CodecStateStore = class {
|
|
|
5989
6014
|
}
|
|
5990
6015
|
inner;
|
|
5991
6016
|
codec;
|
|
6017
|
+
/**
|
|
6018
|
+
* Forwarded verbatim — a facet cell counts `status`/`origin`, neither of which the codec touches
|
|
6019
|
+
* (it encodes payloads: input/output/error). Bound as a PROPERTY, and only when the inner store
|
|
6020
|
+
* actually aggregates, so `store.runFacets?.()` still reports absence through the wrapper instead
|
|
6021
|
+
* of resolving to a silently wrong empty result.
|
|
6022
|
+
*/
|
|
6023
|
+
runFacets;
|
|
5992
6024
|
constructor(inner, codec) {
|
|
5993
6025
|
this.inner = inner;
|
|
5994
6026
|
this.codec = codec;
|
|
6027
|
+
const facets = inner.runFacets;
|
|
6028
|
+
if (facets) this.runFacets = (query) => facets.call(inner, query);
|
|
5995
6029
|
}
|
|
5996
6030
|
enc(v) {
|
|
5997
6031
|
return v === void 0 ? void 0 : this.codec.encode(v);
|
|
@@ -6689,7 +6723,9 @@ var InMemoryStateStore = class {
|
|
|
6689
6723
|
}
|
|
6690
6724
|
return out;
|
|
6691
6725
|
}
|
|
6692
|
-
|
|
6726
|
+
/** Every run satisfying `query`'s predicates, unsorted and unpaged — the shared body of
|
|
6727
|
+
* {@link listRuns} (which then sorts + pages it) and {@link runFacets} (which groups it). */
|
|
6728
|
+
matching(query) {
|
|
6693
6729
|
let runs = [
|
|
6694
6730
|
...this.runs.values()
|
|
6695
6731
|
];
|
|
@@ -6698,7 +6734,8 @@ var InMemoryStateStore = class {
|
|
|
6698
6734
|
if (query.statuses) runs = runs.filter((r) => query.statuses?.includes(r.status));
|
|
6699
6735
|
if (query.tag) runs = runs.filter((r) => r.tags?.includes(query.tag));
|
|
6700
6736
|
if (query.namespace !== void 0) runs = runs.filter((r) => r.namespace === query.namespace);
|
|
6701
|
-
if (query.origin
|
|
6737
|
+
if (query.origin === null) runs = runs.filter((r) => r.origin == null);
|
|
6738
|
+
else if (query.origin !== void 0) runs = runs.filter((r) => r.origin === query.origin);
|
|
6702
6739
|
if (query.attributes?.length) {
|
|
6703
6740
|
let candidates = null;
|
|
6704
6741
|
for (const f of query.attributes) {
|
|
@@ -6717,6 +6754,10 @@ var InMemoryStateStore = class {
|
|
|
6717
6754
|
this.lastAttributeCandidates = ids.size;
|
|
6718
6755
|
runs = runs.filter((r) => ids.has(r.id));
|
|
6719
6756
|
}
|
|
6757
|
+
return runs;
|
|
6758
|
+
}
|
|
6759
|
+
async listRuns(query) {
|
|
6760
|
+
const runs = this.matching(query);
|
|
6720
6761
|
runs.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
6721
6762
|
const offset = query.offset ?? 0;
|
|
6722
6763
|
const limit = query.limit ?? runs.length;
|
|
@@ -6724,6 +6765,13 @@ var InMemoryStateStore = class {
|
|
|
6724
6765
|
...r
|
|
6725
6766
|
}));
|
|
6726
6767
|
}
|
|
6768
|
+
async runFacets(query) {
|
|
6769
|
+
return mergeRunFacetRows(this.matching(query).map((run) => ({
|
|
6770
|
+
status: run.status,
|
|
6771
|
+
origin: run.origin,
|
|
6772
|
+
count: 1
|
|
6773
|
+
})));
|
|
6774
|
+
}
|
|
6727
6775
|
async listCheckpoints(runId) {
|
|
6728
6776
|
const rows = [
|
|
6729
6777
|
...this.checkpoints.values()
|
|
@@ -6868,6 +6916,7 @@ export {
|
|
|
6868
6916
|
eventNameOf,
|
|
6869
6917
|
eventPrefix,
|
|
6870
6918
|
eventToken,
|
|
6919
|
+
facetOrigin,
|
|
6871
6920
|
hasDurableExecutionWrappers,
|
|
6872
6921
|
heartbeatStatus,
|
|
6873
6922
|
indexWaitersByRun,
|
|
@@ -6877,6 +6926,7 @@ export {
|
|
|
6877
6926
|
isWorkflowControlFlowSignal,
|
|
6878
6927
|
log,
|
|
6879
6928
|
matchesAttributes,
|
|
6929
|
+
mergeRunFacetRows,
|
|
6880
6930
|
missingCapabilities,
|
|
6881
6931
|
negotiate,
|
|
6882
6932
|
normalizeAttributeRows,
|