@bratsos/workflow-engine 0.6.0 → 0.8.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/README.md +93 -0
- package/dist/{chunk-2MWO6UVR.js → chunk-NANAXHS5.js} +2 -2
- package/dist/chunk-NANAXHS5.js.map +1 -0
- package/dist/{chunk-DIADEUGZ.js → chunk-TWYPSP7P.js} +99 -7
- package/dist/chunk-TWYPSP7P.js.map +1 -0
- package/dist/{chunk-HKGZ2WHJ.js → chunk-WWK2SPN7.js} +16 -9
- package/dist/chunk-WWK2SPN7.js.map +1 -0
- package/dist/{chunk-HOGDFLCG.js → chunk-XPWAEYOO.js} +449 -59
- package/dist/chunk-XPWAEYOO.js.map +1 -0
- package/dist/{client-llB6XpHS.d.ts → client-YFKVt4p7.d.ts} +10 -21
- package/dist/client.d.ts +4 -4
- package/dist/client.js +1 -1
- package/dist/conventions/index.d.ts +114 -0
- package/dist/conventions/index.js +95 -0
- package/dist/conventions/index.js.map +1 -0
- package/dist/{events-D_P24UaY.d.ts → events-B3XPPu0c.d.ts} +23 -1
- package/dist/{index-sGgV8JNu.d.ts → index-CL0KmlyW.d.ts} +10 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +5 -5
- package/dist/{interface-DCdddCe0.d.ts → interface-BPz138Hf.d.ts} +110 -2
- package/dist/kernel/index.d.ts +6 -6
- package/dist/kernel/index.js +2 -2
- package/dist/kernel/testing/index.d.ts +3 -3
- package/dist/persistence/index.d.ts +2 -2
- package/dist/persistence/index.js +2 -2
- package/dist/persistence/prisma/index.d.ts +2 -2
- package/dist/persistence/prisma/index.js +2 -2
- package/dist/{plugins-Oyo_iu0l.d.ts → plugins-zT-aIcEZ.d.ts} +63 -4
- package/dist/{ports-ChGnJcn2.d.ts → ports-DUL4hlQr.d.ts} +11 -2
- package/dist/{stage-_7BKqqUG.d.ts → stage-WuK0mfrC.d.ts} +81 -1
- package/dist/testing/index.d.ts +8 -1
- package/dist/testing/index.js +88 -2
- package/dist/testing/index.js.map +1 -1
- package/package.json +6 -1
- package/skills/workflow-engine/SKILL.md +58 -1
- package/skills/workflow-engine/migrations/README.md +275 -0
- package/skills/workflow-engine/migrations/migrate-0.7-to-0.8.md +528 -0
- package/skills/workflow-engine/references/10-annotations.md +479 -0
- package/dist/chunk-2MWO6UVR.js.map +0 -1
- package/dist/chunk-DIADEUGZ.js.map +0 -1
- package/dist/chunk-HKGZ2WHJ.js.map +0 -1
- package/dist/chunk-HOGDFLCG.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { i as AnnotationActor } from './interface-BPz138Hf.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Core type definitions for Workflow System v2
|
|
@@ -83,6 +84,83 @@ type StageMode = "sync" | "async-batch";
|
|
|
83
84
|
* - Can suspend workflow for long-running batch operations
|
|
84
85
|
*/
|
|
85
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Single-attribute form options.
|
|
89
|
+
*
|
|
90
|
+
* The `actor` field accepts an `AnnotationActor` ({ kind?, id?, version? }).
|
|
91
|
+
* `payload` is a separate blob slot for non-queryable rich data.
|
|
92
|
+
* `idempotencyKey` opts the annotation into the unique constraint on
|
|
93
|
+
* `(workflowRunId, key, idempotencyKey)` so retries are deduped.
|
|
94
|
+
*/
|
|
95
|
+
interface AnnotateOpts {
|
|
96
|
+
actor?: AnnotationActor;
|
|
97
|
+
payload?: Record<string, unknown>;
|
|
98
|
+
idempotencyKey?: string;
|
|
99
|
+
/**
|
|
100
|
+
* If true, the engine writes an `annotation:created` outbox event in
|
|
101
|
+
* the same transaction as the annotation row. Useful for plugins or
|
|
102
|
+
* external systems (audit pipelines, SIEM, live dashboards) that
|
|
103
|
+
* want push notifications on provenance writes. Off by default.
|
|
104
|
+
*/
|
|
105
|
+
emitEvent?: boolean;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Batch form — multiple attributes share one envelope (actor / payload /
|
|
109
|
+
* idempotencyKey / emitEvent). Each attribute becomes one row in
|
|
110
|
+
* WorkflowAnnotation; if `emitEvent` is set, each row also emits its
|
|
111
|
+
* own `annotation:created` outbox event.
|
|
112
|
+
*/
|
|
113
|
+
interface AnnotateBatch {
|
|
114
|
+
attributes: Record<string, unknown>;
|
|
115
|
+
actor?: AnnotationActor;
|
|
116
|
+
payload?: Record<string, unknown>;
|
|
117
|
+
idempotencyKey?: string;
|
|
118
|
+
emitEvent?: boolean;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Stability level for a well-known annotation key, attached at definition
|
|
122
|
+
* time and surfaced to IDEs through the conventions module.
|
|
123
|
+
*
|
|
124
|
+
* Policy: once a key is `stable`, it is immutable. Renames and value-type
|
|
125
|
+
* changes must ship as new keys; the old key gets a `@deprecated` JSDoc
|
|
126
|
+
* tag. No env-var stability opt-in (we deliberately do not copy
|
|
127
|
+
* OpenTelemetry's `OTEL_SEMCONV_STABILITY_OPT_IN`).
|
|
128
|
+
*/
|
|
129
|
+
type Stability = "stable" | "experimental" | "deprecated";
|
|
130
|
+
/**
|
|
131
|
+
* Typed annotation key. The phantom `_valueType` parameter lets
|
|
132
|
+
* `ctx.annotate(key, value)` enforce that `value` matches `T` at compile
|
|
133
|
+
* time when the key was defined with `typedKey<T>(...)`. The marker is
|
|
134
|
+
* never set at runtime — only the `key` string is.
|
|
135
|
+
*/
|
|
136
|
+
interface TypedKey<T = unknown> {
|
|
137
|
+
readonly key: string;
|
|
138
|
+
readonly stability: Stability;
|
|
139
|
+
readonly description?: string;
|
|
140
|
+
/** Phantom — never populated. Used only for `T` inference. */
|
|
141
|
+
readonly _valueType?: T;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Overloaded callable supporting three forms:
|
|
145
|
+
*
|
|
146
|
+
* - **Typed key**: `ctx.annotate(Decision.outcome, "low")` — value type
|
|
147
|
+
* is inferred from the TypedKey, giving compile-time linkage between
|
|
148
|
+
* well-known keys and their expected value shapes.
|
|
149
|
+
* - **String key**: `ctx.annotate("custom.namespace.key", value)` —
|
|
150
|
+
* escape hatch for org-defined conventions.
|
|
151
|
+
* - **Batch**: `ctx.annotate({ attributes: {...}, actor?, ... })` —
|
|
152
|
+
* emit several related attributes sharing one envelope.
|
|
153
|
+
*
|
|
154
|
+
* All three return `void` from the caller's perspective; writes are
|
|
155
|
+
* buffered on the context and flushed inside the stage-completion
|
|
156
|
+
* transaction. `undefined` values are dropped (OTel pattern: callers can
|
|
157
|
+
* write `ctx.annotate("x.id", maybeId)` without guarding).
|
|
158
|
+
*/
|
|
159
|
+
interface AnnotateFn {
|
|
160
|
+
<T>(key: TypedKey<T>, value: T, opts?: AnnotateOpts): void;
|
|
161
|
+
(key: string, value: unknown, opts?: AnnotateOpts): void;
|
|
162
|
+
(args: AnnotateBatch): void;
|
|
163
|
+
}
|
|
86
164
|
interface StageContext<TInput, TConfig, TWorkflowContext = Record<string, unknown>> {
|
|
87
165
|
workflowRunId: string;
|
|
88
166
|
stageId: string;
|
|
@@ -96,6 +174,7 @@ interface StageContext<TInput, TConfig, TWorkflowContext = Record<string, unknow
|
|
|
96
174
|
onProgress: (update: ProgressUpdate) => void;
|
|
97
175
|
onLog: (level: LogLevel, message: string, meta?: Record<string, unknown>) => void;
|
|
98
176
|
log: (level: LogLevel, message: string, meta?: Record<string, unknown>) => void;
|
|
177
|
+
annotate: AnnotateFn;
|
|
99
178
|
storage: StageStorage;
|
|
100
179
|
workflowContext: Partial<TWorkflowContext>;
|
|
101
180
|
}
|
|
@@ -118,6 +197,7 @@ interface CheckCompletionContext<TConfig> {
|
|
|
118
197
|
config: TConfig;
|
|
119
198
|
onLog: (level: LogLevel, message: string, meta?: Record<string, unknown>) => void;
|
|
120
199
|
log: (level: LogLevel, message: string, meta?: Record<string, unknown>) => void;
|
|
200
|
+
annotate: AnnotateFn;
|
|
121
201
|
storage: StageStorage;
|
|
122
202
|
}
|
|
123
203
|
interface Stage<TInput extends z.ZodTypeAny, TOutput extends z.ZodTypeAny, TConfig extends z.ZodTypeAny, TWorkflowContext = Record<string, unknown>, TId extends string = string> {
|
|
@@ -141,4 +221,4 @@ interface Stage<TInput extends z.ZodTypeAny, TOutput extends z.ZodTypeAny, TConf
|
|
|
141
221
|
estimateCost?: (input: z.infer<TInput>, config: z.infer<TConfig>) => number;
|
|
142
222
|
}
|
|
143
223
|
|
|
144
|
-
export { type CheckCompletionContext as C, type LogLevel as L, type
|
|
224
|
+
export { type CheckCompletionContext as C, type LogLevel as L, type Stability as S, type TypedKey as T, type Stage as a, type StageResult as b, type StageContext as c, SuspendedStateSchema as d, type CompletionCheckResult as e };
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { k as AICallLogger, l as CreateAICallInput, m as AIHelperStats, n as AICallRecord, J as JobQueue, E as EnqueueJobInput, D as DequeueResult, o as JobRecord, p as JobStatus, q as WorkflowPersistence, C as CreateRunInput, W as WorkflowRunRecord, U as UpdateRunInput, r as WorkflowStatus, a as CreateStageInput, b as WorkflowStageRecord, c as UpsertStageInput, d as UpdateStageInput, s as WorkflowStageStatus, e as CreateLogInput, h as CreateOutboxEventInput, O as OutboxRecord, t as SaveArtifactInput, u as WorkflowArtifactRecord, f as CreateAnnotationInput, A as AnnotationFilters, g as WorkflowAnnotationRecord, v as WorkflowLogRecord } from '../interface-BPz138Hf.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* In-Memory AI Call Logger
|
|
@@ -185,6 +185,7 @@ declare class InMemoryWorkflowPersistence implements WorkflowPersistence {
|
|
|
185
185
|
private stages;
|
|
186
186
|
private logs;
|
|
187
187
|
private artifacts;
|
|
188
|
+
private annotations;
|
|
188
189
|
private outbox;
|
|
189
190
|
private idempotencyKeys;
|
|
190
191
|
private idempotencyInProgress;
|
|
@@ -240,6 +241,8 @@ declare class InMemoryWorkflowPersistence implements WorkflowPersistence {
|
|
|
240
241
|
deleteArtifact(runId: string, key: string): Promise<void>;
|
|
241
242
|
listArtifacts(runId: string): Promise<WorkflowArtifactRecord[]>;
|
|
242
243
|
getStageIdForArtifact(runId: string, stageId: string): Promise<string | null>;
|
|
244
|
+
appendAnnotations(inputs: CreateAnnotationInput[]): Promise<void>;
|
|
245
|
+
listAnnotations(workflowRunId: string, filters?: AnnotationFilters): Promise<WorkflowAnnotationRecord[]>;
|
|
243
246
|
saveStageOutput(runId: string, workflowType: string, stageId: string, output: unknown): Promise<string>;
|
|
244
247
|
/**
|
|
245
248
|
* Clear all data - useful between tests
|
|
@@ -261,6 +264,10 @@ declare class InMemoryWorkflowPersistence implements WorkflowPersistence {
|
|
|
261
264
|
* Get all artifacts for inspection
|
|
262
265
|
*/
|
|
263
266
|
getAllArtifacts(): WorkflowArtifactRecord[];
|
|
267
|
+
/**
|
|
268
|
+
* Get all annotations for inspection
|
|
269
|
+
*/
|
|
270
|
+
getAllAnnotations(): WorkflowAnnotationRecord[];
|
|
264
271
|
}
|
|
265
272
|
|
|
266
273
|
export { InMemoryAICallLogger, InMemoryJobQueue, InMemoryWorkflowPersistence };
|
package/dist/testing/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StaleVersionError } from '../chunk-
|
|
1
|
+
import { StaleVersionError } from '../chunk-NANAXHS5.js';
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
3
|
|
|
4
4
|
var InMemoryAICallLogger = class {
|
|
@@ -447,6 +447,7 @@ var InMemoryWorkflowPersistence = class {
|
|
|
447
447
|
stages = /* @__PURE__ */ new Map();
|
|
448
448
|
logs = /* @__PURE__ */ new Map();
|
|
449
449
|
artifacts = /* @__PURE__ */ new Map();
|
|
450
|
+
annotations = [];
|
|
450
451
|
outbox = [];
|
|
451
452
|
idempotencyKeys = /* @__PURE__ */ new Map();
|
|
452
453
|
idempotencyInProgress = /* @__PURE__ */ new Set();
|
|
@@ -487,7 +488,8 @@ var InMemoryWorkflowPersistence = class {
|
|
|
487
488
|
config: data.config ?? {},
|
|
488
489
|
totalCost: 0,
|
|
489
490
|
totalTokens: 0,
|
|
490
|
-
priority: data.priority ?? 5
|
|
491
|
+
priority: data.priority ?? 5,
|
|
492
|
+
metadata: data.metadata ?? null
|
|
491
493
|
};
|
|
492
494
|
this.runs.set(record.id, record);
|
|
493
495
|
return { ...record };
|
|
@@ -599,6 +601,7 @@ var InMemoryWorkflowPersistence = class {
|
|
|
599
601
|
stageName: data.stageName,
|
|
600
602
|
stageNumber: data.stageNumber,
|
|
601
603
|
executionGroup: data.executionGroup,
|
|
604
|
+
attempt: data.attempt ?? 0,
|
|
602
605
|
status: data.status ?? "PENDING",
|
|
603
606
|
startedAt: data.startedAt ?? null,
|
|
604
607
|
completedAt: null,
|
|
@@ -747,6 +750,11 @@ var InMemoryWorkflowPersistence = class {
|
|
|
747
750
|
if (stage) {
|
|
748
751
|
this.stages.delete(id);
|
|
749
752
|
this.stages.delete(this.stageKey(stage.workflowRunId, stage.stageId));
|
|
753
|
+
for (const annotation of this.annotations) {
|
|
754
|
+
if (annotation.workflowStageRecordId === id) {
|
|
755
|
+
annotation.workflowStageRecordId = null;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
750
758
|
}
|
|
751
759
|
}
|
|
752
760
|
// ============================================================================
|
|
@@ -894,6 +902,77 @@ var InMemoryWorkflowPersistence = class {
|
|
|
894
902
|
return stage?.id ?? null;
|
|
895
903
|
}
|
|
896
904
|
// ============================================================================
|
|
905
|
+
// WorkflowAnnotation Operations
|
|
906
|
+
// ============================================================================
|
|
907
|
+
async appendAnnotations(inputs) {
|
|
908
|
+
for (const input of inputs) {
|
|
909
|
+
if (input.idempotencyKey !== null && input.idempotencyKey !== void 0) {
|
|
910
|
+
const exists = this.annotations.some(
|
|
911
|
+
(a) => a.workflowRunId === input.workflowRunId && a.key === input.key && a.idempotencyKey === input.idempotencyKey
|
|
912
|
+
);
|
|
913
|
+
if (exists) continue;
|
|
914
|
+
}
|
|
915
|
+
const record = {
|
|
916
|
+
id: randomUUID(),
|
|
917
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
918
|
+
workflowRunId: input.workflowRunId,
|
|
919
|
+
workflowStageRecordId: input.workflowStageRecordId ?? null,
|
|
920
|
+
attempt: input.attempt ?? 0,
|
|
921
|
+
scope: input.scope,
|
|
922
|
+
scopeId: input.scopeId ?? null,
|
|
923
|
+
actorKind: input.actor?.kind ?? null,
|
|
924
|
+
actorId: input.actor?.id ?? null,
|
|
925
|
+
actorVersion: input.actor?.version ?? null,
|
|
926
|
+
key: input.key,
|
|
927
|
+
value: input.value,
|
|
928
|
+
payload: input.payload ?? null,
|
|
929
|
+
idempotencyKey: input.idempotencyKey ?? null
|
|
930
|
+
};
|
|
931
|
+
this.annotations.push(record);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
async listAnnotations(workflowRunId, filters = {}) {
|
|
935
|
+
let rows = this.annotations.filter(
|
|
936
|
+
(a) => a.workflowRunId === workflowRunId
|
|
937
|
+
);
|
|
938
|
+
if (filters.key !== void 0) {
|
|
939
|
+
rows = rows.filter((a) => a.key === filters.key);
|
|
940
|
+
} else if (filters.keyPrefix !== void 0) {
|
|
941
|
+
const prefix = filters.keyPrefix;
|
|
942
|
+
rows = rows.filter((a) => a.key.startsWith(prefix));
|
|
943
|
+
}
|
|
944
|
+
if (filters.scope !== void 0) {
|
|
945
|
+
rows = rows.filter((a) => a.scope === filters.scope);
|
|
946
|
+
}
|
|
947
|
+
if (filters.scopeId !== void 0) {
|
|
948
|
+
rows = rows.filter((a) => a.scopeId === filters.scopeId);
|
|
949
|
+
}
|
|
950
|
+
if (filters.actorId !== void 0) {
|
|
951
|
+
rows = rows.filter((a) => a.actorId === filters.actorId);
|
|
952
|
+
}
|
|
953
|
+
if (filters.actorKind !== void 0) {
|
|
954
|
+
rows = rows.filter((a) => a.actorKind === filters.actorKind);
|
|
955
|
+
}
|
|
956
|
+
if (filters.attempt !== void 0) {
|
|
957
|
+
rows = rows.filter((a) => a.attempt === filters.attempt);
|
|
958
|
+
}
|
|
959
|
+
if (filters.since !== void 0) {
|
|
960
|
+
const since = filters.since;
|
|
961
|
+
rows = rows.filter((a) => a.createdAt >= since);
|
|
962
|
+
}
|
|
963
|
+
if (filters.until !== void 0) {
|
|
964
|
+
const until = filters.until;
|
|
965
|
+
rows = rows.filter((a) => a.createdAt <= until);
|
|
966
|
+
}
|
|
967
|
+
rows.sort((a, b) => {
|
|
968
|
+
const cmp = a.createdAt.getTime() - b.createdAt.getTime();
|
|
969
|
+
if (cmp !== 0) return cmp;
|
|
970
|
+
return a.id.localeCompare(b.id);
|
|
971
|
+
});
|
|
972
|
+
const limit = filters.limit ?? 1e3;
|
|
973
|
+
return rows.slice(0, limit).map((a) => ({ ...a }));
|
|
974
|
+
}
|
|
975
|
+
// ============================================================================
|
|
897
976
|
// Stage Output Convenience Method
|
|
898
977
|
// ============================================================================
|
|
899
978
|
async saveStageOutput(runId, workflowType, stageId, output) {
|
|
@@ -920,6 +999,7 @@ var InMemoryWorkflowPersistence = class {
|
|
|
920
999
|
this.stages.clear();
|
|
921
1000
|
this.logs.clear();
|
|
922
1001
|
this.artifacts.clear();
|
|
1002
|
+
this.annotations = [];
|
|
923
1003
|
this.outbox = [];
|
|
924
1004
|
this.idempotencyKeys.clear();
|
|
925
1005
|
this.idempotencyInProgress.clear();
|
|
@@ -949,6 +1029,12 @@ var InMemoryWorkflowPersistence = class {
|
|
|
949
1029
|
getAllArtifacts() {
|
|
950
1030
|
return Array.from(this.artifacts.values()).map((a) => ({ ...a }));
|
|
951
1031
|
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Get all annotations for inspection
|
|
1034
|
+
*/
|
|
1035
|
+
getAllAnnotations() {
|
|
1036
|
+
return this.annotations.map((a) => ({ ...a }));
|
|
1037
|
+
}
|
|
952
1038
|
};
|
|
953
1039
|
|
|
954
1040
|
export { InMemoryAICallLogger, InMemoryJobQueue, InMemoryWorkflowPersistence };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/in-memory-ai-logger.ts","../../src/testing/in-memory-job-queue.ts","../../src/testing/in-memory-persistence.ts"],"names":["randomUUID"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * In-Memory AI Call Logger\n *\n * A complete in-memory implementation of AICallLogger for testing.\n * Tracks all AI calls with full cost/token tracking and topic-based aggregation.\n *\n * @example\n * ```typescript\n * import { InMemoryAICallLogger } from '@bratsos/workflow-engine/testing';\n *\n * const aiLogger = new InMemoryAICallLogger();\n * // Use in tests...\n * aiLogger.clear(); // Reset between tests\n * ```\n */\n\nimport { randomUUID } from \"crypto\";\nimport type {\n AICallLogger,\n AICallRecord,\n AIHelperStats,\n CreateAICallInput,\n} from \"../persistence/interface.js\";\n\nexport class InMemoryAICallLogger implements AICallLogger {\n private calls = new Map<string, AICallRecord>();\n private recordedBatches = new Set<string>();\n\n // ============================================================================\n // Core Operations\n // ============================================================================\n\n /**\n * Log a single AI call (fire and forget)\n */\n logCall(call: CreateAICallInput): void {\n const id = randomUUID();\n const record: AICallRecord = {\n id,\n createdAt: new Date(),\n topic: call.topic,\n callType: call.callType,\n modelKey: call.modelKey,\n modelId: call.modelId,\n prompt: call.prompt,\n response: call.response,\n inputTokens: call.inputTokens,\n outputTokens: call.outputTokens,\n cost: call.cost,\n metadata: call.metadata ?? null,\n };\n this.calls.set(id, record);\n }\n\n /**\n * Log batch results (for recording batch API results)\n */\n async logBatchResults(\n batchId: string,\n results: CreateAICallInput[],\n ): Promise<void> {\n // Mark batch as recorded\n this.recordedBatches.add(batchId);\n\n // Log each result\n for (const result of results) {\n this.logCall({\n ...result,\n metadata: {\n ...(result.metadata as Record<string, unknown> | undefined),\n batchId,\n },\n });\n }\n }\n\n /**\n * Get aggregated stats for a topic prefix\n */\n async getStats(topicPrefix: string): Promise<AIHelperStats> {\n const matchingCalls = Array.from(this.calls.values()).filter((call) =>\n call.topic.startsWith(topicPrefix),\n );\n\n const stats: AIHelperStats = {\n totalCalls: matchingCalls.length,\n totalInputTokens: 0,\n totalOutputTokens: 0,\n totalCost: 0,\n perModel: {},\n };\n\n for (const call of matchingCalls) {\n stats.totalInputTokens += call.inputTokens;\n stats.totalOutputTokens += call.outputTokens;\n stats.totalCost += call.cost;\n\n // Aggregate per model\n if (!stats.perModel[call.modelKey]) {\n stats.perModel[call.modelKey] = {\n calls: 0,\n inputTokens: 0,\n outputTokens: 0,\n cost: 0,\n };\n }\n stats.perModel[call.modelKey]!.calls++;\n stats.perModel[call.modelKey]!.inputTokens += call.inputTokens;\n stats.perModel[call.modelKey]!.outputTokens += call.outputTokens;\n stats.perModel[call.modelKey]!.cost += call.cost;\n }\n\n return stats;\n }\n\n /**\n * Check if batch results are already recorded\n */\n async isRecorded(batchId: string): Promise<boolean> {\n return this.recordedBatches.has(batchId);\n }\n\n // ============================================================================\n // Test Helpers\n // ============================================================================\n\n /**\n * Clear all data - useful between tests\n */\n clear(): void {\n this.calls.clear();\n this.recordedBatches.clear();\n }\n\n /**\n * Get all calls for inspection\n */\n getAllCalls(): AICallRecord[] {\n return Array.from(this.calls.values()).map((c) => ({ ...c }));\n }\n\n /**\n * Get calls by topic for inspection\n */\n getCallsByTopic(topic: string): AICallRecord[] {\n return Array.from(this.calls.values())\n .filter((c) => c.topic === topic)\n .map((c) => ({ ...c }));\n }\n\n /**\n * Get calls by topic prefix for inspection\n */\n getCallsByTopicPrefix(prefix: string): AICallRecord[] {\n return Array.from(this.calls.values())\n .filter((c) => c.topic.startsWith(prefix))\n .map((c) => ({ ...c }));\n }\n\n /**\n * Get calls by model for inspection\n */\n getCallsByModel(modelKey: string): AICallRecord[] {\n return Array.from(this.calls.values())\n .filter((c) => c.modelKey === modelKey)\n .map((c) => ({ ...c }));\n }\n\n /**\n * Get calls by call type for inspection\n */\n getCallsByType(callType: string): AICallRecord[] {\n return Array.from(this.calls.values())\n .filter((c) => c.callType === callType)\n .map((c) => ({ ...c }));\n }\n\n /**\n * Get total cost across all calls\n */\n getTotalCost(): number {\n let total = 0;\n for (const call of this.calls.values()) {\n total += call.cost;\n }\n return total;\n }\n\n /**\n * Get total tokens across all calls\n */\n getTotalTokens(): { input: number; output: number } {\n let input = 0;\n let output = 0;\n for (const call of this.calls.values()) {\n input += call.inputTokens;\n output += call.outputTokens;\n }\n return { input, output };\n }\n\n /**\n * Get call count\n */\n getCallCount(): number {\n return this.calls.size;\n }\n\n /**\n * Get all recorded batch IDs\n */\n getRecordedBatchIds(): string[] {\n return Array.from(this.recordedBatches);\n }\n\n /**\n * Get the last call made (useful for assertions)\n */\n getLastCall(): AICallRecord | null {\n const calls = Array.from(this.calls.values());\n if (calls.length === 0) return null;\n\n // Sort by createdAt descending\n calls.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n return { ...calls[0]! };\n }\n\n /**\n * Assert a call was made with specific properties\n */\n hasCallMatching(predicate: (call: AICallRecord) => boolean): boolean {\n return Array.from(this.calls.values()).some(predicate);\n }\n}\n","/**\n * In-Memory Job Queue\n *\n * A complete in-memory implementation of JobQueue for testing.\n * Supports priority ordering, locking, and stale job recovery.\n *\n * @example\n * ```typescript\n * import { InMemoryJobQueue } from '@bratsos/workflow-engine/testing';\n *\n * const jobQueue = new InMemoryJobQueue();\n * // Use in tests...\n * jobQueue.clear(); // Reset between tests\n * ```\n */\n\nimport { randomUUID } from \"crypto\";\nimport type {\n DequeueResult,\n EnqueueJobInput,\n JobQueue,\n JobRecord,\n JobStatus,\n} from \"../persistence/interface.js\";\n\nexport class InMemoryJobQueue implements JobQueue {\n private jobs = new Map<string, JobRecord>();\n private workerId: string;\n private defaultMaxAttempts = 3;\n\n constructor(workerId?: string) {\n this.workerId = workerId ?? `worker-${randomUUID().slice(0, 8)}`;\n }\n\n // ============================================================================\n // Core Operations\n // ============================================================================\n\n async enqueue(options: EnqueueJobInput): Promise<string> {\n const now = new Date();\n const id = randomUUID();\n\n const job: JobRecord = {\n id,\n createdAt: now,\n updatedAt: now,\n workflowRunId: options.workflowRunId,\n workflowId: options.workflowId,\n stageId: options.stageId,\n status: \"PENDING\",\n priority: options.priority ?? 5,\n workerId: null,\n lockedAt: null,\n startedAt: null,\n completedAt: null,\n attempt: 0,\n maxAttempts: this.defaultMaxAttempts,\n lastError: null,\n nextPollAt: options.scheduledFor ?? null,\n payload: options.payload ?? {},\n };\n\n this.jobs.set(id, job);\n return id;\n }\n\n async enqueueParallel(jobs: EnqueueJobInput[]): Promise<string[]> {\n const ids: string[] = [];\n for (const job of jobs) {\n const id = await this.enqueue(job);\n ids.push(id);\n }\n return ids;\n }\n\n async dequeue(): Promise<DequeueResult | null> {\n // Find the highest priority PENDING job\n const now = new Date();\n const pendingJobs = Array.from(this.jobs.values())\n .filter(\n (j) =>\n j.status === \"PENDING\" &&\n (j.nextPollAt === null || j.nextPollAt <= now),\n )\n .sort((a, b) => {\n // Higher priority first\n if (b.priority !== a.priority) {\n return b.priority - a.priority;\n }\n // Earlier creation first (FIFO for same priority)\n return a.createdAt.getTime() - b.createdAt.getTime();\n });\n\n if (pendingJobs.length === 0) {\n return null;\n }\n\n const job = pendingJobs[0]!;\n\n // Lock the job and increment attempt (matches Prisma dequeue semantics)\n const newAttempt = job.attempt + 1;\n const updated: JobRecord = {\n ...job,\n status: \"RUNNING\",\n workerId: this.workerId,\n lockedAt: now,\n startedAt: now,\n updatedAt: now,\n attempt: newAttempt,\n };\n this.jobs.set(job.id, updated);\n\n return {\n jobId: job.id,\n workflowRunId: job.workflowRunId,\n workflowId: job.workflowId,\n stageId: job.stageId,\n priority: job.priority,\n attempt: newAttempt,\n maxAttempts: job.maxAttempts,\n payload: job.payload,\n };\n }\n\n async complete(jobId: string): Promise<void> {\n const job = this.jobs.get(jobId);\n if (!job) {\n throw new Error(`Job not found: ${jobId}`);\n }\n\n const now = new Date();\n const updated: JobRecord = {\n ...job,\n status: \"COMPLETED\",\n completedAt: now,\n updatedAt: now,\n };\n this.jobs.set(jobId, updated);\n }\n\n async suspend(jobId: string, nextPollAt: Date): Promise<void> {\n const job = this.jobs.get(jobId);\n if (!job) {\n throw new Error(`Job not found: ${jobId}`);\n }\n\n const updated: JobRecord = {\n ...job,\n status: \"SUSPENDED\",\n nextPollAt,\n workerId: null,\n lockedAt: null,\n updatedAt: new Date(),\n };\n this.jobs.set(jobId, updated);\n }\n\n async fail(\n jobId: string,\n error: string,\n shouldRetry: boolean = true,\n ): Promise<void> {\n const job = this.jobs.get(jobId);\n if (!job) {\n throw new Error(`Job not found: ${jobId}`);\n }\n\n const now = new Date();\n\n if (shouldRetry && job.attempt < job.maxAttempts) {\n // Retry: move back to PENDING (attempt was already incremented during dequeue)\n const updated: JobRecord = {\n ...job,\n status: \"PENDING\",\n lastError: error,\n workerId: null,\n lockedAt: null,\n updatedAt: now,\n };\n this.jobs.set(jobId, updated);\n } else {\n // No more retries: mark as FAILED\n const updated: JobRecord = {\n ...job,\n status: \"FAILED\",\n lastError: error,\n completedAt: now,\n updatedAt: now,\n };\n this.jobs.set(jobId, updated);\n }\n }\n\n async getSuspendedJobsReadyToPoll(): Promise<\n Array<{ jobId: string; stageId: string; workflowRunId: string }>\n > {\n const now = new Date();\n return Array.from(this.jobs.values())\n .filter(\n (j) => j.status === \"SUSPENDED\" && j.nextPollAt && j.nextPollAt <= now,\n )\n .map((j) => ({\n jobId: j.id,\n stageId: j.stageId,\n workflowRunId: j.workflowRunId,\n }));\n }\n\n async releaseStaleJobs(staleThresholdMs: number = 60000): Promise<number> {\n const now = new Date();\n const threshold = new Date(now.getTime() - staleThresholdMs);\n let released = 0;\n\n for (const job of this.jobs.values()) {\n if (\n job.status === \"RUNNING\" &&\n job.lockedAt &&\n job.lockedAt < threshold\n ) {\n // Release the stale lock\n const updated: JobRecord = {\n ...job,\n status: \"PENDING\",\n workerId: null,\n lockedAt: null,\n updatedAt: now,\n };\n this.jobs.set(job.id, updated);\n released++;\n }\n }\n\n return released;\n }\n\n async cancelByRun(workflowRunId: string): Promise<number> {\n const now = new Date();\n let count = 0;\n for (const job of this.jobs.values()) {\n if (\n job.workflowRunId === workflowRunId &&\n (job.status === \"PENDING\" || job.status === \"SUSPENDED\")\n ) {\n const updated: JobRecord = {\n ...job,\n status: \"CANCELLED\",\n completedAt: now,\n updatedAt: now,\n };\n this.jobs.set(job.id, updated);\n count++;\n }\n }\n return count;\n }\n\n // ============================================================================\n // Test Helpers\n // ============================================================================\n\n /**\n * Clear all jobs - useful between tests\n */\n clear(): void {\n this.jobs.clear();\n }\n\n /**\n * Get all jobs for inspection\n */\n getAllJobs(): JobRecord[] {\n return Array.from(this.jobs.values()).map((j) => ({ ...j }));\n }\n\n /**\n * Get jobs by status for inspection\n */\n getJobsByStatus(status: JobStatus): JobRecord[] {\n return Array.from(this.jobs.values())\n .filter((j) => j.status === status)\n .map((j) => ({ ...j }));\n }\n\n /**\n * Get a specific job by ID\n */\n getJob(jobId: string): JobRecord | null {\n const job = this.jobs.get(jobId);\n return job ? { ...job } : null;\n }\n\n /**\n * Get the worker ID for this queue instance\n */\n getWorkerId(): string {\n return this.workerId;\n }\n\n /**\n * Set max attempts for new jobs\n */\n setDefaultMaxAttempts(maxAttempts: number): void {\n this.defaultMaxAttempts = maxAttempts;\n }\n\n /**\n * Simulate a worker crash by releasing a job's lock without completing it\n */\n simulateCrash(jobId: string): void {\n const job = this.jobs.get(jobId);\n if (job && job.status === \"RUNNING\") {\n // Don't change status - just leave it locked by the \"crashed\" worker\n // releaseStaleJobs() will clean it up\n }\n }\n\n /**\n * Move a suspended job back to pending (for manual resume testing)\n */\n resumeJob(jobId: string): void {\n const job = this.jobs.get(jobId);\n if (job && job.status === \"SUSPENDED\") {\n const updated: JobRecord = {\n ...job,\n status: \"PENDING\",\n nextPollAt: null,\n updatedAt: new Date(),\n };\n this.jobs.set(jobId, updated);\n }\n }\n\n /**\n * Set lockedAt for testing stale job scenarios\n */\n setJobLockedAt(jobId: string, lockedAt: Date): void {\n const job = this.jobs.get(jobId);\n if (job) {\n const updated: JobRecord = {\n ...job,\n lockedAt,\n };\n this.jobs.set(jobId, updated);\n }\n }\n\n /**\n * Set nextPollAt for testing suspended job polling\n */\n setJobNextPollAt(jobId: string, nextPollAt: Date | null): void {\n const job = this.jobs.get(jobId);\n if (job) {\n const updated: JobRecord = {\n ...job,\n nextPollAt,\n };\n this.jobs.set(jobId, updated);\n }\n }\n}\n","/**\n * In-Memory Workflow Persistence\n *\n * A complete in-memory implementation of WorkflowPersistence for testing.\n * All data is stored in Maps and lost when the instance is garbage collected.\n *\n * @example\n * ```typescript\n * import { InMemoryWorkflowPersistence } from '@bratsos/workflow-engine/testing';\n *\n * const persistence = new InMemoryWorkflowPersistence();\n * // Use in tests...\n * persistence.clear(); // Reset between tests\n * ```\n */\n\nimport { randomUUID } from \"crypto\";\nimport {\n type CreateLogInput,\n type CreateOutboxEventInput,\n type CreateRunInput,\n type CreateStageInput,\n type IdempotencyRecord,\n type OutboxRecord,\n type SaveArtifactInput,\n StaleVersionError,\n type UpdateRunInput,\n type UpdateStageInput,\n type UpsertStageInput,\n type WorkflowArtifactRecord,\n type WorkflowLogRecord,\n type WorkflowPersistence,\n type WorkflowRunRecord,\n type WorkflowStageRecord,\n type WorkflowStageStatus,\n type WorkflowStatus,\n} from \"../persistence/interface.js\";\n\nexport class InMemoryWorkflowPersistence implements WorkflowPersistence {\n private runs = new Map<string, WorkflowRunRecord>();\n private stages = new Map<string, WorkflowStageRecord>();\n private logs = new Map<string, WorkflowLogRecord>();\n private artifacts = new Map<string, WorkflowArtifactRecord>();\n private outbox: OutboxRecord[] = [];\n private idempotencyKeys = new Map<string, IdempotencyRecord>();\n private idempotencyInProgress = new Set<string>();\n private outboxSequences = new Map<string, number>();\n\n // Helper to generate composite keys for stages\n private stageKey(runId: string, stageId: string): string {\n return `${runId}:${stageId}`;\n }\n\n // Helper to generate composite keys for artifacts\n private artifactKey(runId: string, key: string): string {\n return `${runId}:${key}`;\n }\n\n private idempotencyCompositeKey(commandType: string, key: string): string {\n return `${commandType}:${key}`;\n }\n\n async withTransaction<T>(\n fn: (tx: WorkflowPersistence) => Promise<T>,\n ): Promise<T> {\n return fn(this);\n }\n\n // ============================================================================\n // WorkflowRun Operations\n // ============================================================================\n\n async createRun(data: CreateRunInput): Promise<WorkflowRunRecord> {\n const now = new Date();\n const record: WorkflowRunRecord = {\n id: data.id ?? randomUUID(),\n createdAt: now,\n updatedAt: now,\n version: 1,\n workflowId: data.workflowId,\n workflowName: data.workflowName,\n workflowType: data.workflowType,\n status: \"PENDING\",\n startedAt: null,\n completedAt: null,\n duration: null,\n input: data.input,\n output: null,\n config: data.config ?? {},\n totalCost: 0,\n totalTokens: 0,\n priority: data.priority ?? 5,\n };\n this.runs.set(record.id, record);\n return { ...record };\n }\n\n async updateRun(id: string, data: UpdateRunInput): Promise<void> {\n const run = this.runs.get(id);\n if (!run) {\n throw new Error(`WorkflowRun not found: ${id}`);\n }\n\n if (\n data.expectedVersion !== undefined &&\n run.version !== data.expectedVersion\n ) {\n throw new StaleVersionError(\n \"WorkflowRun\",\n id,\n data.expectedVersion,\n run.version,\n );\n }\n\n const { expectedVersion: _, ...rest } = data;\n const updated: WorkflowRunRecord = {\n ...run,\n ...rest,\n updatedAt: new Date(),\n version: run.version + 1,\n };\n this.runs.set(id, updated);\n }\n\n async getRun(id: string): Promise<WorkflowRunRecord | null> {\n const run = this.runs.get(id);\n return run ? { ...run } : null;\n }\n\n async getRunStatus(id: string): Promise<WorkflowStatus | null> {\n const run = this.runs.get(id);\n return run?.status ?? null;\n }\n\n async getRunsByStatus(status: WorkflowStatus): Promise<WorkflowRunRecord[]> {\n return Array.from(this.runs.values())\n .filter((run) => run.status === status)\n .map((run) => ({ ...run }));\n }\n\n async getStuckRuns(stuckSince: Date): Promise<WorkflowRunRecord[]> {\n const runningRuns = await this.getRunsByStatus(\"RUNNING\");\n return runningRuns.filter((run) => {\n // Find all stages for this run (deduplicate by ID since stages are stored with composite keys)\n const seenIds = new Set<string>();\n const stages = Array.from(this.stages.values()).filter((s) => {\n if (s.workflowRunId !== run.id) return false;\n if (seenIds.has(s.id)) return false;\n seenIds.add(s.id);\n return true;\n });\n const lastStageUpdate = stages.reduce(\n (max, s) => (s.updatedAt > max ? s.updatedAt : max),\n new Date(0),\n );\n const lastActivity =\n run.updatedAt > lastStageUpdate ? run.updatedAt : lastStageUpdate;\n return lastActivity <= stuckSince;\n });\n }\n\n async claimPendingRun(id: string): Promise<boolean> {\n const run = this.runs.get(id);\n if (!run || run.status !== \"PENDING\") {\n return false;\n }\n\n // Atomically update status to RUNNING\n const updated: WorkflowRunRecord = {\n ...run,\n status: \"RUNNING\",\n startedAt: new Date(),\n updatedAt: new Date(),\n version: run.version + 1,\n };\n this.runs.set(id, updated);\n return true;\n }\n\n async claimNextPendingRun(): Promise<WorkflowRunRecord | null> {\n // Find all pending runs\n const pendingRuns = Array.from(this.runs.values())\n .filter((run) => run.status === \"PENDING\")\n // Sort by priority (highest first), then by createdAt (oldest first - FIFO)\n .sort((a, b) => {\n if (a.priority !== b.priority) {\n return b.priority - a.priority; // Higher priority first\n }\n return a.createdAt.getTime() - b.createdAt.getTime(); // Oldest first\n });\n\n if (pendingRuns.length === 0) {\n return null;\n }\n\n // Get the first one and atomically claim it\n const runToClaim = pendingRuns[0];\n\n // Double-check it's still pending (simulates FOR UPDATE SKIP LOCKED behavior)\n const currentRun = this.runs.get(runToClaim.id);\n if (!currentRun || currentRun.status !== \"PENDING\") {\n // Another worker claimed it between our query and now\n // In real FOR UPDATE SKIP LOCKED, this row would be skipped\n // Try the next one recursively\n return this.claimNextPendingRun();\n }\n\n // Atomically update status to RUNNING\n const claimed: WorkflowRunRecord = {\n ...currentRun,\n status: \"RUNNING\",\n startedAt: new Date(),\n updatedAt: new Date(),\n version: currentRun.version + 1,\n };\n this.runs.set(claimed.id, claimed);\n\n return { ...claimed };\n }\n\n // ============================================================================\n // WorkflowStage Operations\n // ============================================================================\n\n async createStage(data: CreateStageInput): Promise<WorkflowStageRecord> {\n const now = new Date();\n const id = randomUUID();\n const record: WorkflowStageRecord = {\n id,\n createdAt: now,\n updatedAt: now,\n version: 1,\n workflowRunId: data.workflowRunId,\n stageId: data.stageId,\n stageName: data.stageName,\n stageNumber: data.stageNumber,\n executionGroup: data.executionGroup,\n status: data.status ?? \"PENDING\",\n startedAt: data.startedAt ?? null,\n completedAt: null,\n duration: null,\n inputData: data.inputData ?? null,\n outputData: null,\n config: data.config ?? null,\n suspendedState: null,\n resumeData: null,\n nextPollAt: null,\n pollInterval: null,\n maxWaitUntil: null,\n metrics: null,\n embeddingInfo: null,\n errorMessage: null,\n };\n\n this.stages.set(id, record);\n // Also index by composite key for lookups\n this.stages.set(this.stageKey(data.workflowRunId, data.stageId), record);\n return { ...record };\n }\n\n async upsertStage(data: UpsertStageInput): Promise<WorkflowStageRecord> {\n const key = this.stageKey(data.workflowRunId, data.stageId);\n const existing = this.stages.get(key);\n\n if (existing) {\n const updated: WorkflowStageRecord = {\n ...existing,\n ...data.update,\n updatedAt: new Date(),\n version: existing.version + 1,\n };\n this.stages.set(existing.id, updated);\n this.stages.set(key, updated);\n return { ...updated };\n } else {\n return this.createStage(data.create);\n }\n }\n\n async updateStage(id: string, data: UpdateStageInput): Promise<void> {\n const stage = this.stages.get(id);\n if (!stage) {\n throw new Error(`WorkflowStage not found: ${id}`);\n }\n\n if (\n data.expectedVersion !== undefined &&\n stage.version !== data.expectedVersion\n ) {\n throw new StaleVersionError(\n \"WorkflowStage\",\n id,\n data.expectedVersion,\n stage.version,\n );\n }\n\n const { expectedVersion: _, ...rest } = data;\n const updated: WorkflowStageRecord = {\n ...stage,\n ...rest,\n updatedAt: new Date(),\n version: stage.version + 1,\n };\n this.stages.set(id, updated);\n this.stages.set(this.stageKey(stage.workflowRunId, stage.stageId), updated);\n }\n\n async updateStageByRunAndStageId(\n workflowRunId: string,\n stageId: string,\n data: UpdateStageInput,\n ): Promise<void> {\n const key = this.stageKey(workflowRunId, stageId);\n const stage = this.stages.get(key);\n if (!stage) {\n throw new Error(`WorkflowStage not found: ${workflowRunId}/${stageId}`);\n }\n\n if (\n data.expectedVersion !== undefined &&\n stage.version !== data.expectedVersion\n ) {\n throw new StaleVersionError(\n \"WorkflowStage\",\n `${workflowRunId}/${stageId}`,\n data.expectedVersion,\n stage.version,\n );\n }\n\n const { expectedVersion: _, ...rest } = data;\n const updated: WorkflowStageRecord = {\n ...stage,\n ...rest,\n updatedAt: new Date(),\n version: stage.version + 1,\n };\n this.stages.set(stage.id, updated);\n this.stages.set(key, updated);\n }\n\n async getStage(\n runId: string,\n stageId: string,\n ): Promise<WorkflowStageRecord | null> {\n const key = this.stageKey(runId, stageId);\n const stage = this.stages.get(key);\n return stage ? { ...stage } : null;\n }\n\n async getStageById(id: string): Promise<WorkflowStageRecord | null> {\n const stage = this.stages.get(id);\n return stage ? { ...stage } : null;\n }\n\n async getStagesByRun(\n runId: string,\n options?: { status?: WorkflowStageStatus; orderBy?: \"asc\" | \"desc\" },\n ): Promise<WorkflowStageRecord[]> {\n // Use a Set to track seen IDs and avoid duplicates from composite keys\n const seenIds = new Set<string>();\n let stages = Array.from(this.stages.values()).filter((s) => {\n if (s.workflowRunId !== runId) return false;\n if (seenIds.has(s.id)) return false;\n seenIds.add(s.id);\n return true;\n });\n\n if (options?.status) {\n stages = stages.filter((s) => s.status === options.status);\n }\n\n // Sort by stageNumber\n stages.sort((a, b) => {\n const diff = a.stageNumber - b.stageNumber;\n return options?.orderBy === \"desc\" ? -diff : diff;\n });\n\n return stages.map((s) => ({ ...s }));\n }\n\n async getSuspendedStages(beforeDate: Date): Promise<WorkflowStageRecord[]> {\n const seenIds = new Set<string>();\n return Array.from(this.stages.values())\n .filter((s) => {\n if (seenIds.has(s.id)) return false;\n seenIds.add(s.id);\n return (\n s.status === \"SUSPENDED\" &&\n s.nextPollAt !== null &&\n s.nextPollAt <= beforeDate\n );\n })\n .map((s) => ({ ...s }));\n }\n\n async getFirstSuspendedStageReadyToResume(\n runId: string,\n ): Promise<WorkflowStageRecord | null> {\n const stages = await this.getStagesByRun(runId, { status: \"SUSPENDED\" });\n const now = new Date();\n const ready = stages.find((s) => s.nextPollAt && s.nextPollAt <= now);\n return ready ?? null;\n }\n\n async getFirstFailedStage(\n runId: string,\n ): Promise<WorkflowStageRecord | null> {\n const stages = await this.getStagesByRun(runId, { status: \"FAILED\" });\n return stages[0] ?? null;\n }\n\n async getLastCompletedStage(\n runId: string,\n ): Promise<WorkflowStageRecord | null> {\n const stages = await this.getStagesByRun(runId, {\n status: \"COMPLETED\",\n orderBy: \"desc\",\n });\n return stages[0] ?? null;\n }\n\n async getLastCompletedStageBefore(\n runId: string,\n executionGroup: number,\n ): Promise<WorkflowStageRecord | null> {\n const stages = await this.getStagesByRun(runId, {\n status: \"COMPLETED\",\n orderBy: \"desc\",\n });\n const before = stages.filter((s) => s.executionGroup < executionGroup);\n return before[0] ?? null;\n }\n\n async deleteStage(id: string): Promise<void> {\n const stage = this.stages.get(id);\n if (stage) {\n this.stages.delete(id);\n this.stages.delete(this.stageKey(stage.workflowRunId, stage.stageId));\n }\n }\n\n // ============================================================================\n // WorkflowLog Operations\n // ============================================================================\n\n async createLog(data: CreateLogInput): Promise<void> {\n const record: WorkflowLogRecord = {\n id: randomUUID(),\n createdAt: new Date(),\n workflowRunId: data.workflowRunId ?? null,\n workflowStageId: data.workflowStageId ?? null,\n level: data.level,\n message: data.message,\n metadata: data.metadata ?? null,\n };\n this.logs.set(record.id, record);\n }\n\n // ============================================================================\n // Outbox Operations\n // ============================================================================\n\n async appendOutboxEvents(events: CreateOutboxEventInput[]): Promise<void> {\n for (const event of events) {\n const currentSeq = this.outboxSequences.get(event.workflowRunId) ?? 0;\n const nextSeq = currentSeq + 1;\n this.outboxSequences.set(event.workflowRunId, nextSeq);\n\n const record: OutboxRecord = {\n id: randomUUID(),\n workflowRunId: event.workflowRunId,\n sequence: nextSeq,\n eventType: event.eventType,\n payload: event.payload,\n causationId: event.causationId,\n occurredAt: event.occurredAt,\n publishedAt: null,\n retryCount: 0,\n dlqAt: null,\n };\n this.outbox.push(record);\n }\n }\n\n async getUnpublishedOutboxEvents(limit?: number): Promise<OutboxRecord[]> {\n const effectiveLimit = limit ?? 100;\n return this.outbox\n .filter((r) => r.publishedAt === null && r.dlqAt === null)\n .sort((a, b) => {\n const runCmp = a.workflowRunId.localeCompare(b.workflowRunId);\n if (runCmp !== 0) return runCmp;\n return a.sequence - b.sequence;\n })\n .slice(0, effectiveLimit)\n .map((r) => ({ ...r }));\n }\n\n async markOutboxEventsPublished(ids: string[]): Promise<void> {\n const idSet = new Set(ids);\n for (const record of this.outbox) {\n if (idSet.has(record.id)) {\n record.publishedAt = new Date();\n }\n }\n }\n\n async incrementOutboxRetryCount(id: string): Promise<number> {\n const record = this.outbox.find((r) => r.id === id);\n if (!record) throw new Error(`Outbox event not found: ${id}`);\n record.retryCount++;\n return record.retryCount;\n }\n\n async moveOutboxEventToDLQ(id: string): Promise<void> {\n const record = this.outbox.find((r) => r.id === id);\n if (!record) throw new Error(`Outbox event not found: ${id}`);\n record.dlqAt = new Date();\n }\n\n async replayDLQEvents(maxEvents: number): Promise<number> {\n const dlqEvents = this.outbox\n .filter((r) => r.dlqAt !== null)\n .slice(0, maxEvents);\n for (const record of dlqEvents) {\n record.dlqAt = null;\n record.retryCount = 0;\n }\n return dlqEvents.length;\n }\n\n // ============================================================================\n // Idempotency Operations\n // ============================================================================\n\n async acquireIdempotencyKey(\n key: string,\n commandType: string,\n ): Promise<\n | { status: \"acquired\" }\n | { status: \"replay\"; result: unknown }\n | { status: \"in_progress\" }\n > {\n const compositeKey = this.idempotencyCompositeKey(commandType, key);\n const record = this.idempotencyKeys.get(compositeKey);\n if (record) {\n return { status: \"replay\", result: record.result };\n }\n if (this.idempotencyInProgress.has(compositeKey)) {\n return { status: \"in_progress\" };\n }\n this.idempotencyInProgress.add(compositeKey);\n return { status: \"acquired\" };\n }\n\n async completeIdempotencyKey(\n key: string,\n commandType: string,\n result: unknown,\n ): Promise<void> {\n const compositeKey = this.idempotencyCompositeKey(commandType, key);\n this.idempotencyInProgress.delete(compositeKey);\n this.idempotencyKeys.set(compositeKey, {\n key,\n commandType,\n result,\n createdAt: new Date(),\n });\n }\n\n async releaseIdempotencyKey(key: string, commandType: string): Promise<void> {\n this.idempotencyInProgress.delete(\n this.idempotencyCompositeKey(commandType, key),\n );\n }\n\n // ============================================================================\n // WorkflowArtifact Operations\n // ============================================================================\n\n async saveArtifact(data: SaveArtifactInput): Promise<void> {\n const now = new Date();\n const key = this.artifactKey(data.workflowRunId, data.key);\n const existing = this.artifacts.get(key);\n\n const record: WorkflowArtifactRecord = {\n id: existing?.id ?? randomUUID(),\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n workflowRunId: data.workflowRunId,\n workflowStageId: data.workflowStageId ?? null,\n key: data.key,\n type: data.type,\n data: data.data,\n size: data.size,\n metadata: data.metadata ?? null,\n };\n this.artifacts.set(key, record);\n }\n\n async loadArtifact(runId: string, key: string): Promise<unknown> {\n const artifact = this.artifacts.get(this.artifactKey(runId, key));\n if (!artifact) {\n throw new Error(`Artifact not found: ${runId}/${key}`);\n }\n return artifact.data;\n }\n\n async hasArtifact(runId: string, key: string): Promise<boolean> {\n return this.artifacts.has(this.artifactKey(runId, key));\n }\n\n async deleteArtifact(runId: string, key: string): Promise<void> {\n this.artifacts.delete(this.artifactKey(runId, key));\n }\n\n async listArtifacts(runId: string): Promise<WorkflowArtifactRecord[]> {\n return Array.from(this.artifacts.values())\n .filter((a) => a.workflowRunId === runId)\n .map((a) => ({ ...a }));\n }\n\n async getStageIdForArtifact(\n runId: string,\n stageId: string,\n ): Promise<string | null> {\n const stage = await this.getStage(runId, stageId);\n return stage?.id ?? null;\n }\n\n // ============================================================================\n // Stage Output Convenience Method\n // ============================================================================\n\n async saveStageOutput(\n runId: string,\n workflowType: string,\n stageId: string,\n output: unknown,\n ): Promise<string> {\n const key = `workflow-v2/${workflowType}/${runId}/${stageId}/output.json`;\n const stageDbId = await this.getStageIdForArtifact(runId, stageId);\n\n await this.saveArtifact({\n workflowRunId: runId,\n workflowStageId: stageDbId ?? undefined,\n key,\n type: \"STAGE_OUTPUT\",\n data: output,\n size: JSON.stringify(output).length,\n });\n\n return key;\n }\n\n // ============================================================================\n // Test Helpers\n // ============================================================================\n\n /**\n * Clear all data - useful between tests\n */\n clear(): void {\n this.runs.clear();\n this.stages.clear();\n this.logs.clear();\n this.artifacts.clear();\n this.outbox = [];\n this.idempotencyKeys.clear();\n this.idempotencyInProgress.clear();\n this.outboxSequences.clear();\n }\n\n /**\n * Get all runs for inspection\n */\n getAllRuns(): WorkflowRunRecord[] {\n return Array.from(this.runs.values()).map((r) => ({ ...r }));\n }\n\n /**\n * Get all stages for inspection\n */\n getAllStages(): WorkflowStageRecord[] {\n // Filter out composite key duplicates\n return Array.from(this.stages.values())\n .filter((s) => this.stages.get(s.id) === s)\n .map((s) => ({ ...s }));\n }\n\n /**\n * Get all logs for inspection\n */\n getAllLogs(): WorkflowLogRecord[] {\n return Array.from(this.logs.values()).map((l) => ({ ...l }));\n }\n\n /**\n * Get all artifacts for inspection\n */\n getAllArtifacts(): WorkflowArtifactRecord[] {\n return Array.from(this.artifacts.values()).map((a) => ({ ...a }));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/testing/in-memory-ai-logger.ts","../../src/testing/in-memory-job-queue.ts","../../src/testing/in-memory-persistence.ts"],"names":["randomUUID"],"mappings":";;;AAwBO,IAAM,uBAAN,MAAmD;AAAA,EAChD,KAAA,uBAAY,GAAA,EAA0B;AAAA,EACtC,eAAA,uBAAsB,GAAA,EAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS1C,QAAQ,IAAA,EAA+B;AACrC,IAAA,MAAM,KAAK,UAAA,EAAW;AACtB,IAAA,MAAM,MAAA,GAAuB;AAAA,MAC3B,EAAA;AAAA,MACA,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,QAAA,EAAU,KAAK,QAAA,IAAY;AAAA,KAC7B;AACA,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,EAAA,EAAI,MAAM,CAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAA,CACJ,OAAA,EACA,OAAA,EACe;AAEf,IAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,OAAO,CAAA;AAGhC,IAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,MAAA,IAAA,CAAK,OAAA,CAAQ;AAAA,QACX,GAAG,MAAA;AAAA,QACH,QAAA,EAAU;AAAA,UACR,GAAI,MAAA,CAAO,QAAA;AAAA,UACX;AAAA;AACF,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,WAAA,EAA6C;AAC1D,IAAA,MAAM,gBAAgB,KAAA,CAAM,IAAA,CAAK,KAAK,KAAA,CAAM,MAAA,EAAQ,CAAA,CAAE,MAAA;AAAA,MAAO,CAAC,IAAA,KAC5D,IAAA,CAAK,KAAA,CAAM,WAAW,WAAW;AAAA,KACnC;AAEA,IAAA,MAAM,KAAA,GAAuB;AAAA,MAC3B,YAAY,aAAA,CAAc,MAAA;AAAA,MAC1B,gBAAA,EAAkB,CAAA;AAAA,MAClB,iBAAA,EAAmB,CAAA;AAAA,MACnB,SAAA,EAAW,CAAA;AAAA,MACX,UAAU;AAAC,KACb;AAEA,IAAA,KAAA,MAAW,QAAQ,aAAA,EAAe;AAChC,MAAA,KAAA,CAAM,oBAAoB,IAAA,CAAK,WAAA;AAC/B,MAAA,KAAA,CAAM,qBAAqB,IAAA,CAAK,YAAA;AAChC,MAAA,KAAA,CAAM,aAAa,IAAA,CAAK,IAAA;AAGxB,MAAA,IAAI,CAAC,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,QAAQ,CAAA,EAAG;AAClC,QAAA,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,QAAQ,CAAA,GAAI;AAAA,UAC9B,KAAA,EAAO,CAAA;AAAA,UACP,WAAA,EAAa,CAAA;AAAA,UACb,YAAA,EAAc,CAAA;AAAA,UACd,IAAA,EAAM;AAAA,SACR;AAAA,MACF;AACA,MAAA,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,QAAQ,CAAA,CAAG,KAAA,EAAA;AAC/B,MAAA,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,QAAQ,CAAA,CAAG,eAAe,IAAA,CAAK,WAAA;AACnD,MAAA,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,QAAQ,CAAA,CAAG,gBAAgB,IAAA,CAAK,YAAA;AACpD,MAAA,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,QAAQ,CAAA,CAAG,QAAQ,IAAA,CAAK,IAAA;AAAA,IAC9C;AAEA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,OAAA,EAAmC;AAClD,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,OAAO,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AACjB,IAAA,IAAA,CAAK,gBAAgB,KAAA,EAAM;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,WAAA,GAA8B;AAC5B,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,KAAA,EAA+B;AAC7C,IAAA,OAAO,KAAA,CAAM,KAAK,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,CAClC,OAAO,CAAC,CAAA,KAAM,EAAE,KAAA,KAAU,KAAK,EAC/B,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,MAAA,EAAgC;AACpD,IAAA,OAAO,KAAA,CAAM,KAAK,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,CAClC,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAM,UAAA,CAAW,MAAM,CAAC,CAAA,CACxC,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAE,CAAE,CAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,QAAA,EAAkC;AAChD,IAAA,OAAO,KAAA,CAAM,KAAK,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,CAClC,OAAO,CAAC,CAAA,KAAM,EAAE,QAAA,KAAa,QAAQ,EACrC,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,QAAA,EAAkC;AAC/C,IAAA,OAAO,KAAA,CAAM,KAAK,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,CAClC,OAAO,CAAC,CAAA,KAAM,EAAE,QAAA,KAAa,QAAQ,EACrC,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,GAAuB;AACrB,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,KAAA,CAAM,MAAA,EAAO,EAAG;AACtC,MAAA,KAAA,IAAS,IAAA,CAAK,IAAA;AAAA,IAChB;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,cAAA,GAAoD;AAClD,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,KAAA,CAAM,MAAA,EAAO,EAAG;AACtC,MAAA,KAAA,IAAS,IAAA,CAAK,WAAA;AACd,MAAA,MAAA,IAAU,IAAA,CAAK,YAAA;AAAA,IACjB;AACA,IAAA,OAAO,EAAE,OAAO,MAAA,EAAO;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,GAAuB;AACrB,IAAA,OAAO,KAAK,KAAA,CAAM,IAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAA,GAAgC;AAC9B,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,eAAe,CAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,WAAA,GAAmC;AACjC,IAAA,MAAM,QAAQ,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AAC5C,IAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAG/B,IAAA,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,SAAA,CAAU,OAAA,EAAQ,GAAI,CAAA,CAAE,SAAA,CAAU,OAAA,EAAS,CAAA;AAClE,IAAA,OAAO,EAAE,GAAG,KAAA,CAAM,CAAC,CAAA,EAAG;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,SAAA,EAAqD;AACnE,IAAA,OAAO,KAAA,CAAM,KAAK,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,CAAE,KAAK,SAAS,CAAA;AAAA,EACvD;AACF;AChNO,IAAM,mBAAN,MAA2C;AAAA,EACxC,IAAA,uBAAW,GAAA,EAAuB;AAAA,EAClC,QAAA;AAAA,EACA,kBAAA,GAAqB,CAAA;AAAA,EAE7B,YAAY,QAAA,EAAmB;AAC7B,IAAA,IAAA,CAAK,QAAA,GAAW,YAAY,CAAA,OAAA,EAAUA,UAAAA,GAAa,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,OAAA,EAA2C;AACvD,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,KAAKA,UAAAA,EAAW;AAEtB,IAAA,MAAM,GAAA,GAAiB;AAAA,MACrB,EAAA;AAAA,MACA,SAAA,EAAW,GAAA;AAAA,MACX,SAAA,EAAW,GAAA;AAAA,MACX,eAAe,OAAA,CAAQ,aAAA;AAAA,MACvB,YAAY,OAAA,CAAQ,UAAA;AAAA,MACpB,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,MAAA,EAAQ,SAAA;AAAA,MACR,QAAA,EAAU,QAAQ,QAAA,IAAY,CAAA;AAAA,MAC9B,QAAA,EAAU,IAAA;AAAA,MACV,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAa,IAAA;AAAA,MACb,OAAA,EAAS,CAAA;AAAA,MACT,aAAa,IAAA,CAAK,kBAAA;AAAA,MAClB,SAAA,EAAW,IAAA;AAAA,MACX,UAAA,EAAY,QAAQ,YAAA,IAAgB,IAAA;AAAA,MACpC,OAAA,EAAS,OAAA,CAAQ,OAAA,IAAW;AAAC,KAC/B;AAEA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,GAAG,CAAA;AACrB,IAAA,OAAO,EAAA;AAAA,EACT;AAAA,EAEA,MAAM,gBAAgB,IAAA,EAA4C;AAChE,IAAA,MAAM,MAAgB,EAAC;AACvB,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,MAAM,EAAA,GAAK,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACjC,MAAA,GAAA,CAAI,KAAK,EAAE,CAAA;AAAA,IACb;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AAAA,EAEA,MAAM,OAAA,GAAyC;AAE7C,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,cAAc,KAAA,CAAM,IAAA,CAAK,KAAK,IAAA,CAAK,MAAA,EAAQ,CAAA,CAC9C,MAAA;AAAA,MACC,CAAC,MACC,CAAA,CAAE,MAAA,KAAW,cACZ,CAAA,CAAE,UAAA,KAAe,IAAA,IAAQ,CAAA,CAAE,UAAA,IAAc,GAAA;AAAA,KAC9C,CACC,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM;AAEd,MAAA,IAAI,CAAA,CAAE,QAAA,KAAa,CAAA,CAAE,QAAA,EAAU;AAC7B,QAAA,OAAO,CAAA,CAAE,WAAW,CAAA,CAAE,QAAA;AAAA,MACxB;AAEA,MAAA,OAAO,EAAE,SAAA,CAAU,OAAA,EAAQ,GAAI,CAAA,CAAE,UAAU,OAAA,EAAQ;AAAA,IACrD,CAAC,CAAA;AAEH,IAAA,IAAI,WAAA,CAAY,WAAW,CAAA,EAAG;AAC5B,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,GAAA,GAAM,YAAY,CAAC,CAAA;AAGzB,IAAA,MAAM,UAAA,GAAa,IAAI,OAAA,GAAU,CAAA;AACjC,IAAA,MAAM,OAAA,GAAqB;AAAA,MACzB,GAAG,GAAA;AAAA,MACH,MAAA,EAAQ,SAAA;AAAA,MACR,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,QAAA,EAAU,GAAA;AAAA,MACV,SAAA,EAAW,GAAA;AAAA,MACX,SAAA,EAAW,GAAA;AAAA,MACX,OAAA,EAAS;AAAA,KACX;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,EAAA,EAAI,OAAO,CAAA;AAE7B,IAAA,OAAO;AAAA,MACL,OAAO,GAAA,CAAI,EAAA;AAAA,MACX,eAAe,GAAA,CAAI,aAAA;AAAA,MACnB,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,UAAU,GAAA,CAAI,QAAA;AAAA,MACd,OAAA,EAAS,UAAA;AAAA,MACT,aAAa,GAAA,CAAI,WAAA;AAAA,MACjB,SAAS,GAAA,CAAI;AAAA,KACf;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,KAAA,EAA8B;AAC3C,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,KAAK,CAAA,CAAE,CAAA;AAAA,IAC3C;AAEA,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,OAAA,GAAqB;AAAA,MACzB,GAAG,GAAA;AAAA,MACH,MAAA,EAAQ,WAAA;AAAA,MACR,WAAA,EAAa,GAAA;AAAA,MACb,SAAA,EAAW;AAAA,KACb;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAAA,EAC9B;AAAA,EAEA,MAAM,OAAA,CAAQ,KAAA,EAAe,UAAA,EAAiC;AAC5D,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,KAAK,CAAA,CAAE,CAAA;AAAA,IAC3C;AAEA,IAAA,MAAM,OAAA,GAAqB;AAAA,MACzB,GAAG,GAAA;AAAA,MACH,MAAA,EAAQ,WAAA;AAAA,MACR,UAAA;AAAA,MACA,QAAA,EAAU,IAAA;AAAA,MACV,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,sBAAe,IAAA;AAAK,KACtB;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAAA,EAC9B;AAAA,EAEA,MAAM,IAAA,CACJ,KAAA,EACA,KAAA,EACA,cAAuB,IAAA,EACR;AACf,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,KAAK,CAAA,CAAE,CAAA;AAAA,IAC3C;AAEA,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AAErB,IAAA,IAAI,WAAA,IAAe,GAAA,CAAI,OAAA,GAAU,GAAA,CAAI,WAAA,EAAa;AAEhD,MAAA,MAAM,OAAA,GAAqB;AAAA,QACzB,GAAG,GAAA;AAAA,QACH,MAAA,EAAQ,SAAA;AAAA,QACR,SAAA,EAAW,KAAA;AAAA,QACX,QAAA,EAAU,IAAA;AAAA,QACV,QAAA,EAAU,IAAA;AAAA,QACV,SAAA,EAAW;AAAA,OACb;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAAA,IAC9B,CAAA,MAAO;AAEL,MAAA,MAAM,OAAA,GAAqB;AAAA,QACzB,GAAG,GAAA;AAAA,QACH,MAAA,EAAQ,QAAA;AAAA,QACR,SAAA,EAAW,KAAA;AAAA,QACX,WAAA,EAAa,GAAA;AAAA,QACb,SAAA,EAAW;AAAA,OACb;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,MAAM,2BAAA,GAEJ;AACA,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,OAAO,MAAM,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,CAAA,CACjC,MAAA;AAAA,MACC,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,eAAe,CAAA,CAAE,UAAA,IAAc,EAAE,UAAA,IAAc;AAAA,KACrE,CACC,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MACX,OAAO,CAAA,CAAE,EAAA;AAAA,MACT,SAAS,CAAA,CAAE,OAAA;AAAA,MACX,eAAe,CAAA,CAAE;AAAA,KACnB,CAAE,CAAA;AAAA,EACN;AAAA,EAEA,MAAM,gBAAA,CAAiB,gBAAA,GAA2B,GAAA,EAAwB;AACxE,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,YAAY,IAAI,IAAA,CAAK,GAAA,CAAI,OAAA,KAAY,gBAAgB,CAAA;AAC3D,IAAA,IAAI,QAAA,GAAW,CAAA;AAEf,IAAA,KAAA,MAAW,GAAA,IAAO,IAAA,CAAK,IAAA,CAAK,MAAA,EAAO,EAAG;AACpC,MAAA,IACE,IAAI,MAAA,KAAW,SAAA,IACf,IAAI,QAAA,IACJ,GAAA,CAAI,WAAW,SAAA,EACf;AAEA,QAAA,MAAM,OAAA,GAAqB;AAAA,UACzB,GAAG,GAAA;AAAA,UACH,MAAA,EAAQ,SAAA;AAAA,UACR,QAAA,EAAU,IAAA;AAAA,UACV,QAAA,EAAU,IAAA;AAAA,UACV,SAAA,EAAW;AAAA,SACb;AACA,QAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,EAAA,EAAI,OAAO,CAAA;AAC7B,QAAA,QAAA,EAAA;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,aAAA,EAAwC;AACxD,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,KAAA,MAAW,GAAA,IAAO,IAAA,CAAK,IAAA,CAAK,MAAA,EAAO,EAAG;AACpC,MAAA,IACE,GAAA,CAAI,kBAAkB,aAAA,KACrB,GAAA,CAAI,WAAW,SAAA,IAAa,GAAA,CAAI,WAAW,WAAA,CAAA,EAC5C;AACA,QAAA,MAAM,OAAA,GAAqB;AAAA,UACzB,GAAG,GAAA;AAAA,UACH,MAAA,EAAQ,WAAA;AAAA,UACR,WAAA,EAAa,GAAA;AAAA,UACb,SAAA,EAAW;AAAA,SACb;AACA,QAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,EAAA,EAAI,OAAO,CAAA;AAC7B,QAAA,KAAA,EAAA;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,KAAK,KAAA,EAAM;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAA,GAA0B;AACxB,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,MAAA,EAAgC;AAC9C,IAAA,OAAO,KAAA,CAAM,KAAK,IAAA,CAAK,IAAA,CAAK,QAAQ,CAAA,CACjC,OAAO,CAAC,CAAA,KAAM,EAAE,MAAA,KAAW,MAAM,EACjC,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,KAAA,EAAiC;AACtC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,IAAA,OAAO,GAAA,GAAM,EAAE,GAAG,GAAA,EAAI,GAAI,IAAA;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,WAAA,GAAsB;AACpB,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,WAAA,EAA2B;AAC/C,IAAA,IAAA,CAAK,kBAAA,GAAqB,WAAA;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,KAAA,EAAqB;AACjC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,IAAA,IAAI,GAAA,IAAO,GAAA,CAAI,MAAA,KAAW,SAAA,EAAW;AAGrC,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,KAAA,EAAqB;AAC7B,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,IAAA,IAAI,GAAA,IAAO,GAAA,CAAI,MAAA,KAAW,WAAA,EAAa;AACrC,MAAA,MAAM,OAAA,GAAqB;AAAA,QACzB,GAAG,GAAA;AAAA,QACH,MAAA,EAAQ,SAAA;AAAA,QACR,UAAA,EAAY,IAAA;AAAA,QACZ,SAAA,sBAAe,IAAA;AAAK,OACtB;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAA,CAAe,OAAe,QAAA,EAAsB;AAClD,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,MAAM,OAAA,GAAqB;AAAA,QACzB,GAAG,GAAA;AAAA,QACH;AAAA,OACF;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAA,CAAiB,OAAe,UAAA,EAA+B;AAC7D,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,MAAM,OAAA,GAAqB;AAAA,QACzB,GAAG,GAAA;AAAA,QACH;AAAA,OACF;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAAA,IAC9B;AAAA,EACF;AACF;AC9TO,IAAM,8BAAN,MAAiE;AAAA,EAC9D,IAAA,uBAAW,GAAA,EAA+B;AAAA,EAC1C,MAAA,uBAAa,GAAA,EAAiC;AAAA,EAC9C,IAAA,uBAAW,GAAA,EAA+B;AAAA,EAC1C,SAAA,uBAAgB,GAAA,EAAoC;AAAA,EACpD,cAA0C,EAAC;AAAA,EAC3C,SAAyB,EAAC;AAAA,EAC1B,eAAA,uBAAsB,GAAA,EAA+B;AAAA,EACrD,qBAAA,uBAA4B,GAAA,EAAY;AAAA,EACxC,eAAA,uBAAsB,GAAA,EAAoB;AAAA;AAAA,EAG1C,QAAA,CAAS,OAAe,OAAA,EAAyB;AACvD,IAAA,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA;AAAA,EAC5B;AAAA;AAAA,EAGQ,WAAA,CAAY,OAAe,GAAA,EAAqB;AACtD,IAAA,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA;AAAA,EACxB;AAAA,EAEQ,uBAAA,CAAwB,aAAqB,GAAA,EAAqB;AACxE,IAAA,OAAO,CAAA,EAAG,WAAW,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA;AAAA,EAC9B;AAAA,EAEA,MAAM,gBACJ,EAAA,EACY;AACZ,IAAA,OAAO,GAAG,IAAI,CAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAAU,IAAA,EAAkD;AAChE,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,MAAA,GAA4B;AAAA,MAChC,EAAA,EAAI,IAAA,CAAK,EAAA,IAAMA,UAAAA,EAAW;AAAA,MAC1B,SAAA,EAAW,GAAA;AAAA,MACX,SAAA,EAAW,GAAA;AAAA,MACX,OAAA,EAAS,CAAA;AAAA,MACT,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAa,IAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,MAAA,EAAQ,IAAA;AAAA,MACR,MAAA,EAAQ,IAAA,CAAK,MAAA,IAAU,EAAC;AAAA,MACxB,SAAA,EAAW,CAAA;AAAA,MACX,WAAA,EAAa,CAAA;AAAA,MACb,QAAA,EAAU,KAAK,QAAA,IAAY,CAAA;AAAA,MAC3B,QAAA,EAAU,KAAK,QAAA,IAAY;AAAA,KAC7B;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,MAAM,CAAA;AAC/B,IAAA,OAAO,EAAE,GAAG,MAAA,EAAO;AAAA,EACrB;AAAA,EAEA,MAAM,SAAA,CAAU,EAAA,EAAY,IAAA,EAAqC;AAC/D,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA;AAC5B,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA0B,EAAE,CAAA,CAAE,CAAA;AAAA,IAChD;AAEA,IAAA,IACE,KAAK,eAAA,KAAoB,MAAA,IACzB,GAAA,CAAI,OAAA,KAAY,KAAK,eAAA,EACrB;AACA,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,aAAA;AAAA,QACA,EAAA;AAAA,QACA,IAAA,CAAK,eAAA;AAAA,QACL,GAAA,CAAI;AAAA,OACN;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,eAAA,EAAiB,CAAA,EAAG,GAAG,MAAK,GAAI,IAAA;AACxC,IAAA,MAAM,OAAA,GAA6B;AAAA,MACjC,GAAG,GAAA;AAAA,MACH,GAAG,IAAA;AAAA,MACH,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,OAAA,EAAS,IAAI,OAAA,GAAU;AAAA,KACzB;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,OAAO,CAAA;AAAA,EAC3B;AAAA,EAEA,MAAM,OAAO,EAAA,EAA+C;AAC1D,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA;AAC5B,IAAA,OAAO,GAAA,GAAM,EAAE,GAAG,GAAA,EAAI,GAAI,IAAA;AAAA,EAC5B;AAAA,EAEA,MAAM,aAAa,EAAA,EAA4C;AAC7D,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA;AAC5B,IAAA,OAAO,KAAK,MAAA,IAAU,IAAA;AAAA,EACxB;AAAA,EAEA,MAAM,gBAAgB,MAAA,EAAsD;AAC1E,IAAA,OAAO,KAAA,CAAM,KAAK,IAAA,CAAK,IAAA,CAAK,QAAQ,CAAA,CACjC,OAAO,CAAC,GAAA,KAAQ,IAAI,MAAA,KAAW,MAAM,EACrC,GAAA,CAAI,CAAC,SAAS,EAAE,GAAG,KAAI,CAAE,CAAA;AAAA,EAC9B;AAAA,EAEA,MAAM,aAAa,UAAA,EAAgD;AACjE,IAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,eAAA,CAAgB,SAAS,CAAA;AACxD,IAAA,OAAO,WAAA,CAAY,MAAA,CAAO,CAAC,GAAA,KAAQ;AAEjC,MAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,MAAA,MAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,QAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM;AAC5D,QAAA,IAAI,CAAA,CAAE,aAAA,KAAkB,GAAA,CAAI,EAAA,EAAI,OAAO,KAAA;AACvC,QAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,EAAE,GAAG,OAAO,KAAA;AAC9B,QAAA,OAAA,CAAQ,GAAA,CAAI,EAAE,EAAE,CAAA;AAChB,QAAA,OAAO,IAAA;AAAA,MACT,CAAC,CAAA;AACD,MAAA,MAAM,kBAAkB,MAAA,CAAO,MAAA;AAAA,QAC7B,CAAC,GAAA,EAAK,CAAA,KAAO,EAAE,SAAA,GAAY,GAAA,GAAM,EAAE,SAAA,GAAY,GAAA;AAAA,wBAC/C,IAAI,KAAK,CAAC;AAAA,OACZ;AACA,MAAA,MAAM,YAAA,GACJ,GAAA,CAAI,SAAA,GAAY,eAAA,GAAkB,IAAI,SAAA,GAAY,eAAA;AACpD,MAAA,OAAO,YAAA,IAAgB,UAAA;AAAA,IACzB,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,gBAAgB,EAAA,EAA8B;AAClD,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA;AAC5B,IAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,MAAA,KAAW,SAAA,EAAW;AACpC,MAAA,OAAO,KAAA;AAAA,IACT;AAGA,IAAA,MAAM,OAAA,GAA6B;AAAA,MACjC,GAAG,GAAA;AAAA,MACH,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,OAAA,EAAS,IAAI,OAAA,GAAU;AAAA,KACzB;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,OAAO,CAAA;AACzB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,MAAM,mBAAA,GAAyD;AAE7D,IAAA,MAAM,cAAc,KAAA,CAAM,IAAA,CAAK,KAAK,IAAA,CAAK,MAAA,EAAQ,CAAA,CAC9C,MAAA,CAAO,CAAC,GAAA,KAAQ,IAAI,MAAA,KAAW,SAAS,EAExC,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AACd,MAAA,IAAI,CAAA,CAAE,QAAA,KAAa,CAAA,CAAE,QAAA,EAAU;AAC7B,QAAA,OAAO,CAAA,CAAE,WAAW,CAAA,CAAE,QAAA;AAAA,MACxB;AACA,MAAA,OAAO,EAAE,SAAA,CAAU,OAAA,EAAQ,GAAI,CAAA,CAAE,UAAU,OAAA,EAAQ;AAAA,IACrD,CAAC,CAAA;AAEH,IAAA,IAAI,WAAA,CAAY,WAAW,CAAA,EAAG;AAC5B,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,MAAM,UAAA,GAAa,YAAY,CAAC,CAAA;AAGhC,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,WAAW,EAAE,CAAA;AAC9C,IAAA,IAAI,CAAC,UAAA,IAAc,UAAA,CAAW,MAAA,KAAW,SAAA,EAAW;AAIlD,MAAA,OAAO,KAAK,mBAAA,EAAoB;AAAA,IAClC;AAGA,IAAA,MAAM,OAAA,GAA6B;AAAA,MACjC,GAAG,UAAA;AAAA,MACH,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,OAAA,EAAS,WAAW,OAAA,GAAU;AAAA,KAChC;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,EAAA,EAAI,OAAO,CAAA;AAEjC,IAAA,OAAO,EAAE,GAAG,OAAA,EAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,IAAA,EAAsD;AACtE,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,KAAKA,UAAAA,EAAW;AACtB,IAAA,MAAM,MAAA,GAA8B;AAAA,MAClC,EAAA;AAAA,MACA,SAAA,EAAW,GAAA;AAAA,MACX,SAAA,EAAW,GAAA;AAAA,MACX,OAAA,EAAS,CAAA;AAAA,MACT,eAAe,IAAA,CAAK,aAAA;AAAA,MACpB,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,gBAAgB,IAAA,CAAK,cAAA;AAAA,MACrB,OAAA,EAAS,KAAK,OAAA,IAAW,CAAA;AAAA,MACzB,MAAA,EAAQ,KAAK,MAAA,IAAU,SAAA;AAAA,MACvB,SAAA,EAAW,KAAK,SAAA,IAAa,IAAA;AAAA,MAC7B,WAAA,EAAa,IAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,SAAA,EAAW,KAAK,SAAA,IAAa,IAAA;AAAA,MAC7B,UAAA,EAAY,IAAA;AAAA,MACZ,MAAA,EAAQ,KAAK,MAAA,IAAU,IAAA;AAAA,MACvB,cAAA,EAAgB,IAAA;AAAA,MAChB,UAAA,EAAY,IAAA;AAAA,MACZ,UAAA,EAAY,IAAA;AAAA,MACZ,YAAA,EAAc,IAAA;AAAA,MACd,YAAA,EAAc,IAAA;AAAA,MACd,OAAA,EAAS,IAAA;AAAA,MACT,aAAA,EAAe,IAAA;AAAA,MACf,YAAA,EAAc;AAAA,KAChB;AAEA,IAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,EAAA,EAAI,MAAM,CAAA;AAE1B,IAAA,IAAA,CAAK,MAAA,CAAO,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,aAAA,EAAe,IAAA,CAAK,OAAO,CAAA,EAAG,MAAM,CAAA;AACvE,IAAA,OAAO,EAAE,GAAG,MAAA,EAAO;AAAA,EACrB;AAAA,EAEA,MAAM,YAAY,IAAA,EAAsD;AACtE,IAAA,MAAM,MAAM,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,aAAA,EAAe,KAAK,OAAO,CAAA;AAC1D,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAEpC,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,MAAM,OAAA,GAA+B;AAAA,QACnC,GAAG,QAAA;AAAA,QACH,GAAG,IAAA,CAAK,MAAA;AAAA,QACR,SAAA,sBAAe,IAAA,EAAK;AAAA,QACpB,OAAA,EAAS,SAAS,OAAA,GAAU;AAAA,OAC9B;AACA,MAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI,OAAO,CAAA;AACpC,MAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,GAAA,EAAK,OAAO,CAAA;AAC5B,MAAA,OAAO,EAAE,GAAG,OAAA,EAAQ;AAAA,IACtB,CAAA,MAAO;AACL,MAAA,OAAO,IAAA,CAAK,WAAA,CAAY,IAAA,CAAK,MAAM,CAAA;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,MAAM,WAAA,CAAY,EAAA,EAAY,IAAA,EAAuC;AACnE,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA;AAChC,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,EAAE,CAAA,CAAE,CAAA;AAAA,IAClD;AAEA,IAAA,IACE,KAAK,eAAA,KAAoB,MAAA,IACzB,KAAA,CAAM,OAAA,KAAY,KAAK,eAAA,EACvB;AACA,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,eAAA;AAAA,QACA,EAAA;AAAA,QACA,IAAA,CAAK,eAAA;AAAA,QACL,KAAA,CAAM;AAAA,OACR;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,eAAA,EAAiB,CAAA,EAAG,GAAG,MAAK,GAAI,IAAA;AACxC,IAAA,MAAM,OAAA,GAA+B;AAAA,MACnC,GAAG,KAAA;AAAA,MACH,GAAG,IAAA;AAAA,MACH,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,OAAA,EAAS,MAAM,OAAA,GAAU;AAAA,KAC3B;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,EAAA,EAAI,OAAO,CAAA;AAC3B,IAAA,IAAA,CAAK,MAAA,CAAO,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,aAAA,EAAe,KAAA,CAAM,OAAO,CAAA,EAAG,OAAO,CAAA;AAAA,EAC5E;AAAA,EAEA,MAAM,0BAAA,CACJ,aAAA,EACA,OAAA,EACA,IAAA,EACe;AACf,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,QAAA,CAAS,aAAA,EAAe,OAAO,CAAA;AAChD,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AACjC,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,aAAa,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE,CAAA;AAAA,IACxE;AAEA,IAAA,IACE,KAAK,eAAA,KAAoB,MAAA,IACzB,KAAA,CAAM,OAAA,KAAY,KAAK,eAAA,EACvB;AACA,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,eAAA;AAAA,QACA,CAAA,EAAG,aAAa,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA;AAAA,QAC3B,IAAA,CAAK,eAAA;AAAA,QACL,KAAA,CAAM;AAAA,OACR;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,eAAA,EAAiB,CAAA,EAAG,GAAG,MAAK,GAAI,IAAA;AACxC,IAAA,MAAM,OAAA,GAA+B;AAAA,MACnC,GAAG,KAAA;AAAA,MACH,GAAG,IAAA;AAAA,MACH,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,OAAA,EAAS,MAAM,OAAA,GAAU;AAAA,KAC3B;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,EAAA,EAAI,OAAO,CAAA;AACjC,IAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,GAAA,EAAK,OAAO,CAAA;AAAA,EAC9B;AAAA,EAEA,MAAM,QAAA,CACJ,KAAA,EACA,OAAA,EACqC;AACrC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,QAAA,CAAS,KAAA,EAAO,OAAO,CAAA;AACxC,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AACjC,IAAA,OAAO,KAAA,GAAQ,EAAE,GAAG,KAAA,EAAM,GAAI,IAAA;AAAA,EAChC;AAAA,EAEA,MAAM,aAAa,EAAA,EAAiD;AAClE,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA;AAChC,IAAA,OAAO,KAAA,GAAQ,EAAE,GAAG,KAAA,EAAM,GAAI,IAAA;AAAA,EAChC;AAAA,EAEA,MAAM,cAAA,CACJ,KAAA,EACA,OAAA,EACgC;AAEhC,IAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,IAAA,IAAI,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,QAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM;AAC1D,MAAA,IAAI,CAAA,CAAE,aAAA,KAAkB,KAAA,EAAO,OAAO,KAAA;AACtC,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,EAAE,GAAG,OAAO,KAAA;AAC9B,MAAA,OAAA,CAAQ,GAAA,CAAI,EAAE,EAAE,CAAA;AAChB,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAED,IAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,MAAA,MAAA,GAAS,OAAO,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,QAAQ,MAAM,CAAA;AAAA,IAC3D;AAGA,IAAA,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM;AACpB,MAAA,MAAM,IAAA,GAAO,CAAA,CAAE,WAAA,GAAc,CAAA,CAAE,WAAA;AAC/B,MAAA,OAAO,OAAA,EAAS,OAAA,KAAY,MAAA,GAAS,CAAC,IAAA,GAAO,IAAA;AAAA,IAC/C,CAAC,CAAA;AAED,IAAA,OAAO,OAAO,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EACrC;AAAA,EAEA,MAAM,mBAAmB,UAAA,EAAkD;AACzE,IAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,IAAA,OAAO,KAAA,CAAM,KAAK,IAAA,CAAK,MAAA,CAAO,QAAQ,CAAA,CACnC,MAAA,CAAO,CAAC,CAAA,KAAM;AACb,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,EAAE,GAAG,OAAO,KAAA;AAC9B,MAAA,OAAA,CAAQ,GAAA,CAAI,EAAE,EAAE,CAAA;AAChB,MAAA,OACE,EAAE,MAAA,KAAW,WAAA,IACb,EAAE,UAAA,KAAe,IAAA,IACjB,EAAE,UAAA,IAAc,UAAA;AAAA,IAEpB,CAAC,EACA,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC1B;AAAA,EAEA,MAAM,oCACJ,KAAA,EACqC;AACrC,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,cAAA,CAAe,OAAO,EAAE,MAAA,EAAQ,aAAa,CAAA;AACvE,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,UAAA,IAAc,CAAA,CAAE,UAAA,IAAc,GAAG,CAAA;AACpE,IAAA,OAAO,KAAA,IAAS,IAAA;AAAA,EAClB;AAAA,EAEA,MAAM,oBACJ,KAAA,EACqC;AACrC,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,cAAA,CAAe,OAAO,EAAE,MAAA,EAAQ,UAAU,CAAA;AACpE,IAAA,OAAO,MAAA,CAAO,CAAC,CAAA,IAAK,IAAA;AAAA,EACtB;AAAA,EAEA,MAAM,sBACJ,KAAA,EACqC;AACrC,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,cAAA,CAAe,KAAA,EAAO;AAAA,MAC9C,MAAA,EAAQ,WAAA;AAAA,MACR,OAAA,EAAS;AAAA,KACV,CAAA;AACD,IAAA,OAAO,MAAA,CAAO,CAAC,CAAA,IAAK,IAAA;AAAA,EACtB;AAAA,EAEA,MAAM,2BAAA,CACJ,KAAA,EACA,cAAA,EACqC;AACrC,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,cAAA,CAAe,KAAA,EAAO;AAAA,MAC9C,MAAA,EAAQ,WAAA;AAAA,MACR,OAAA,EAAS;AAAA,KACV,CAAA;AACD,IAAA,MAAM,SAAS,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,iBAAiB,cAAc,CAAA;AACrE,IAAA,OAAO,MAAA,CAAO,CAAC,CAAA,IAAK,IAAA;AAAA,EACtB;AAAA,EAEA,MAAM,YAAY,EAAA,EAA2B;AAC3C,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA;AAChC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,IAAA,CAAK,MAAA,CAAO,OAAO,EAAE,CAAA;AACrB,MAAA,IAAA,CAAK,MAAA,CAAO,OAAO,IAAA,CAAK,QAAA,CAAS,MAAM,aAAA,EAAe,KAAA,CAAM,OAAO,CAAC,CAAA;AAKpE,MAAA,KAAA,MAAW,UAAA,IAAc,KAAK,WAAA,EAAa;AACzC,QAAA,IAAI,UAAA,CAAW,0BAA0B,EAAA,EAAI;AAC3C,UAAA,UAAA,CAAW,qBAAA,GAAwB,IAAA;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAAU,IAAA,EAAqC;AACnD,IAAA,MAAM,MAAA,GAA4B;AAAA,MAChC,IAAIA,UAAAA,EAAW;AAAA,MACf,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,aAAA,EAAe,KAAK,aAAA,IAAiB,IAAA;AAAA,MACrC,eAAA,EAAiB,KAAK,eAAA,IAAmB,IAAA;AAAA,MACzC,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,QAAA,EAAU,KAAK,QAAA,IAAY;AAAA,KAC7B;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,MAAM,CAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,mBAAmB,MAAA,EAAiD;AACxE,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,MAAM,aAAa,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,KAAA,CAAM,aAAa,CAAA,IAAK,CAAA;AACpE,MAAA,MAAM,UAAU,UAAA,GAAa,CAAA;AAC7B,MAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,KAAA,CAAM,aAAA,EAAe,OAAO,CAAA;AAErD,MAAA,MAAM,MAAA,GAAuB;AAAA,QAC3B,IAAIA,UAAAA,EAAW;AAAA,QACf,eAAe,KAAA,CAAM,aAAA;AAAA,QACrB,QAAA,EAAU,OAAA;AAAA,QACV,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,SAAS,KAAA,CAAM,OAAA;AAAA,QACf,aAAa,KAAA,CAAM,WAAA;AAAA,QACnB,YAAY,KAAA,CAAM,UAAA;AAAA,QAClB,WAAA,EAAa,IAAA;AAAA,QACb,UAAA,EAAY,CAAA;AAAA,QACZ,KAAA,EAAO;AAAA,OACT;AACA,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,MAAM,CAAA;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,MAAM,2BAA2B,KAAA,EAAyC;AACxE,IAAA,MAAM,iBAAiB,KAAA,IAAS,GAAA;AAChC,IAAA,OAAO,IAAA,CAAK,MAAA,CACT,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,WAAA,KAAgB,IAAA,IAAQ,CAAA,CAAE,UAAU,IAAI,CAAA,CACxD,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AACd,MAAA,MAAM,MAAA,GAAS,CAAA,CAAE,aAAA,CAAc,aAAA,CAAc,EAAE,aAAa,CAAA;AAC5D,MAAA,IAAI,MAAA,KAAW,GAAG,OAAO,MAAA;AACzB,MAAA,OAAO,CAAA,CAAE,WAAW,CAAA,CAAE,QAAA;AAAA,IACxB,CAAC,CAAA,CACA,KAAA,CAAM,CAAA,EAAG,cAAc,CAAA,CACvB,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAE,CAAE,CAAA;AAAA,EAC1B;AAAA,EAEA,MAAM,0BAA0B,GAAA,EAA8B;AAC5D,IAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,GAAG,CAAA;AACzB,IAAA,KAAA,MAAW,MAAA,IAAU,KAAK,MAAA,EAAQ;AAChC,MAAA,IAAI,KAAA,CAAM,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA,EAAG;AACxB,QAAA,MAAA,CAAO,WAAA,uBAAkB,IAAA,EAAK;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,0BAA0B,EAAA,EAA6B;AAC3D,IAAA,MAAM,MAAA,GAAS,KAAK,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,EAAE,CAAA;AAClD,IAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,EAAE,CAAA,CAAE,CAAA;AAC5D,IAAA,MAAA,CAAO,UAAA,EAAA;AACP,IAAA,OAAO,MAAA,CAAO,UAAA;AAAA,EAChB;AAAA,EAEA,MAAM,qBAAqB,EAAA,EAA2B;AACpD,IAAA,MAAM,MAAA,GAAS,KAAK,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,EAAE,CAAA;AAClD,IAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,EAAE,CAAA,CAAE,CAAA;AAC5D,IAAA,MAAA,CAAO,KAAA,uBAAY,IAAA,EAAK;AAAA,EAC1B;AAAA,EAEA,MAAM,gBAAgB,SAAA,EAAoC;AACxD,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,MAAA,CACpB,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,KAAU,IAAI,CAAA,CAC9B,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA;AACrB,IAAA,KAAA,MAAW,UAAU,SAAA,EAAW;AAC9B,MAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AACf,MAAA,MAAA,CAAO,UAAA,GAAa,CAAA;AAAA,IACtB;AACA,IAAA,OAAO,SAAA,CAAU,MAAA;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,qBAAA,CACJ,GAAA,EACA,WAAA,EAKA;AACA,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,uBAAA,CAAwB,WAAA,EAAa,GAAG,CAAA;AAClE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,YAAY,CAAA;AACpD,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,MAAA,EAAQ,OAAO,MAAA,EAAO;AAAA,IACnD;AACA,IAAA,IAAI,IAAA,CAAK,qBAAA,CAAsB,GAAA,CAAI,YAAY,CAAA,EAAG;AAChD,MAAA,OAAO,EAAE,QAAQ,aAAA,EAAc;AAAA,IACjC;AACA,IAAA,IAAA,CAAK,qBAAA,CAAsB,IAAI,YAAY,CAAA;AAC3C,IAAA,OAAO,EAAE,QAAQ,UAAA,EAAW;AAAA,EAC9B;AAAA,EAEA,MAAM,sBAAA,CACJ,GAAA,EACA,WAAA,EACA,MAAA,EACe;AACf,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,uBAAA,CAAwB,WAAA,EAAa,GAAG,CAAA;AAClE,IAAA,IAAA,CAAK,qBAAA,CAAsB,OAAO,YAAY,CAAA;AAC9C,IAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,YAAA,EAAc;AAAA,MACrC,GAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA;AAAA,MACA,SAAA,sBAAe,IAAA;AAAK,KACrB,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,qBAAA,CAAsB,GAAA,EAAa,WAAA,EAAoC;AAC3E,IAAA,IAAA,CAAK,qBAAA,CAAsB,MAAA;AAAA,MACzB,IAAA,CAAK,uBAAA,CAAwB,WAAA,EAAa,GAAG;AAAA,KAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,IAAA,EAAwC;AACzD,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,MAAM,IAAA,CAAK,WAAA,CAAY,IAAA,CAAK,aAAA,EAAe,KAAK,GAAG,CAAA;AACzD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,GAAG,CAAA;AAEvC,IAAA,MAAM,MAAA,GAAiC;AAAA,MACrC,EAAA,EAAI,QAAA,EAAU,EAAA,IAAMA,UAAAA,EAAW;AAAA,MAC/B,SAAA,EAAW,UAAU,SAAA,IAAa,GAAA;AAAA,MAClC,SAAA,EAAW,GAAA;AAAA,MACX,eAAe,IAAA,CAAK,aAAA;AAAA,MACpB,eAAA,EAAiB,KAAK,eAAA,IAAmB,IAAA;AAAA,MACzC,KAAK,IAAA,CAAK,GAAA;AAAA,MACV,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,QAAA,EAAU,KAAK,QAAA,IAAY;AAAA,KAC7B;AACA,IAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,GAAA,EAAK,MAAM,CAAA;AAAA,EAChC;AAAA,EAEA,MAAM,YAAA,CAAa,KAAA,EAAe,GAAA,EAA+B;AAC/D,IAAA,MAAM,QAAA,GAAW,KAAK,SAAA,CAAU,GAAA,CAAI,KAAK,WAAA,CAAY,KAAA,EAAO,GAAG,CAAC,CAAA;AAChE,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAAA,IACvD;AACA,IAAA,OAAO,QAAA,CAAS,IAAA;AAAA,EAClB;AAAA,EAEA,MAAM,WAAA,CAAY,KAAA,EAAe,GAAA,EAA+B;AAC9D,IAAA,OAAO,KAAK,SAAA,CAAU,GAAA,CAAI,KAAK,WAAA,CAAY,KAAA,EAAO,GAAG,CAAC,CAAA;AAAA,EACxD;AAAA,EAEA,MAAM,cAAA,CAAe,KAAA,EAAe,GAAA,EAA4B;AAC9D,IAAA,IAAA,CAAK,UAAU,MAAA,CAAO,IAAA,CAAK,WAAA,CAAY,KAAA,EAAO,GAAG,CAAC,CAAA;AAAA,EACpD;AAAA,EAEA,MAAM,cAAc,KAAA,EAAkD;AACpE,IAAA,OAAO,KAAA,CAAM,KAAK,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA,CACtC,OAAO,CAAC,CAAA,KAAM,EAAE,aAAA,KAAkB,KAAK,EACvC,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC1B;AAAA,EAEA,MAAM,qBAAA,CACJ,KAAA,EACA,OAAA,EACwB;AACxB,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,QAAA,CAAS,OAAO,OAAO,CAAA;AAChD,IAAA,OAAO,OAAO,EAAA,IAAM,IAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBAAkB,MAAA,EAAgD;AACtE,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAE1B,MAAA,IAAI,KAAA,CAAM,cAAA,KAAmB,IAAA,IAAQ,KAAA,CAAM,mBAAmB,MAAA,EAAW;AACvE,QAAA,MAAM,MAAA,GAAS,KAAK,WAAA,CAAY,IAAA;AAAA,UAC9B,CAAC,CAAA,KACC,CAAA,CAAE,aAAA,KAAkB,KAAA,CAAM,aAAA,IAC1B,CAAA,CAAE,GAAA,KAAQ,KAAA,CAAM,GAAA,IAChB,CAAA,CAAE,cAAA,KAAmB,KAAA,CAAM;AAAA,SAC/B;AACA,QAAA,IAAI,MAAA,EAAQ;AAAA,MACd;AAEA,MAAA,MAAM,MAAA,GAAmC;AAAA,QACvC,IAAIA,UAAAA,EAAW;AAAA,QACf,SAAA,sBAAe,IAAA,EAAK;AAAA,QACpB,eAAe,KAAA,CAAM,aAAA;AAAA,QACrB,qBAAA,EAAuB,MAAM,qBAAA,IAAyB,IAAA;AAAA,QACtD,OAAA,EAAS,MAAM,OAAA,IAAW,CAAA;AAAA,QAC1B,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,OAAA,EAAS,MAAM,OAAA,IAAW,IAAA;AAAA,QAC1B,SAAA,EAAW,KAAA,CAAM,KAAA,EAAO,IAAA,IAAQ,IAAA;AAAA,QAChC,OAAA,EAAS,KAAA,CAAM,KAAA,EAAO,EAAA,IAAM,IAAA;AAAA,QAC5B,YAAA,EAAc,KAAA,CAAM,KAAA,EAAO,OAAA,IAAW,IAAA;AAAA,QACtC,KAAK,KAAA,CAAM,GAAA;AAAA,QACX,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,OAAA,EAAS,MAAM,OAAA,IAAW,IAAA;AAAA,QAC1B,cAAA,EAAgB,MAAM,cAAA,IAAkB;AAAA,OAC1C;AACA,MAAA,IAAA,CAAK,WAAA,CAAY,KAAK,MAAM,CAAA;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,MAAM,eAAA,CACJ,aAAA,EACA,OAAA,GAA6B,EAAC,EACO;AACrC,IAAA,IAAI,IAAA,GAAO,KAAK,WAAA,CAAY,MAAA;AAAA,MAC1B,CAAC,CAAA,KAAM,CAAA,CAAE,aAAA,KAAkB;AAAA,KAC7B;AAEA,IAAA,IAAI,OAAA,CAAQ,QAAQ,MAAA,EAAW;AAC7B,MAAA,IAAA,GAAO,KAAK,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,GAAA,KAAQ,QAAQ,GAAG,CAAA;AAAA,IACjD,CAAA,MAAA,IAAW,OAAA,CAAQ,SAAA,KAAc,MAAA,EAAW;AAC1C,MAAA,MAAM,SAAS,OAAA,CAAQ,SAAA;AACvB,MAAA,IAAA,GAAO,IAAA,CAAK,OAAO,CAAC,CAAA,KAAM,EAAE,GAAA,CAAI,UAAA,CAAW,MAAM,CAAC,CAAA;AAAA,IACpD;AAEA,IAAA,IAAI,OAAA,CAAQ,UAAU,MAAA,EAAW;AAC/B,MAAA,IAAA,GAAO,KAAK,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,KAAA,KAAU,QAAQ,KAAK,CAAA;AAAA,IACrD;AACA,IAAA,IAAI,OAAA,CAAQ,YAAY,MAAA,EAAW;AACjC,MAAA,IAAA,GAAO,KAAK,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,OAAA,KAAY,QAAQ,OAAO,CAAA;AAAA,IACzD;AACA,IAAA,IAAI,OAAA,CAAQ,YAAY,MAAA,EAAW;AACjC,MAAA,IAAA,GAAO,KAAK,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,OAAA,KAAY,QAAQ,OAAO,CAAA;AAAA,IACzD;AACA,IAAA,IAAI,OAAA,CAAQ,cAAc,MAAA,EAAW;AACnC,MAAA,IAAA,GAAO,KAAK,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,SAAA,KAAc,QAAQ,SAAS,CAAA;AAAA,IAC7D;AACA,IAAA,IAAI,OAAA,CAAQ,YAAY,MAAA,EAAW;AACjC,MAAA,IAAA,GAAO,KAAK,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,OAAA,KAAY,QAAQ,OAAO,CAAA;AAAA,IACzD;AACA,IAAA,IAAI,OAAA,CAAQ,UAAU,MAAA,EAAW;AAC/B,MAAA,MAAM,QAAQ,OAAA,CAAQ,KAAA;AACtB,MAAA,IAAA,GAAO,KAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,aAAa,KAAK,CAAA;AAAA,IAChD;AACA,IAAA,IAAI,OAAA,CAAQ,UAAU,MAAA,EAAW;AAC/B,MAAA,MAAM,QAAQ,OAAA,CAAQ,KAAA;AACtB,MAAA,IAAA,GAAO,KAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,aAAa,KAAK,CAAA;AAAA,IAChD;AAIA,IAAA,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM;AAClB,MAAA,MAAM,MAAM,CAAA,CAAE,SAAA,CAAU,SAAQ,GAAI,CAAA,CAAE,UAAU,OAAA,EAAQ;AACxD,MAAA,IAAI,GAAA,KAAQ,GAAG,OAAO,GAAA;AACtB,MAAA,OAAO,CAAA,CAAE,EAAA,CAAG,aAAA,CAAc,CAAA,CAAE,EAAE,CAAA;AAAA,IAChC,CAAC,CAAA;AAED,IAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,GAAA;AAC/B,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAE,CAAE,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAA,CACJ,KAAA,EACA,YAAA,EACA,SACA,MAAA,EACiB;AACjB,IAAA,MAAM,MAAM,CAAA,YAAA,EAAe,YAAY,CAAA,CAAA,EAAI,KAAK,IAAI,OAAO,CAAA,YAAA,CAAA;AAC3D,IAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,qBAAA,CAAsB,OAAO,OAAO,CAAA;AAEjE,IAAA,MAAM,KAAK,YAAA,CAAa;AAAA,MACtB,aAAA,EAAe,KAAA;AAAA,MACf,iBAAiB,SAAA,IAAa,MAAA;AAAA,MAC9B,GAAA;AAAA,MACA,IAAA,EAAM,cAAA;AAAA,MACN,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,MAAM,CAAA,CAAE;AAAA,KAC9B,CAAA;AAED,IAAA,OAAO,GAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,KAAK,KAAA,EAAM;AAChB,IAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAClB,IAAA,IAAA,CAAK,KAAK,KAAA,EAAM;AAChB,IAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AACrB,IAAA,IAAA,CAAK,cAAc,EAAC;AACpB,IAAA,IAAA,CAAK,SAAS,EAAC;AACf,IAAA,IAAA,CAAK,gBAAgB,KAAA,EAAM;AAC3B,IAAA,IAAA,CAAK,sBAAsB,KAAA,EAAM;AACjC,IAAA,IAAA,CAAK,gBAAgB,KAAA,EAAM;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,UAAA,GAAkC;AAChC,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,GAAsC;AAEpC,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,CAAA,CACnC,MAAA,CAAO,CAAC,CAAA,KAAM,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,CAAE,EAAE,CAAA,KAAM,CAAC,CAAA,CACzC,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAE,CAAE,CAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,UAAA,GAAkC;AAChC,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,eAAA,GAA4C;AAC1C,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAA,GAAgD;AAC9C,IAAA,OAAO,IAAA,CAAK,YAAY,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,GAAE,CAAE,CAAA;AAAA,EAC/C;AACF","file":"index.js","sourcesContent":["/**\n * In-Memory AI Call Logger\n *\n * A complete in-memory implementation of AICallLogger for testing.\n * Tracks all AI calls with full cost/token tracking and topic-based aggregation.\n *\n * @example\n * ```typescript\n * import { InMemoryAICallLogger } from '@bratsos/workflow-engine/testing';\n *\n * const aiLogger = new InMemoryAICallLogger();\n * // Use in tests...\n * aiLogger.clear(); // Reset between tests\n * ```\n */\n\nimport { randomUUID } from \"crypto\";\nimport type {\n AICallLogger,\n AICallRecord,\n AIHelperStats,\n CreateAICallInput,\n} from \"../persistence/interface.js\";\n\nexport class InMemoryAICallLogger implements AICallLogger {\n private calls = new Map<string, AICallRecord>();\n private recordedBatches = new Set<string>();\n\n // ============================================================================\n // Core Operations\n // ============================================================================\n\n /**\n * Log a single AI call (fire and forget)\n */\n logCall(call: CreateAICallInput): void {\n const id = randomUUID();\n const record: AICallRecord = {\n id,\n createdAt: new Date(),\n topic: call.topic,\n callType: call.callType,\n modelKey: call.modelKey,\n modelId: call.modelId,\n prompt: call.prompt,\n response: call.response,\n inputTokens: call.inputTokens,\n outputTokens: call.outputTokens,\n cost: call.cost,\n metadata: call.metadata ?? null,\n };\n this.calls.set(id, record);\n }\n\n /**\n * Log batch results (for recording batch API results)\n */\n async logBatchResults(\n batchId: string,\n results: CreateAICallInput[],\n ): Promise<void> {\n // Mark batch as recorded\n this.recordedBatches.add(batchId);\n\n // Log each result\n for (const result of results) {\n this.logCall({\n ...result,\n metadata: {\n ...(result.metadata as Record<string, unknown> | undefined),\n batchId,\n },\n });\n }\n }\n\n /**\n * Get aggregated stats for a topic prefix\n */\n async getStats(topicPrefix: string): Promise<AIHelperStats> {\n const matchingCalls = Array.from(this.calls.values()).filter((call) =>\n call.topic.startsWith(topicPrefix),\n );\n\n const stats: AIHelperStats = {\n totalCalls: matchingCalls.length,\n totalInputTokens: 0,\n totalOutputTokens: 0,\n totalCost: 0,\n perModel: {},\n };\n\n for (const call of matchingCalls) {\n stats.totalInputTokens += call.inputTokens;\n stats.totalOutputTokens += call.outputTokens;\n stats.totalCost += call.cost;\n\n // Aggregate per model\n if (!stats.perModel[call.modelKey]) {\n stats.perModel[call.modelKey] = {\n calls: 0,\n inputTokens: 0,\n outputTokens: 0,\n cost: 0,\n };\n }\n stats.perModel[call.modelKey]!.calls++;\n stats.perModel[call.modelKey]!.inputTokens += call.inputTokens;\n stats.perModel[call.modelKey]!.outputTokens += call.outputTokens;\n stats.perModel[call.modelKey]!.cost += call.cost;\n }\n\n return stats;\n }\n\n /**\n * Check if batch results are already recorded\n */\n async isRecorded(batchId: string): Promise<boolean> {\n return this.recordedBatches.has(batchId);\n }\n\n // ============================================================================\n // Test Helpers\n // ============================================================================\n\n /**\n * Clear all data - useful between tests\n */\n clear(): void {\n this.calls.clear();\n this.recordedBatches.clear();\n }\n\n /**\n * Get all calls for inspection\n */\n getAllCalls(): AICallRecord[] {\n return Array.from(this.calls.values()).map((c) => ({ ...c }));\n }\n\n /**\n * Get calls by topic for inspection\n */\n getCallsByTopic(topic: string): AICallRecord[] {\n return Array.from(this.calls.values())\n .filter((c) => c.topic === topic)\n .map((c) => ({ ...c }));\n }\n\n /**\n * Get calls by topic prefix for inspection\n */\n getCallsByTopicPrefix(prefix: string): AICallRecord[] {\n return Array.from(this.calls.values())\n .filter((c) => c.topic.startsWith(prefix))\n .map((c) => ({ ...c }));\n }\n\n /**\n * Get calls by model for inspection\n */\n getCallsByModel(modelKey: string): AICallRecord[] {\n return Array.from(this.calls.values())\n .filter((c) => c.modelKey === modelKey)\n .map((c) => ({ ...c }));\n }\n\n /**\n * Get calls by call type for inspection\n */\n getCallsByType(callType: string): AICallRecord[] {\n return Array.from(this.calls.values())\n .filter((c) => c.callType === callType)\n .map((c) => ({ ...c }));\n }\n\n /**\n * Get total cost across all calls\n */\n getTotalCost(): number {\n let total = 0;\n for (const call of this.calls.values()) {\n total += call.cost;\n }\n return total;\n }\n\n /**\n * Get total tokens across all calls\n */\n getTotalTokens(): { input: number; output: number } {\n let input = 0;\n let output = 0;\n for (const call of this.calls.values()) {\n input += call.inputTokens;\n output += call.outputTokens;\n }\n return { input, output };\n }\n\n /**\n * Get call count\n */\n getCallCount(): number {\n return this.calls.size;\n }\n\n /**\n * Get all recorded batch IDs\n */\n getRecordedBatchIds(): string[] {\n return Array.from(this.recordedBatches);\n }\n\n /**\n * Get the last call made (useful for assertions)\n */\n getLastCall(): AICallRecord | null {\n const calls = Array.from(this.calls.values());\n if (calls.length === 0) return null;\n\n // Sort by createdAt descending\n calls.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n return { ...calls[0]! };\n }\n\n /**\n * Assert a call was made with specific properties\n */\n hasCallMatching(predicate: (call: AICallRecord) => boolean): boolean {\n return Array.from(this.calls.values()).some(predicate);\n }\n}\n","/**\n * In-Memory Job Queue\n *\n * A complete in-memory implementation of JobQueue for testing.\n * Supports priority ordering, locking, and stale job recovery.\n *\n * @example\n * ```typescript\n * import { InMemoryJobQueue } from '@bratsos/workflow-engine/testing';\n *\n * const jobQueue = new InMemoryJobQueue();\n * // Use in tests...\n * jobQueue.clear(); // Reset between tests\n * ```\n */\n\nimport { randomUUID } from \"crypto\";\nimport type {\n DequeueResult,\n EnqueueJobInput,\n JobQueue,\n JobRecord,\n JobStatus,\n} from \"../persistence/interface.js\";\n\nexport class InMemoryJobQueue implements JobQueue {\n private jobs = new Map<string, JobRecord>();\n private workerId: string;\n private defaultMaxAttempts = 3;\n\n constructor(workerId?: string) {\n this.workerId = workerId ?? `worker-${randomUUID().slice(0, 8)}`;\n }\n\n // ============================================================================\n // Core Operations\n // ============================================================================\n\n async enqueue(options: EnqueueJobInput): Promise<string> {\n const now = new Date();\n const id = randomUUID();\n\n const job: JobRecord = {\n id,\n createdAt: now,\n updatedAt: now,\n workflowRunId: options.workflowRunId,\n workflowId: options.workflowId,\n stageId: options.stageId,\n status: \"PENDING\",\n priority: options.priority ?? 5,\n workerId: null,\n lockedAt: null,\n startedAt: null,\n completedAt: null,\n attempt: 0,\n maxAttempts: this.defaultMaxAttempts,\n lastError: null,\n nextPollAt: options.scheduledFor ?? null,\n payload: options.payload ?? {},\n };\n\n this.jobs.set(id, job);\n return id;\n }\n\n async enqueueParallel(jobs: EnqueueJobInput[]): Promise<string[]> {\n const ids: string[] = [];\n for (const job of jobs) {\n const id = await this.enqueue(job);\n ids.push(id);\n }\n return ids;\n }\n\n async dequeue(): Promise<DequeueResult | null> {\n // Find the highest priority PENDING job\n const now = new Date();\n const pendingJobs = Array.from(this.jobs.values())\n .filter(\n (j) =>\n j.status === \"PENDING\" &&\n (j.nextPollAt === null || j.nextPollAt <= now),\n )\n .sort((a, b) => {\n // Higher priority first\n if (b.priority !== a.priority) {\n return b.priority - a.priority;\n }\n // Earlier creation first (FIFO for same priority)\n return a.createdAt.getTime() - b.createdAt.getTime();\n });\n\n if (pendingJobs.length === 0) {\n return null;\n }\n\n const job = pendingJobs[0]!;\n\n // Lock the job and increment attempt (matches Prisma dequeue semantics)\n const newAttempt = job.attempt + 1;\n const updated: JobRecord = {\n ...job,\n status: \"RUNNING\",\n workerId: this.workerId,\n lockedAt: now,\n startedAt: now,\n updatedAt: now,\n attempt: newAttempt,\n };\n this.jobs.set(job.id, updated);\n\n return {\n jobId: job.id,\n workflowRunId: job.workflowRunId,\n workflowId: job.workflowId,\n stageId: job.stageId,\n priority: job.priority,\n attempt: newAttempt,\n maxAttempts: job.maxAttempts,\n payload: job.payload,\n };\n }\n\n async complete(jobId: string): Promise<void> {\n const job = this.jobs.get(jobId);\n if (!job) {\n throw new Error(`Job not found: ${jobId}`);\n }\n\n const now = new Date();\n const updated: JobRecord = {\n ...job,\n status: \"COMPLETED\",\n completedAt: now,\n updatedAt: now,\n };\n this.jobs.set(jobId, updated);\n }\n\n async suspend(jobId: string, nextPollAt: Date): Promise<void> {\n const job = this.jobs.get(jobId);\n if (!job) {\n throw new Error(`Job not found: ${jobId}`);\n }\n\n const updated: JobRecord = {\n ...job,\n status: \"SUSPENDED\",\n nextPollAt,\n workerId: null,\n lockedAt: null,\n updatedAt: new Date(),\n };\n this.jobs.set(jobId, updated);\n }\n\n async fail(\n jobId: string,\n error: string,\n shouldRetry: boolean = true,\n ): Promise<void> {\n const job = this.jobs.get(jobId);\n if (!job) {\n throw new Error(`Job not found: ${jobId}`);\n }\n\n const now = new Date();\n\n if (shouldRetry && job.attempt < job.maxAttempts) {\n // Retry: move back to PENDING (attempt was already incremented during dequeue)\n const updated: JobRecord = {\n ...job,\n status: \"PENDING\",\n lastError: error,\n workerId: null,\n lockedAt: null,\n updatedAt: now,\n };\n this.jobs.set(jobId, updated);\n } else {\n // No more retries: mark as FAILED\n const updated: JobRecord = {\n ...job,\n status: \"FAILED\",\n lastError: error,\n completedAt: now,\n updatedAt: now,\n };\n this.jobs.set(jobId, updated);\n }\n }\n\n async getSuspendedJobsReadyToPoll(): Promise<\n Array<{ jobId: string; stageId: string; workflowRunId: string }>\n > {\n const now = new Date();\n return Array.from(this.jobs.values())\n .filter(\n (j) => j.status === \"SUSPENDED\" && j.nextPollAt && j.nextPollAt <= now,\n )\n .map((j) => ({\n jobId: j.id,\n stageId: j.stageId,\n workflowRunId: j.workflowRunId,\n }));\n }\n\n async releaseStaleJobs(staleThresholdMs: number = 60000): Promise<number> {\n const now = new Date();\n const threshold = new Date(now.getTime() - staleThresholdMs);\n let released = 0;\n\n for (const job of this.jobs.values()) {\n if (\n job.status === \"RUNNING\" &&\n job.lockedAt &&\n job.lockedAt < threshold\n ) {\n // Release the stale lock\n const updated: JobRecord = {\n ...job,\n status: \"PENDING\",\n workerId: null,\n lockedAt: null,\n updatedAt: now,\n };\n this.jobs.set(job.id, updated);\n released++;\n }\n }\n\n return released;\n }\n\n async cancelByRun(workflowRunId: string): Promise<number> {\n const now = new Date();\n let count = 0;\n for (const job of this.jobs.values()) {\n if (\n job.workflowRunId === workflowRunId &&\n (job.status === \"PENDING\" || job.status === \"SUSPENDED\")\n ) {\n const updated: JobRecord = {\n ...job,\n status: \"CANCELLED\",\n completedAt: now,\n updatedAt: now,\n };\n this.jobs.set(job.id, updated);\n count++;\n }\n }\n return count;\n }\n\n // ============================================================================\n // Test Helpers\n // ============================================================================\n\n /**\n * Clear all jobs - useful between tests\n */\n clear(): void {\n this.jobs.clear();\n }\n\n /**\n * Get all jobs for inspection\n */\n getAllJobs(): JobRecord[] {\n return Array.from(this.jobs.values()).map((j) => ({ ...j }));\n }\n\n /**\n * Get jobs by status for inspection\n */\n getJobsByStatus(status: JobStatus): JobRecord[] {\n return Array.from(this.jobs.values())\n .filter((j) => j.status === status)\n .map((j) => ({ ...j }));\n }\n\n /**\n * Get a specific job by ID\n */\n getJob(jobId: string): JobRecord | null {\n const job = this.jobs.get(jobId);\n return job ? { ...job } : null;\n }\n\n /**\n * Get the worker ID for this queue instance\n */\n getWorkerId(): string {\n return this.workerId;\n }\n\n /**\n * Set max attempts for new jobs\n */\n setDefaultMaxAttempts(maxAttempts: number): void {\n this.defaultMaxAttempts = maxAttempts;\n }\n\n /**\n * Simulate a worker crash by releasing a job's lock without completing it\n */\n simulateCrash(jobId: string): void {\n const job = this.jobs.get(jobId);\n if (job && job.status === \"RUNNING\") {\n // Don't change status - just leave it locked by the \"crashed\" worker\n // releaseStaleJobs() will clean it up\n }\n }\n\n /**\n * Move a suspended job back to pending (for manual resume testing)\n */\n resumeJob(jobId: string): void {\n const job = this.jobs.get(jobId);\n if (job && job.status === \"SUSPENDED\") {\n const updated: JobRecord = {\n ...job,\n status: \"PENDING\",\n nextPollAt: null,\n updatedAt: new Date(),\n };\n this.jobs.set(jobId, updated);\n }\n }\n\n /**\n * Set lockedAt for testing stale job scenarios\n */\n setJobLockedAt(jobId: string, lockedAt: Date): void {\n const job = this.jobs.get(jobId);\n if (job) {\n const updated: JobRecord = {\n ...job,\n lockedAt,\n };\n this.jobs.set(jobId, updated);\n }\n }\n\n /**\n * Set nextPollAt for testing suspended job polling\n */\n setJobNextPollAt(jobId: string, nextPollAt: Date | null): void {\n const job = this.jobs.get(jobId);\n if (job) {\n const updated: JobRecord = {\n ...job,\n nextPollAt,\n };\n this.jobs.set(jobId, updated);\n }\n }\n}\n","/**\n * In-Memory Workflow Persistence\n *\n * A complete in-memory implementation of WorkflowPersistence for testing.\n * All data is stored in Maps and lost when the instance is garbage collected.\n *\n * @example\n * ```typescript\n * import { InMemoryWorkflowPersistence } from '@bratsos/workflow-engine/testing';\n *\n * const persistence = new InMemoryWorkflowPersistence();\n * // Use in tests...\n * persistence.clear(); // Reset between tests\n * ```\n */\n\nimport { randomUUID } from \"crypto\";\nimport {\n type AnnotationFilters,\n type CreateAnnotationInput,\n type CreateLogInput,\n type CreateOutboxEventInput,\n type CreateRunInput,\n type CreateStageInput,\n type IdempotencyRecord,\n type OutboxRecord,\n type SaveArtifactInput,\n StaleVersionError,\n type UpdateRunInput,\n type UpdateStageInput,\n type UpsertStageInput,\n type WorkflowAnnotationRecord,\n type WorkflowArtifactRecord,\n type WorkflowLogRecord,\n type WorkflowPersistence,\n type WorkflowRunRecord,\n type WorkflowStageRecord,\n type WorkflowStageStatus,\n type WorkflowStatus,\n} from \"../persistence/interface.js\";\n\nexport class InMemoryWorkflowPersistence implements WorkflowPersistence {\n private runs = new Map<string, WorkflowRunRecord>();\n private stages = new Map<string, WorkflowStageRecord>();\n private logs = new Map<string, WorkflowLogRecord>();\n private artifacts = new Map<string, WorkflowArtifactRecord>();\n private annotations: WorkflowAnnotationRecord[] = [];\n private outbox: OutboxRecord[] = [];\n private idempotencyKeys = new Map<string, IdempotencyRecord>();\n private idempotencyInProgress = new Set<string>();\n private outboxSequences = new Map<string, number>();\n\n // Helper to generate composite keys for stages\n private stageKey(runId: string, stageId: string): string {\n return `${runId}:${stageId}`;\n }\n\n // Helper to generate composite keys for artifacts\n private artifactKey(runId: string, key: string): string {\n return `${runId}:${key}`;\n }\n\n private idempotencyCompositeKey(commandType: string, key: string): string {\n return `${commandType}:${key}`;\n }\n\n async withTransaction<T>(\n fn: (tx: WorkflowPersistence) => Promise<T>,\n ): Promise<T> {\n return fn(this);\n }\n\n // ============================================================================\n // WorkflowRun Operations\n // ============================================================================\n\n async createRun(data: CreateRunInput): Promise<WorkflowRunRecord> {\n const now = new Date();\n const record: WorkflowRunRecord = {\n id: data.id ?? randomUUID(),\n createdAt: now,\n updatedAt: now,\n version: 1,\n workflowId: data.workflowId,\n workflowName: data.workflowName,\n workflowType: data.workflowType,\n status: \"PENDING\",\n startedAt: null,\n completedAt: null,\n duration: null,\n input: data.input,\n output: null,\n config: data.config ?? {},\n totalCost: 0,\n totalTokens: 0,\n priority: data.priority ?? 5,\n metadata: data.metadata ?? null,\n };\n this.runs.set(record.id, record);\n return { ...record };\n }\n\n async updateRun(id: string, data: UpdateRunInput): Promise<void> {\n const run = this.runs.get(id);\n if (!run) {\n throw new Error(`WorkflowRun not found: ${id}`);\n }\n\n if (\n data.expectedVersion !== undefined &&\n run.version !== data.expectedVersion\n ) {\n throw new StaleVersionError(\n \"WorkflowRun\",\n id,\n data.expectedVersion,\n run.version,\n );\n }\n\n const { expectedVersion: _, ...rest } = data;\n const updated: WorkflowRunRecord = {\n ...run,\n ...rest,\n updatedAt: new Date(),\n version: run.version + 1,\n };\n this.runs.set(id, updated);\n }\n\n async getRun(id: string): Promise<WorkflowRunRecord | null> {\n const run = this.runs.get(id);\n return run ? { ...run } : null;\n }\n\n async getRunStatus(id: string): Promise<WorkflowStatus | null> {\n const run = this.runs.get(id);\n return run?.status ?? null;\n }\n\n async getRunsByStatus(status: WorkflowStatus): Promise<WorkflowRunRecord[]> {\n return Array.from(this.runs.values())\n .filter((run) => run.status === status)\n .map((run) => ({ ...run }));\n }\n\n async getStuckRuns(stuckSince: Date): Promise<WorkflowRunRecord[]> {\n const runningRuns = await this.getRunsByStatus(\"RUNNING\");\n return runningRuns.filter((run) => {\n // Find all stages for this run (deduplicate by ID since stages are stored with composite keys)\n const seenIds = new Set<string>();\n const stages = Array.from(this.stages.values()).filter((s) => {\n if (s.workflowRunId !== run.id) return false;\n if (seenIds.has(s.id)) return false;\n seenIds.add(s.id);\n return true;\n });\n const lastStageUpdate = stages.reduce(\n (max, s) => (s.updatedAt > max ? s.updatedAt : max),\n new Date(0),\n );\n const lastActivity =\n run.updatedAt > lastStageUpdate ? run.updatedAt : lastStageUpdate;\n return lastActivity <= stuckSince;\n });\n }\n\n async claimPendingRun(id: string): Promise<boolean> {\n const run = this.runs.get(id);\n if (!run || run.status !== \"PENDING\") {\n return false;\n }\n\n // Atomically update status to RUNNING\n const updated: WorkflowRunRecord = {\n ...run,\n status: \"RUNNING\",\n startedAt: new Date(),\n updatedAt: new Date(),\n version: run.version + 1,\n };\n this.runs.set(id, updated);\n return true;\n }\n\n async claimNextPendingRun(): Promise<WorkflowRunRecord | null> {\n // Find all pending runs\n const pendingRuns = Array.from(this.runs.values())\n .filter((run) => run.status === \"PENDING\")\n // Sort by priority (highest first), then by createdAt (oldest first - FIFO)\n .sort((a, b) => {\n if (a.priority !== b.priority) {\n return b.priority - a.priority; // Higher priority first\n }\n return a.createdAt.getTime() - b.createdAt.getTime(); // Oldest first\n });\n\n if (pendingRuns.length === 0) {\n return null;\n }\n\n // Get the first one and atomically claim it\n const runToClaim = pendingRuns[0];\n\n // Double-check it's still pending (simulates FOR UPDATE SKIP LOCKED behavior)\n const currentRun = this.runs.get(runToClaim.id);\n if (!currentRun || currentRun.status !== \"PENDING\") {\n // Another worker claimed it between our query and now\n // In real FOR UPDATE SKIP LOCKED, this row would be skipped\n // Try the next one recursively\n return this.claimNextPendingRun();\n }\n\n // Atomically update status to RUNNING\n const claimed: WorkflowRunRecord = {\n ...currentRun,\n status: \"RUNNING\",\n startedAt: new Date(),\n updatedAt: new Date(),\n version: currentRun.version + 1,\n };\n this.runs.set(claimed.id, claimed);\n\n return { ...claimed };\n }\n\n // ============================================================================\n // WorkflowStage Operations\n // ============================================================================\n\n async createStage(data: CreateStageInput): Promise<WorkflowStageRecord> {\n const now = new Date();\n const id = randomUUID();\n const record: WorkflowStageRecord = {\n id,\n createdAt: now,\n updatedAt: now,\n version: 1,\n workflowRunId: data.workflowRunId,\n stageId: data.stageId,\n stageName: data.stageName,\n stageNumber: data.stageNumber,\n executionGroup: data.executionGroup,\n attempt: data.attempt ?? 0,\n status: data.status ?? \"PENDING\",\n startedAt: data.startedAt ?? null,\n completedAt: null,\n duration: null,\n inputData: data.inputData ?? null,\n outputData: null,\n config: data.config ?? null,\n suspendedState: null,\n resumeData: null,\n nextPollAt: null,\n pollInterval: null,\n maxWaitUntil: null,\n metrics: null,\n embeddingInfo: null,\n errorMessage: null,\n };\n\n this.stages.set(id, record);\n // Also index by composite key for lookups\n this.stages.set(this.stageKey(data.workflowRunId, data.stageId), record);\n return { ...record };\n }\n\n async upsertStage(data: UpsertStageInput): Promise<WorkflowStageRecord> {\n const key = this.stageKey(data.workflowRunId, data.stageId);\n const existing = this.stages.get(key);\n\n if (existing) {\n const updated: WorkflowStageRecord = {\n ...existing,\n ...data.update,\n updatedAt: new Date(),\n version: existing.version + 1,\n };\n this.stages.set(existing.id, updated);\n this.stages.set(key, updated);\n return { ...updated };\n } else {\n return this.createStage(data.create);\n }\n }\n\n async updateStage(id: string, data: UpdateStageInput): Promise<void> {\n const stage = this.stages.get(id);\n if (!stage) {\n throw new Error(`WorkflowStage not found: ${id}`);\n }\n\n if (\n data.expectedVersion !== undefined &&\n stage.version !== data.expectedVersion\n ) {\n throw new StaleVersionError(\n \"WorkflowStage\",\n id,\n data.expectedVersion,\n stage.version,\n );\n }\n\n const { expectedVersion: _, ...rest } = data;\n const updated: WorkflowStageRecord = {\n ...stage,\n ...rest,\n updatedAt: new Date(),\n version: stage.version + 1,\n };\n this.stages.set(id, updated);\n this.stages.set(this.stageKey(stage.workflowRunId, stage.stageId), updated);\n }\n\n async updateStageByRunAndStageId(\n workflowRunId: string,\n stageId: string,\n data: UpdateStageInput,\n ): Promise<void> {\n const key = this.stageKey(workflowRunId, stageId);\n const stage = this.stages.get(key);\n if (!stage) {\n throw new Error(`WorkflowStage not found: ${workflowRunId}/${stageId}`);\n }\n\n if (\n data.expectedVersion !== undefined &&\n stage.version !== data.expectedVersion\n ) {\n throw new StaleVersionError(\n \"WorkflowStage\",\n `${workflowRunId}/${stageId}`,\n data.expectedVersion,\n stage.version,\n );\n }\n\n const { expectedVersion: _, ...rest } = data;\n const updated: WorkflowStageRecord = {\n ...stage,\n ...rest,\n updatedAt: new Date(),\n version: stage.version + 1,\n };\n this.stages.set(stage.id, updated);\n this.stages.set(key, updated);\n }\n\n async getStage(\n runId: string,\n stageId: string,\n ): Promise<WorkflowStageRecord | null> {\n const key = this.stageKey(runId, stageId);\n const stage = this.stages.get(key);\n return stage ? { ...stage } : null;\n }\n\n async getStageById(id: string): Promise<WorkflowStageRecord | null> {\n const stage = this.stages.get(id);\n return stage ? { ...stage } : null;\n }\n\n async getStagesByRun(\n runId: string,\n options?: { status?: WorkflowStageStatus; orderBy?: \"asc\" | \"desc\" },\n ): Promise<WorkflowStageRecord[]> {\n // Use a Set to track seen IDs and avoid duplicates from composite keys\n const seenIds = new Set<string>();\n let stages = Array.from(this.stages.values()).filter((s) => {\n if (s.workflowRunId !== runId) return false;\n if (seenIds.has(s.id)) return false;\n seenIds.add(s.id);\n return true;\n });\n\n if (options?.status) {\n stages = stages.filter((s) => s.status === options.status);\n }\n\n // Sort by stageNumber\n stages.sort((a, b) => {\n const diff = a.stageNumber - b.stageNumber;\n return options?.orderBy === \"desc\" ? -diff : diff;\n });\n\n return stages.map((s) => ({ ...s }));\n }\n\n async getSuspendedStages(beforeDate: Date): Promise<WorkflowStageRecord[]> {\n const seenIds = new Set<string>();\n return Array.from(this.stages.values())\n .filter((s) => {\n if (seenIds.has(s.id)) return false;\n seenIds.add(s.id);\n return (\n s.status === \"SUSPENDED\" &&\n s.nextPollAt !== null &&\n s.nextPollAt <= beforeDate\n );\n })\n .map((s) => ({ ...s }));\n }\n\n async getFirstSuspendedStageReadyToResume(\n runId: string,\n ): Promise<WorkflowStageRecord | null> {\n const stages = await this.getStagesByRun(runId, { status: \"SUSPENDED\" });\n const now = new Date();\n const ready = stages.find((s) => s.nextPollAt && s.nextPollAt <= now);\n return ready ?? null;\n }\n\n async getFirstFailedStage(\n runId: string,\n ): Promise<WorkflowStageRecord | null> {\n const stages = await this.getStagesByRun(runId, { status: \"FAILED\" });\n return stages[0] ?? null;\n }\n\n async getLastCompletedStage(\n runId: string,\n ): Promise<WorkflowStageRecord | null> {\n const stages = await this.getStagesByRun(runId, {\n status: \"COMPLETED\",\n orderBy: \"desc\",\n });\n return stages[0] ?? null;\n }\n\n async getLastCompletedStageBefore(\n runId: string,\n executionGroup: number,\n ): Promise<WorkflowStageRecord | null> {\n const stages = await this.getStagesByRun(runId, {\n status: \"COMPLETED\",\n orderBy: \"desc\",\n });\n const before = stages.filter((s) => s.executionGroup < executionGroup);\n return before[0] ?? null;\n }\n\n async deleteStage(id: string): Promise<void> {\n const stage = this.stages.get(id);\n if (stage) {\n this.stages.delete(id);\n this.stages.delete(this.stageKey(stage.workflowRunId, stage.stageId));\n // Mirror Prisma `onDelete: SetNull` on WorkflowAnnotation.workflowStage:\n // surviving annotations keep their data but lose the FK to the\n // deleted stage record. Their `attempt` value already captured at\n // write time still disambiguates them from new attempts.\n for (const annotation of this.annotations) {\n if (annotation.workflowStageRecordId === id) {\n annotation.workflowStageRecordId = null;\n }\n }\n }\n }\n\n // ============================================================================\n // WorkflowLog Operations\n // ============================================================================\n\n async createLog(data: CreateLogInput): Promise<void> {\n const record: WorkflowLogRecord = {\n id: randomUUID(),\n createdAt: new Date(),\n workflowRunId: data.workflowRunId ?? null,\n workflowStageId: data.workflowStageId ?? null,\n level: data.level,\n message: data.message,\n metadata: data.metadata ?? null,\n };\n this.logs.set(record.id, record);\n }\n\n // ============================================================================\n // Outbox Operations\n // ============================================================================\n\n async appendOutboxEvents(events: CreateOutboxEventInput[]): Promise<void> {\n for (const event of events) {\n const currentSeq = this.outboxSequences.get(event.workflowRunId) ?? 0;\n const nextSeq = currentSeq + 1;\n this.outboxSequences.set(event.workflowRunId, nextSeq);\n\n const record: OutboxRecord = {\n id: randomUUID(),\n workflowRunId: event.workflowRunId,\n sequence: nextSeq,\n eventType: event.eventType,\n payload: event.payload,\n causationId: event.causationId,\n occurredAt: event.occurredAt,\n publishedAt: null,\n retryCount: 0,\n dlqAt: null,\n };\n this.outbox.push(record);\n }\n }\n\n async getUnpublishedOutboxEvents(limit?: number): Promise<OutboxRecord[]> {\n const effectiveLimit = limit ?? 100;\n return this.outbox\n .filter((r) => r.publishedAt === null && r.dlqAt === null)\n .sort((a, b) => {\n const runCmp = a.workflowRunId.localeCompare(b.workflowRunId);\n if (runCmp !== 0) return runCmp;\n return a.sequence - b.sequence;\n })\n .slice(0, effectiveLimit)\n .map((r) => ({ ...r }));\n }\n\n async markOutboxEventsPublished(ids: string[]): Promise<void> {\n const idSet = new Set(ids);\n for (const record of this.outbox) {\n if (idSet.has(record.id)) {\n record.publishedAt = new Date();\n }\n }\n }\n\n async incrementOutboxRetryCount(id: string): Promise<number> {\n const record = this.outbox.find((r) => r.id === id);\n if (!record) throw new Error(`Outbox event not found: ${id}`);\n record.retryCount++;\n return record.retryCount;\n }\n\n async moveOutboxEventToDLQ(id: string): Promise<void> {\n const record = this.outbox.find((r) => r.id === id);\n if (!record) throw new Error(`Outbox event not found: ${id}`);\n record.dlqAt = new Date();\n }\n\n async replayDLQEvents(maxEvents: number): Promise<number> {\n const dlqEvents = this.outbox\n .filter((r) => r.dlqAt !== null)\n .slice(0, maxEvents);\n for (const record of dlqEvents) {\n record.dlqAt = null;\n record.retryCount = 0;\n }\n return dlqEvents.length;\n }\n\n // ============================================================================\n // Idempotency Operations\n // ============================================================================\n\n async acquireIdempotencyKey(\n key: string,\n commandType: string,\n ): Promise<\n | { status: \"acquired\" }\n | { status: \"replay\"; result: unknown }\n | { status: \"in_progress\" }\n > {\n const compositeKey = this.idempotencyCompositeKey(commandType, key);\n const record = this.idempotencyKeys.get(compositeKey);\n if (record) {\n return { status: \"replay\", result: record.result };\n }\n if (this.idempotencyInProgress.has(compositeKey)) {\n return { status: \"in_progress\" };\n }\n this.idempotencyInProgress.add(compositeKey);\n return { status: \"acquired\" };\n }\n\n async completeIdempotencyKey(\n key: string,\n commandType: string,\n result: unknown,\n ): Promise<void> {\n const compositeKey = this.idempotencyCompositeKey(commandType, key);\n this.idempotencyInProgress.delete(compositeKey);\n this.idempotencyKeys.set(compositeKey, {\n key,\n commandType,\n result,\n createdAt: new Date(),\n });\n }\n\n async releaseIdempotencyKey(key: string, commandType: string): Promise<void> {\n this.idempotencyInProgress.delete(\n this.idempotencyCompositeKey(commandType, key),\n );\n }\n\n // ============================================================================\n // WorkflowArtifact Operations\n // ============================================================================\n\n async saveArtifact(data: SaveArtifactInput): Promise<void> {\n const now = new Date();\n const key = this.artifactKey(data.workflowRunId, data.key);\n const existing = this.artifacts.get(key);\n\n const record: WorkflowArtifactRecord = {\n id: existing?.id ?? randomUUID(),\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n workflowRunId: data.workflowRunId,\n workflowStageId: data.workflowStageId ?? null,\n key: data.key,\n type: data.type,\n data: data.data,\n size: data.size,\n metadata: data.metadata ?? null,\n };\n this.artifacts.set(key, record);\n }\n\n async loadArtifact(runId: string, key: string): Promise<unknown> {\n const artifact = this.artifacts.get(this.artifactKey(runId, key));\n if (!artifact) {\n throw new Error(`Artifact not found: ${runId}/${key}`);\n }\n return artifact.data;\n }\n\n async hasArtifact(runId: string, key: string): Promise<boolean> {\n return this.artifacts.has(this.artifactKey(runId, key));\n }\n\n async deleteArtifact(runId: string, key: string): Promise<void> {\n this.artifacts.delete(this.artifactKey(runId, key));\n }\n\n async listArtifacts(runId: string): Promise<WorkflowArtifactRecord[]> {\n return Array.from(this.artifacts.values())\n .filter((a) => a.workflowRunId === runId)\n .map((a) => ({ ...a }));\n }\n\n async getStageIdForArtifact(\n runId: string,\n stageId: string,\n ): Promise<string | null> {\n const stage = await this.getStage(runId, stageId);\n return stage?.id ?? null;\n }\n\n // ============================================================================\n // WorkflowAnnotation Operations\n // ============================================================================\n\n async appendAnnotations(inputs: CreateAnnotationInput[]): Promise<void> {\n for (const input of inputs) {\n // Honor the (workflowRunId, key, idempotencyKey) unique constraint.\n if (input.idempotencyKey !== null && input.idempotencyKey !== undefined) {\n const exists = this.annotations.some(\n (a) =>\n a.workflowRunId === input.workflowRunId &&\n a.key === input.key &&\n a.idempotencyKey === input.idempotencyKey,\n );\n if (exists) continue;\n }\n\n const record: WorkflowAnnotationRecord = {\n id: randomUUID(),\n createdAt: new Date(),\n workflowRunId: input.workflowRunId,\n workflowStageRecordId: input.workflowStageRecordId ?? null,\n attempt: input.attempt ?? 0,\n scope: input.scope,\n scopeId: input.scopeId ?? null,\n actorKind: input.actor?.kind ?? null,\n actorId: input.actor?.id ?? null,\n actorVersion: input.actor?.version ?? null,\n key: input.key,\n value: input.value,\n payload: input.payload ?? null,\n idempotencyKey: input.idempotencyKey ?? null,\n };\n this.annotations.push(record);\n }\n }\n\n async listAnnotations(\n workflowRunId: string,\n filters: AnnotationFilters = {},\n ): Promise<WorkflowAnnotationRecord[]> {\n let rows = this.annotations.filter(\n (a) => a.workflowRunId === workflowRunId,\n );\n\n if (filters.key !== undefined) {\n rows = rows.filter((a) => a.key === filters.key);\n } else if (filters.keyPrefix !== undefined) {\n const prefix = filters.keyPrefix;\n rows = rows.filter((a) => a.key.startsWith(prefix));\n }\n\n if (filters.scope !== undefined) {\n rows = rows.filter((a) => a.scope === filters.scope);\n }\n if (filters.scopeId !== undefined) {\n rows = rows.filter((a) => a.scopeId === filters.scopeId);\n }\n if (filters.actorId !== undefined) {\n rows = rows.filter((a) => a.actorId === filters.actorId);\n }\n if (filters.actorKind !== undefined) {\n rows = rows.filter((a) => a.actorKind === filters.actorKind);\n }\n if (filters.attempt !== undefined) {\n rows = rows.filter((a) => a.attempt === filters.attempt);\n }\n if (filters.since !== undefined) {\n const since = filters.since;\n rows = rows.filter((a) => a.createdAt >= since);\n }\n if (filters.until !== undefined) {\n const until = filters.until;\n rows = rows.filter((a) => a.createdAt <= until);\n }\n\n // Sort by createdAt with id as tiebreaker (matches Prisma adapter,\n // keeps batched-insert ordering deterministic).\n rows.sort((a, b) => {\n const cmp = a.createdAt.getTime() - b.createdAt.getTime();\n if (cmp !== 0) return cmp;\n return a.id.localeCompare(b.id);\n });\n\n const limit = filters.limit ?? 1000;\n return rows.slice(0, limit).map((a) => ({ ...a }));\n }\n\n // ============================================================================\n // Stage Output Convenience Method\n // ============================================================================\n\n async saveStageOutput(\n runId: string,\n workflowType: string,\n stageId: string,\n output: unknown,\n ): Promise<string> {\n const key = `workflow-v2/${workflowType}/${runId}/${stageId}/output.json`;\n const stageDbId = await this.getStageIdForArtifact(runId, stageId);\n\n await this.saveArtifact({\n workflowRunId: runId,\n workflowStageId: stageDbId ?? undefined,\n key,\n type: \"STAGE_OUTPUT\",\n data: output,\n size: JSON.stringify(output).length,\n });\n\n return key;\n }\n\n // ============================================================================\n // Test Helpers\n // ============================================================================\n\n /**\n * Clear all data - useful between tests\n */\n clear(): void {\n this.runs.clear();\n this.stages.clear();\n this.logs.clear();\n this.artifacts.clear();\n this.annotations = [];\n this.outbox = [];\n this.idempotencyKeys.clear();\n this.idempotencyInProgress.clear();\n this.outboxSequences.clear();\n }\n\n /**\n * Get all runs for inspection\n */\n getAllRuns(): WorkflowRunRecord[] {\n return Array.from(this.runs.values()).map((r) => ({ ...r }));\n }\n\n /**\n * Get all stages for inspection\n */\n getAllStages(): WorkflowStageRecord[] {\n // Filter out composite key duplicates\n return Array.from(this.stages.values())\n .filter((s) => this.stages.get(s.id) === s)\n .map((s) => ({ ...s }));\n }\n\n /**\n * Get all logs for inspection\n */\n getAllLogs(): WorkflowLogRecord[] {\n return Array.from(this.logs.values()).map((l) => ({ ...l }));\n }\n\n /**\n * Get all artifacts for inspection\n */\n getAllArtifacts(): WorkflowArtifactRecord[] {\n return Array.from(this.artifacts.values()).map((a) => ({ ...a }));\n }\n\n /**\n * Get all annotations for inspection\n */\n getAllAnnotations(): WorkflowAnnotationRecord[] {\n return this.annotations.map((a) => ({ ...a }));\n }\n}\n"]}
|