@entifix/workflow 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine/make-flow-engine.d.ts +8 -0
- package/dist/engine/make-flow-engine.d.ts.map +1 -1
- package/dist/engine/make-flow-engine.js +8 -1
- package/dist/engine/make-flow-engine.js.map +1 -1
- package/dist/interpreter/bindings.d.ts +25 -0
- package/dist/interpreter/bindings.d.ts.map +1 -0
- package/dist/interpreter/bindings.js +83 -0
- package/dist/interpreter/bindings.js.map +1 -0
- package/dist/interpreter/slip-workflow.d.ts +3 -1
- package/dist/interpreter/slip-workflow.d.ts.map +1 -1
- package/dist/interpreter/slip-workflow.js +7 -4
- package/dist/interpreter/slip-workflow.js.map +1 -1
- package/package.json +11 -11
|
@@ -20,4 +20,12 @@ export declare const makeFlowEngine: Effect.Effect<FlowEngine, never, FlowStatus
|
|
|
20
20
|
* every call runs under.
|
|
21
21
|
*/
|
|
22
22
|
export declare const FlowEngineLayer: (options: InterpreterOptions) => Layer.Layer<FlowEngineTag, never, import("@entifix/transactions").OutboxTag | import("@entifix/transactions").BulkheadTag | import("@entifix/transactions").CircuitBreakerTag | import("@entifix/transactions").ParticipantClientTag | import("@entifix/transactions").RetryBudgetTag | FlowStatusStoreTag | WorkflowEngine.WorkflowEngine>;
|
|
23
|
+
/**
|
|
24
|
+
* The flow engine over Effect's in-memory workflow engine: every flow lives and
|
|
25
|
+
* dies with the process. For a single-process host — an example, a test, a
|
|
26
|
+
* tool — whose flows need the interpreter's semantics but not its durability;
|
|
27
|
+
* a fleet takes `@entifix/workflow/postgres`'s engines instead, and nothing
|
|
28
|
+
* else in its composition changes.
|
|
29
|
+
*/
|
|
30
|
+
export declare const MemoryFlowEngineLayer: (options: InterpreterOptions) => Layer.Layer<FlowEngineTag, never, import("@entifix/transactions").OutboxTag | import("@entifix/transactions").BulkheadTag | import("@entifix/transactions").CircuitBreakerTag | import("@entifix/transactions").ParticipantClientTag | import("@entifix/transactions").RetryBudgetTag | FlowStatusStoreTag>;
|
|
23
31
|
//# sourceMappingURL=make-flow-engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"make-flow-engine.d.ts","sourceRoot":"","sources":["../../src/engine/make-flow-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,aAAa,EAGd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAW,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AACxD,OAAO,EAAmB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAElE,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEpE;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,sFAoGzB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,SAAS,kBAAkB,gVAGxD,CAAC"}
|
|
1
|
+
{"version":3,"file":"make-flow-engine.d.ts","sourceRoot":"","sources":["../../src/engine/make-flow-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,aAAa,EAGd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAW,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AACxD,OAAO,EAAmB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAElE,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEpE;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,sFAoGzB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,SAAS,kBAAkB,gVAGxD,CAAC;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAAI,SAAS,kBAAkB,gTACS,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
2
|
import { FlowEngineTag, FlowNotFound, FlowSignalRejected } from '@entifix/transactions';
|
|
3
3
|
import { Context, Effect, Layer, Option } from 'effect';
|
|
4
|
-
import { DurableDeferred } from 'effect/workflow';
|
|
4
|
+
import { DurableDeferred, WorkflowEngine } from 'effect/workflow';
|
|
5
5
|
import { SlipWorkflow, SlipWorkflowLayer, waitFor } from '../interpreter/slip-workflow.js';
|
|
6
6
|
import { FlowStatusStoreTag } from '../status/flow-status-store.js';
|
|
7
7
|
/**
|
|
@@ -100,5 +100,12 @@ import { FlowStatusStoreTag } from '../status/flow-status-store.js';
|
|
|
100
100
|
* outbox its events go through, and the breaker, bulkhead and retry budget
|
|
101
101
|
* every call runs under.
|
|
102
102
|
*/ export const FlowEngineLayer = (options)=>Layer.effect(FlowEngineTag, makeFlowEngine).pipe(Layer.provideMerge(SlipWorkflowLayer(options)));
|
|
103
|
+
/**
|
|
104
|
+
* The flow engine over Effect's in-memory workflow engine: every flow lives and
|
|
105
|
+
* dies with the process. For a single-process host — an example, a test, a
|
|
106
|
+
* tool — whose flows need the interpreter's semantics but not its durability;
|
|
107
|
+
* a fleet takes `@entifix/workflow/postgres`'s engines instead, and nothing
|
|
108
|
+
* else in its composition changes.
|
|
109
|
+
*/ export const MemoryFlowEngineLayer = (options)=>FlowEngineLayer(options).pipe(Layer.provide(WorkflowEngine.layerMemory));
|
|
103
110
|
|
|
104
111
|
//# sourceMappingURL=make-flow-engine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/engine/make-flow-engine.ts"],"sourcesContent":["import {\n type FlowEngine,\n FlowEngineTag,\n FlowNotFound,\n FlowSignalRejected,\n} from '@entifix/transactions';\nimport { Context, Effect, Layer, Option } from 'effect';\nimport { DurableDeferred, WorkflowEngine } from 'effect/workflow';\n\nimport {\n type InterpreterOptions,\n SlipWorkflow,\n SlipWorkflowLayer,\n waitFor,\n} from '../interpreter/slip-workflow.js';\nimport type { FlowRecord } from '../status/flow-status-store.js';\nimport { FlowStatusStoreTag } from '../status/flow-status-store.js';\n\n/**\n * The flow engine port over Effect Workflow\n * ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)).\n * A start records the flow under its key and executes the slip detached — it\n * answers the flow id, never the outcome, which arrives as `flow.*` events and\n * in the status record. A signal is accepted only by a flow parked on exactly\n * that wait.\n */\nexport const makeFlowEngine = Effect.gen(function* () {\n const context = yield* Effect.context<\n WorkflowEngine.WorkflowEngine | FlowStatusStoreTag\n >();\n const store = Context.get(context, FlowStatusStoreTag);\n const within = <A, E>(\n effect: Effect.Effect<A, E, WorkflowEngine.WorkflowEngine>,\n ) => Effect.provideContext(effect, context);\n\n const known = (flowId: string) =>\n Effect.flatMap(store.find(flowId), found =>\n Option.match(found, {\n onNone: () => Effect.fail(new FlowNotFound({ flowId })),\n onSome: Effect.succeed,\n }),\n );\n\n /** Completes the wait `record` is parked on, if `token` names it. */\n const complete = (token: string, outcome: unknown) => (record: FlowRecord) =>\n Effect.gen(function* () {\n // Claimed before the wait is resumed, never after: the resumed flow\n // records its own states, and a `running` written behind them would put\n // a finished flow back to running with nothing left to correct it. The\n // claim is conditional, so a second signal racing this one is refused.\n const claimed = yield* store.claimWait(record.flowId, token);\n if (!claimed)\n return yield* Effect.fail(\n new FlowSignalRejected({ flowId: record.flowId, token }),\n );\n const deferred = waitFor(token);\n yield* within(\n DurableDeferred.succeed(deferred, {\n token: DurableDeferred.tokenFromExecutionId(deferred, {\n workflow: SlipWorkflow,\n executionId: record.executionId,\n }),\n value: outcome,\n }),\n ).pipe(\n // The wait was not resumed, so it is parked again and a retried signal\n // can claim it.\n Effect.onError(() =>\n store\n .update(record.flowId, {\n state: 'waiting',\n step: token,\n waitingFor: token,\n ...(record.correlation === undefined\n ? {}\n : { correlation: record.correlation }),\n })\n .pipe(Effect.ignore),\n ),\n );\n });\n\n const engine: FlowEngine = {\n start: (slip, idempotencyKey) =>\n Effect.gen(function* () {\n const payload = { key: idempotencyKey, slip };\n const executionId = yield* SlipWorkflow.executionId(payload);\n const record = yield* store.register(idempotencyKey, {\n flowId: slip.flowId,\n executionId,\n state: 'running',\n });\n if (record.executionId === executionId && record.flowId === slip.flowId)\n yield* within(SlipWorkflow.execute(payload, { discard: true }));\n return { flowId: record.flowId };\n }),\n\n status: flowId =>\n Effect.map(known(flowId), record => ({\n flowId: record.flowId,\n state: record.state,\n ...(record.step === undefined ? {} : { step: record.step }),\n })),\n\n signal: (flowId, token, outcome) =>\n Effect.flatMap(known(flowId), complete(token, outcome)),\n\n signalCorrelated: (correlation, token, outcome) =>\n Effect.gen(function* () {\n const found = yield* store.findByCorrelation(correlation);\n if (Option.isNone(found))\n return yield* Effect.fail(new FlowNotFound({ flowId: correlation }));\n return yield* complete(token, outcome)(found.value);\n }),\n\n interrupt: flowId =>\n Effect.gen(function* () {\n const record = yield* known(flowId);\n yield* within(SlipWorkflow.interrupt(record.executionId));\n yield* store.update(flowId, {\n state: 'interrupted',\n ...(record.step === undefined ? {} : { step: record.step }),\n });\n }),\n };\n return engine;\n});\n\n/**\n * The flow engine with the interpreter registered. Needs a workflow engine —\n * the in-memory one, or the cluster engine over Postgres from\n * `@entifix/workflow/postgres` — a status store, a participant client, the\n * outbox its events go through, and the breaker, bulkhead and retry budget\n * every call runs under.\n */\nexport const FlowEngineLayer = (options: InterpreterOptions) =>\n Layer.effect(FlowEngineTag, makeFlowEngine).pipe(\n Layer.provideMerge(SlipWorkflowLayer(options)),\n );\n"],"names":["FlowEngineTag","FlowNotFound","FlowSignalRejected","Context","Effect","Layer","Option","DurableDeferred","SlipWorkflow","SlipWorkflowLayer","waitFor","FlowStatusStoreTag","makeFlowEngine","gen","context","store","get","within","effect","provideContext","known","flowId","flatMap","find","found","match","onNone","fail","onSome","succeed","complete","token","outcome","record","claimed","claimWait","deferred","tokenFromExecutionId","workflow","executionId","value","pipe","onError","update","state","step","waitingFor","correlation","undefined","ignore","engine","start","slip","idempotencyKey","payload","key","register","execute","discard","status","map","signal","signalCorrelated","findByCorrelation","isNone","interrupt","FlowEngineLayer","options","provideMerge"],"mappings":";AAAA,SAEEA,aAAa,EACbC,YAAY,EACZC,kBAAkB,QACb,wBAAwB;AAC/B,SAASC,OAAO,EAAEC,MAAM,EAAEC,KAAK,EAAEC,MAAM,QAAQ,SAAS;AACxD,SAASC,eAAe,
|
|
1
|
+
{"version":3,"sources":["../../src/engine/make-flow-engine.ts"],"sourcesContent":["import {\n type FlowEngine,\n FlowEngineTag,\n FlowNotFound,\n FlowSignalRejected,\n} from '@entifix/transactions';\nimport { Context, Effect, Layer, Option } from 'effect';\nimport { DurableDeferred, WorkflowEngine } from 'effect/workflow';\n\nimport {\n type InterpreterOptions,\n SlipWorkflow,\n SlipWorkflowLayer,\n waitFor,\n} from '../interpreter/slip-workflow.js';\nimport type { FlowRecord } from '../status/flow-status-store.js';\nimport { FlowStatusStoreTag } from '../status/flow-status-store.js';\n\n/**\n * The flow engine port over Effect Workflow\n * ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)).\n * A start records the flow under its key and executes the slip detached — it\n * answers the flow id, never the outcome, which arrives as `flow.*` events and\n * in the status record. A signal is accepted only by a flow parked on exactly\n * that wait.\n */\nexport const makeFlowEngine = Effect.gen(function* () {\n const context = yield* Effect.context<\n WorkflowEngine.WorkflowEngine | FlowStatusStoreTag\n >();\n const store = Context.get(context, FlowStatusStoreTag);\n const within = <A, E>(\n effect: Effect.Effect<A, E, WorkflowEngine.WorkflowEngine>,\n ) => Effect.provideContext(effect, context);\n\n const known = (flowId: string) =>\n Effect.flatMap(store.find(flowId), found =>\n Option.match(found, {\n onNone: () => Effect.fail(new FlowNotFound({ flowId })),\n onSome: Effect.succeed,\n }),\n );\n\n /** Completes the wait `record` is parked on, if `token` names it. */\n const complete = (token: string, outcome: unknown) => (record: FlowRecord) =>\n Effect.gen(function* () {\n // Claimed before the wait is resumed, never after: the resumed flow\n // records its own states, and a `running` written behind them would put\n // a finished flow back to running with nothing left to correct it. The\n // claim is conditional, so a second signal racing this one is refused.\n const claimed = yield* store.claimWait(record.flowId, token);\n if (!claimed)\n return yield* Effect.fail(\n new FlowSignalRejected({ flowId: record.flowId, token }),\n );\n const deferred = waitFor(token);\n yield* within(\n DurableDeferred.succeed(deferred, {\n token: DurableDeferred.tokenFromExecutionId(deferred, {\n workflow: SlipWorkflow,\n executionId: record.executionId,\n }),\n value: outcome,\n }),\n ).pipe(\n // The wait was not resumed, so it is parked again and a retried signal\n // can claim it.\n Effect.onError(() =>\n store\n .update(record.flowId, {\n state: 'waiting',\n step: token,\n waitingFor: token,\n ...(record.correlation === undefined\n ? {}\n : { correlation: record.correlation }),\n })\n .pipe(Effect.ignore),\n ),\n );\n });\n\n const engine: FlowEngine = {\n start: (slip, idempotencyKey) =>\n Effect.gen(function* () {\n const payload = { key: idempotencyKey, slip };\n const executionId = yield* SlipWorkflow.executionId(payload);\n const record = yield* store.register(idempotencyKey, {\n flowId: slip.flowId,\n executionId,\n state: 'running',\n });\n if (record.executionId === executionId && record.flowId === slip.flowId)\n yield* within(SlipWorkflow.execute(payload, { discard: true }));\n return { flowId: record.flowId };\n }),\n\n status: flowId =>\n Effect.map(known(flowId), record => ({\n flowId: record.flowId,\n state: record.state,\n ...(record.step === undefined ? {} : { step: record.step }),\n })),\n\n signal: (flowId, token, outcome) =>\n Effect.flatMap(known(flowId), complete(token, outcome)),\n\n signalCorrelated: (correlation, token, outcome) =>\n Effect.gen(function* () {\n const found = yield* store.findByCorrelation(correlation);\n if (Option.isNone(found))\n return yield* Effect.fail(new FlowNotFound({ flowId: correlation }));\n return yield* complete(token, outcome)(found.value);\n }),\n\n interrupt: flowId =>\n Effect.gen(function* () {\n const record = yield* known(flowId);\n yield* within(SlipWorkflow.interrupt(record.executionId));\n yield* store.update(flowId, {\n state: 'interrupted',\n ...(record.step === undefined ? {} : { step: record.step }),\n });\n }),\n };\n return engine;\n});\n\n/**\n * The flow engine with the interpreter registered. Needs a workflow engine —\n * the in-memory one, or the cluster engine over Postgres from\n * `@entifix/workflow/postgres` — a status store, a participant client, the\n * outbox its events go through, and the breaker, bulkhead and retry budget\n * every call runs under.\n */\nexport const FlowEngineLayer = (options: InterpreterOptions) =>\n Layer.effect(FlowEngineTag, makeFlowEngine).pipe(\n Layer.provideMerge(SlipWorkflowLayer(options)),\n );\n\n/**\n * The flow engine over Effect's in-memory workflow engine: every flow lives and\n * dies with the process. For a single-process host — an example, a test, a\n * tool — whose flows need the interpreter's semantics but not its durability;\n * a fleet takes `@entifix/workflow/postgres`'s engines instead, and nothing\n * else in its composition changes.\n */\nexport const MemoryFlowEngineLayer = (options: InterpreterOptions) =>\n FlowEngineLayer(options).pipe(Layer.provide(WorkflowEngine.layerMemory));\n"],"names":["FlowEngineTag","FlowNotFound","FlowSignalRejected","Context","Effect","Layer","Option","DurableDeferred","WorkflowEngine","SlipWorkflow","SlipWorkflowLayer","waitFor","FlowStatusStoreTag","makeFlowEngine","gen","context","store","get","within","effect","provideContext","known","flowId","flatMap","find","found","match","onNone","fail","onSome","succeed","complete","token","outcome","record","claimed","claimWait","deferred","tokenFromExecutionId","workflow","executionId","value","pipe","onError","update","state","step","waitingFor","correlation","undefined","ignore","engine","start","slip","idempotencyKey","payload","key","register","execute","discard","status","map","signal","signalCorrelated","findByCorrelation","isNone","interrupt","FlowEngineLayer","options","provideMerge","MemoryFlowEngineLayer","provide","layerMemory"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FragmentDescriptor, SlipStep } from '@entifix/business/flow';
|
|
2
|
+
/**
|
|
3
|
+
* What a flow has learned so far, by the keys its fragments `provide`, and the
|
|
4
|
+
* inputs each call is given from it
|
|
5
|
+
* ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)).
|
|
6
|
+
*
|
|
7
|
+
* A key is bound in the narrowest scope of the step that provided it — its
|
|
8
|
+
* line, else its segment, else the flow — and a step that `consumes` it reads
|
|
9
|
+
* the nearest: the hold a line's conversion converts is the one taken for that
|
|
10
|
+
* line, not another vendor's. A step outside every segment that consumes a key
|
|
11
|
+
* provided per segment is given all of them, by segment.
|
|
12
|
+
*
|
|
13
|
+
* Built only from what Activities answered, so a replay rebuilds it exactly.
|
|
14
|
+
*/
|
|
15
|
+
export interface Bindings {
|
|
16
|
+
/** Binds what a step's answer provides. */
|
|
17
|
+
readonly record: (step: SlipStep, fragment: FragmentDescriptor | undefined, answer: unknown) => void;
|
|
18
|
+
/**
|
|
19
|
+
* The flat inputs one call is given: the step's pinned parameters, beneath
|
|
20
|
+
* what it consumes, beneath — for an undoing — what its own action answered.
|
|
21
|
+
*/
|
|
22
|
+
readonly inputsFor: (step: SlipStep, fragment: FragmentDescriptor | undefined, kind: 'action' | 'compensation') => Readonly<Record<string, unknown>>;
|
|
23
|
+
}
|
|
24
|
+
export declare const makeBindings: () => Bindings;
|
|
25
|
+
//# sourceMappingURL=bindings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bindings.d.ts","sourceRoot":"","sources":["../../src/interpreter/bindings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAE3E;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,QAAQ;IACvB,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,CACf,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,MAAM,EAAE,OAAO,KACZ,IAAI,CAAC;IACV;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,CAClB,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,IAAI,EAAE,QAAQ,GAAG,cAAc,KAC5B,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACxC;AA8CD,eAAO,MAAM,YAAY,QAAO,QA0D/B,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
const segmentKey = (step)=>step.segment === undefined ? undefined : [
|
|
3
|
+
step.segment.vendor,
|
|
4
|
+
step.segment.paymentMethod
|
|
5
|
+
].filter(Boolean).join('/');
|
|
6
|
+
const scopeKey = (segment, line)=>`${segment != null ? segment : ''}|${line != null ? line : ''}`;
|
|
7
|
+
const isRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
8
|
+
/** A field of an answer: inside its envelope's `data` first, else at its top. */ const field = (answer, key)=>{
|
|
9
|
+
if (!isRecord(answer)) return undefined;
|
|
10
|
+
const data = answer['data'];
|
|
11
|
+
return isRecord(data) && data[key] !== undefined ? data[key] : answer[key];
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* What an answer provides: each key by its own name, and the answer's `id`
|
|
15
|
+
* when a step provides exactly one key the participant did not name — a
|
|
16
|
+
* created record answers its id, not the flow's name for it.
|
|
17
|
+
*/ const provided = (fragment, answer)=>{
|
|
18
|
+
var _ref;
|
|
19
|
+
const keys = Object.keys((_ref = fragment == null ? void 0 : fragment.provides) != null ? _ref : {});
|
|
20
|
+
const values = {};
|
|
21
|
+
for (const key of keys){
|
|
22
|
+
const value = field(answer, key);
|
|
23
|
+
if (value !== undefined) values[key] = value;
|
|
24
|
+
else if (keys.length === 1) {
|
|
25
|
+
const id = field(answer, 'id');
|
|
26
|
+
if (id !== undefined) values[key] = id;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return values;
|
|
30
|
+
};
|
|
31
|
+
export const makeBindings = ()=>{
|
|
32
|
+
const scopes = new Map();
|
|
33
|
+
/** What each step's own action answered, for its undoing. */ const own = new Map();
|
|
34
|
+
/** The name a segment's bindings are given by, to a step outside it. */ const segmentNames = new Map();
|
|
35
|
+
const bind = (scope, values)=>scopes.set(scope, _extends({}, scopes.get(scope), values));
|
|
36
|
+
const consumed = (step, key)=>{
|
|
37
|
+
const segment = segmentKey(step);
|
|
38
|
+
for (const scope of [
|
|
39
|
+
scopeKey(segment, step.line),
|
|
40
|
+
scopeKey(segment, undefined),
|
|
41
|
+
scopeKey(undefined, undefined)
|
|
42
|
+
]){
|
|
43
|
+
var _scopes_get;
|
|
44
|
+
const value = (_scopes_get = scopes.get(scope)) == null ? void 0 : _scopes_get[key];
|
|
45
|
+
if (value !== undefined) return value;
|
|
46
|
+
}
|
|
47
|
+
if (segment !== undefined) return undefined;
|
|
48
|
+
// A step outside every segment reading a key bound per segment: all of
|
|
49
|
+
// them, by vendor — a capture over every vendor's order.
|
|
50
|
+
const bySegment = {};
|
|
51
|
+
for (const [scope, values] of scopes){
|
|
52
|
+
const name = segmentNames.get(scope);
|
|
53
|
+
if (name !== undefined && values[key] !== undefined) bySegment[name] = values[key];
|
|
54
|
+
}
|
|
55
|
+
return Object.keys(bySegment).length === 0 ? undefined : bySegment;
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
record: (step, fragment, answer)=>{
|
|
59
|
+
var _step_segment_vendor;
|
|
60
|
+
const values = provided(fragment, answer);
|
|
61
|
+
const id = field(answer, 'id');
|
|
62
|
+
own.set(step.step, id === undefined ? values : _extends({
|
|
63
|
+
id
|
|
64
|
+
}, values));
|
|
65
|
+
const scope = scopeKey(segmentKey(step), step.line);
|
|
66
|
+
// Only a segment's own bindings are offered by name: a line's are its
|
|
67
|
+
// line's, and the flow's are everyone's already.
|
|
68
|
+
if (step.segment !== undefined && step.line === undefined) segmentNames.set(scope, (_step_segment_vendor = step.segment.vendor) != null ? _step_segment_vendor : String(segmentKey(step)));
|
|
69
|
+
bind(scope, values);
|
|
70
|
+
},
|
|
71
|
+
inputsFor: (step, fragment, kind)=>{
|
|
72
|
+
var _ref;
|
|
73
|
+
const inputs = _extends({}, step.parameters);
|
|
74
|
+
for (const key of Object.keys((_ref = fragment == null ? void 0 : fragment.consumes) != null ? _ref : {})){
|
|
75
|
+
const value = consumed(step, key);
|
|
76
|
+
if (value !== undefined) inputs[key] = value;
|
|
77
|
+
}
|
|
78
|
+
return kind === 'compensation' ? _extends({}, inputs, own.get(step.step)) : inputs;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=bindings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/interpreter/bindings.ts"],"sourcesContent":["import type { FragmentDescriptor, SlipStep } from '@entifix/business/flow';\n\n/**\n * What a flow has learned so far, by the keys its fragments `provide`, and the\n * inputs each call is given from it\n * ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)).\n *\n * A key is bound in the narrowest scope of the step that provided it — its\n * line, else its segment, else the flow — and a step that `consumes` it reads\n * the nearest: the hold a line's conversion converts is the one taken for that\n * line, not another vendor's. A step outside every segment that consumes a key\n * provided per segment is given all of them, by segment.\n *\n * Built only from what Activities answered, so a replay rebuilds it exactly.\n */\nexport interface Bindings {\n /** Binds what a step's answer provides. */\n readonly record: (\n step: SlipStep,\n fragment: FragmentDescriptor | undefined,\n answer: unknown,\n ) => void;\n /**\n * The flat inputs one call is given: the step's pinned parameters, beneath\n * what it consumes, beneath — for an undoing — what its own action answered.\n */\n readonly inputsFor: (\n step: SlipStep,\n fragment: FragmentDescriptor | undefined,\n kind: 'action' | 'compensation',\n ) => Readonly<Record<string, unknown>>;\n}\n\ntype Values = Record<string, unknown>;\n\nconst segmentKey = (step: SlipStep): string | undefined =>\n step.segment === undefined\n ? undefined\n : [step.segment.vendor, step.segment.paymentMethod]\n .filter(Boolean)\n .join('/');\n\nconst scopeKey = (segment: string | undefined, line: string | undefined) =>\n `${segment ?? ''}|${line ?? ''}`;\n\nconst isRecord = (value: unknown): value is Values =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/** A field of an answer: inside its envelope's `data` first, else at its top. */\nconst field = (answer: unknown, key: string): unknown => {\n if (!isRecord(answer)) return undefined;\n const data = answer['data'];\n return isRecord(data) && data[key] !== undefined ? data[key] : answer[key];\n};\n\n/**\n * What an answer provides: each key by its own name, and the answer's `id`\n * when a step provides exactly one key the participant did not name — a\n * created record answers its id, not the flow's name for it.\n */\nconst provided = (\n fragment: FragmentDescriptor | undefined,\n answer: unknown,\n): Values => {\n const keys = Object.keys(fragment?.provides ?? {});\n const values: Values = {};\n for (const key of keys) {\n const value = field(answer, key);\n if (value !== undefined) values[key] = value;\n else if (keys.length === 1) {\n const id = field(answer, 'id');\n if (id !== undefined) values[key] = id;\n }\n }\n return values;\n};\n\nexport const makeBindings = (): Bindings => {\n const scopes = new Map<string, Values>();\n /** What each step's own action answered, for its undoing. */\n const own = new Map<string, Values>();\n /** The name a segment's bindings are given by, to a step outside it. */\n const segmentNames = new Map<string, string>();\n\n const bind = (scope: string, values: Values) =>\n scopes.set(scope, { ...scopes.get(scope), ...values });\n\n const consumed = (step: SlipStep, key: string): unknown => {\n const segment = segmentKey(step);\n for (const scope of [\n scopeKey(segment, step.line),\n scopeKey(segment, undefined),\n scopeKey(undefined, undefined),\n ]) {\n const value = scopes.get(scope)?.[key];\n if (value !== undefined) return value;\n }\n if (segment !== undefined) return undefined;\n // A step outside every segment reading a key bound per segment: all of\n // them, by vendor — a capture over every vendor's order.\n const bySegment: Values = {};\n for (const [scope, values] of scopes) {\n const name = segmentNames.get(scope);\n if (name !== undefined && values[key] !== undefined)\n bySegment[name] = values[key];\n }\n return Object.keys(bySegment).length === 0 ? undefined : bySegment;\n };\n\n return {\n record: (step, fragment, answer) => {\n const values = provided(fragment, answer);\n const id = field(answer, 'id');\n own.set(step.step, id === undefined ? values : { id, ...values });\n const scope = scopeKey(segmentKey(step), step.line);\n // Only a segment's own bindings are offered by name: a line's are its\n // line's, and the flow's are everyone's already.\n if (step.segment !== undefined && step.line === undefined)\n segmentNames.set(\n scope,\n step.segment.vendor ?? String(segmentKey(step)),\n );\n bind(scope, values);\n },\n inputsFor: (step, fragment, kind) => {\n const inputs: Values = { ...step.parameters };\n for (const key of Object.keys(fragment?.consumes ?? {})) {\n const value = consumed(step, key);\n if (value !== undefined) inputs[key] = value;\n }\n return kind === 'compensation'\n ? { ...inputs, ...own.get(step.step) }\n : inputs;\n },\n };\n};\n"],"names":["segmentKey","step","segment","undefined","vendor","paymentMethod","filter","Boolean","join","scopeKey","line","isRecord","value","Array","isArray","field","answer","key","data","provided","fragment","keys","Object","provides","values","length","id","makeBindings","scopes","Map","own","segmentNames","bind","scope","set","get","consumed","bySegment","name","record","String","inputsFor","kind","inputs","parameters","consumes"],"mappings":"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"}
|
|
@@ -77,7 +77,9 @@ export declare const SlipWorkflow: Workflow.Workflow<"entifix/slip", Schema.Stru
|
|
|
77
77
|
readonly segment: Schema.optionalKey<Schema.Struct<{
|
|
78
78
|
readonly vendor: Schema.optionalKey<Schema.String>;
|
|
79
79
|
readonly paymentMethod: Schema.optionalKey<Schema.String>;
|
|
80
|
+
readonly entitlements: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
80
81
|
}>>;
|
|
82
|
+
readonly line: Schema.optionalKey<Schema.String>;
|
|
81
83
|
readonly participant: Schema.optionalKey<Schema.String>;
|
|
82
84
|
readonly call: Schema.optionalKey<Schema.Struct<{
|
|
83
85
|
readonly method: Schema.Literals<readonly ["GET", "POST", "PUT", "PATCH", "DELETE"]>;
|
|
@@ -107,7 +109,7 @@ export declare const SlipWorkflow: Workflow.Workflow<"entifix/slip", Schema.Stru
|
|
|
107
109
|
export declare const waitFor: (step: string) => DurableDeferred.DurableDeferred<Schema.Unknown, Schema.Never>;
|
|
108
110
|
/** Every `slipVersion` the interpreter walks — each must have a journal. */
|
|
109
111
|
export declare const interpretedSlipVersions: readonly number[];
|
|
110
|
-
export declare const interpretSlip: (slip: Slip) => Effect.Effect<"completed" | "
|
|
112
|
+
export declare const interpretSlip: (slip: Slip) => Effect.Effect<"completed" | "compensated" | "failed", EntifixFailure<string, string, import("@entifix/core").FailureCategory>, OutboxTag | BulkheadTag | CircuitBreakerTag | ParticipantClientTag | import("@entifix/transactions").RetryBudgetTag | FlowStatusStoreTag | InterpreterOptionsTag | import("effect/workflow/WorkflowEngine").WorkflowInstance | import("effect/workflow/WorkflowEngine").WorkflowEngine>;
|
|
111
113
|
/** The interpreter registered with the workflow engine, with its options. */
|
|
112
114
|
export declare const SlipWorkflowLayer: (options: InterpreterOptions) => import("effect/Layer").Layer<never, never, OutboxTag | BulkheadTag | CircuitBreakerTag | ParticipantClientTag | import("@entifix/transactions").RetryBudgetTag | FlowStatusStoreTag | import("effect/workflow/WorkflowEngine").WorkflowEngine>;
|
|
113
115
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slip-workflow.d.ts","sourceRoot":"","sources":["../../src/interpreter/slip-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EACpB,IAAI,EAGL,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,KAAK,cAAc,EAMpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,WAAW,EACX,iBAAiB,EAIjB,SAAS,EACT,oBAAoB,EACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,OAAO,EACP,MAAM,EAIN,MAAM,EAEP,MAAM,QAAQ,CAAC;AAChB,OAAO,EAGL,eAAe,EACf,QAAQ,EACT,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAGL,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"slip-workflow.d.ts","sourceRoot":"","sources":["../../src/interpreter/slip-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EACpB,IAAI,EAGL,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,KAAK,cAAc,EAMpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,WAAW,EACX,iBAAiB,EAIjB,SAAS,EACT,oBAAoB,EACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,OAAO,EACP,MAAM,EAIN,MAAM,EAEP,MAAM,QAAQ,CAAC;AAChB,OAAO,EAGL,eAAe,EACf,QAAQ,EACT,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAGL,kBAAkB,EACnB,MAAM,gCAAgC,CAAC;AAGxC;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,OAAO,CAShE,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,WAAW,kEAItB,CAAC;;;;AAEH,uEAAuE;AACvE,qBAAa,gBAAiB,SAAQ,qBAKrC;CAAG;AAEJ,6EAA6E;AAC7E,MAAM,WAAW,SAAS;IACxB,6BAA6B;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,0DAA0D;IAC1D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,yCAAyC;IACzC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,kBAAkB,EAAE,SAIhC,CAAC;AAEF,oFAAoF;AACpF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAClB,WAAW,EAAE,MAAM,KAChB,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,GAAG,SAAS,CAAC;CAC1D;;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,0BAGA;CAAG;AAE9C;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mLAYvB,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,kEAC+B,CAAC;AA4TpE,4EAA4E;AAC5E,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EACd,CAAC;AAExC,eAAO,MAAM,aAAa,GAAI,MAAM,IAAI,2ZACF,CAAC;AAEvC,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,GAAI,SAAS,kBAAkB,mPAK1D,CAAC"}
|
|
@@ -5,6 +5,7 @@ import { BulkheadTag, CircuitBreakerTag, flowEvent, On, OutboxTag, ParticipantCl
|
|
|
5
5
|
import { Context, Effect, Exit, Metric, Schedule, Schema, SchemaTransformation } from 'effect';
|
|
6
6
|
import { Activity, DurableClock, DurableDeferred, Workflow } from 'effect/workflow';
|
|
7
7
|
import { flowStates, FlowStatusStoreTag } from '../status/flow-status-store.js';
|
|
8
|
+
import { makeBindings } from './bindings.js';
|
|
8
9
|
/**
|
|
9
10
|
* A failure as an Activity journals it: the problem body on the way in, the
|
|
10
11
|
* failure its code names on the way out, so a resumed flow sees the typed
|
|
@@ -127,7 +128,7 @@ const segmentOf = (step)=>step.segment === undefined ? undefined : [
|
|
|
127
128
|
var _catalog_get;
|
|
128
129
|
return ((_catalog_get = catalog.get(step.ref)) == null ? void 0 : _catalog_get.kind) === 'pivot';
|
|
129
130
|
});
|
|
130
|
-
const
|
|
131
|
+
const bindings = makeBindings();
|
|
131
132
|
const done = [];
|
|
132
133
|
const record = (name, patch)=>Activity.make({
|
|
133
134
|
name,
|
|
@@ -199,7 +200,7 @@ const segmentOf = (step)=>step.segment === undefined ? undefined : [
|
|
|
199
200
|
step,
|
|
200
201
|
kind,
|
|
201
202
|
idempotencyKey: kind === 'action' ? `${slip.flowId}:${step.step}` : `${slip.flowId}:${step.step}:compensation`,
|
|
202
|
-
|
|
203
|
+
inputs: bindings.inputsFor(step, catalog.get(step.ref), kind)
|
|
203
204
|
})))
|
|
204
205
|
});
|
|
205
206
|
const wait = (step)=>Effect.gen(function*() {
|
|
@@ -216,7 +217,7 @@ const segmentOf = (step)=>step.segment === undefined ? undefined : [
|
|
|
216
217
|
const timeoutMs = (_step_parameters1 = step.parameters) == null ? void 0 : _step_parameters1['timeoutMs'];
|
|
217
218
|
// A durable race, so a replay answers the branch that won rather than
|
|
218
219
|
// racing again.
|
|
219
|
-
|
|
220
|
+
const answer = typeof timeoutMs === 'number' ? yield* DurableDeferred.raceAll({
|
|
220
221
|
name: `race:${step.step}`,
|
|
221
222
|
success: Schema.Unknown,
|
|
222
223
|
error: FlowWaitTimedOut,
|
|
@@ -230,6 +231,7 @@ const segmentOf = (step)=>step.segment === undefined ? undefined : [
|
|
|
230
231
|
}))))
|
|
231
232
|
]
|
|
232
233
|
}) : yield* signalled;
|
|
234
|
+
bindings.record(step, catalog.get(step.ref), answer);
|
|
233
235
|
yield* record(`status:${step.step}:resumed`, {
|
|
234
236
|
state: 'running',
|
|
235
237
|
step: step.step
|
|
@@ -245,10 +247,11 @@ const segmentOf = (step)=>step.segment === undefined ? undefined : [
|
|
|
245
247
|
state: 'running',
|
|
246
248
|
step: step.step
|
|
247
249
|
});
|
|
248
|
-
|
|
250
|
+
const answer = yield* call(step, 'action').pipe(Effect.mapError((failure)=>({
|
|
249
251
|
step,
|
|
250
252
|
failure
|
|
251
253
|
})));
|
|
254
|
+
bindings.record(step, catalog.get(step.ref), answer);
|
|
252
255
|
if (((_catalog_get1 = catalog.get(step.ref)) == null ? void 0 : _catalog_get1.kind) === 'compensatable') done.push(step);
|
|
253
256
|
});
|
|
254
257
|
yield* announce('flow.started', 'started', 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/interpreter/slip-workflow.ts"],"sourcesContent":["import {\n type FragmentCatalog,\n Slip,\n type SlipStep,\n slipSteps,\n} from '@entifix/business/flow';\nimport {\n decodeProblem,\n type EntifixFailure,\n Failure,\n isFailure,\n JsonBody,\n problemOf,\n Timeout,\n} from '@entifix/core';\nimport {\n BulkheadTag,\n CircuitBreakerTag,\n flowEvent,\n type FlowEventName,\n On,\n OutboxTag,\n ParticipantClientTag,\n} from '@entifix/transactions';\nimport {\n Context,\n Effect,\n Exit,\n Metric,\n Schedule,\n Schema,\n SchemaTransformation,\n} from 'effect';\nimport {\n Activity,\n DurableClock,\n DurableDeferred,\n Workflow,\n} from 'effect/workflow';\n\nimport {\n type FlowRecordPatch,\n flowStates,\n FlowStatusStoreTag,\n} from '../status/flow-status-store.js';\n\n/**\n * A failure as an Activity journals it: the problem body on the way in, the\n * failure its code names on the way out, so a resumed flow sees the typed\n * refusal a participant sent rather than a cast.\n */\nexport const JournaledFailure: Schema.Codec<EntifixFailure, unknown> =\n Schema.Unknown.pipe(\n Schema.decodeTo(\n Schema.declare((value): value is EntifixFailure => isFailure(value)),\n SchemaTransformation.transform({\n decode: body => decodeProblem(body),\n encode: failure => problemOf(failure),\n }),\n ),\n );\n\n/**\n * How a flow ended, as the workflow's own result: every step ran, or a\n * refusal before the commit point was undone, or an undoing itself failed and\n * the flow stopped where it was — which a person has to look at.\n */\nexport const FlowOutcome = Schema.Literals([\n 'completed',\n 'compensated',\n 'failed',\n]);\n\n/** A durable wait that outlived its timeout before its signal came. */\nexport class FlowWaitTimedOut extends Failure.timeout<FlowWaitTimedOut>()(\n 'FlowWaitTimedOut',\n 'flowWaitTimedOut',\n { step: Schema.String },\n { message: ({ step }) => `the wait at '${step}' timed out` },\n) {}\n\n/** How long a flow gives each participant call, and each step as a whole. */\nexport interface FlowDials {\n /** One attempt at a call. */\n readonly attemptTimeoutMs: number;\n /** Every attempt at a step together, retries included. */\n readonly stepTimeoutMs: number;\n /** Segments of one stage run at once. */\n readonly concurrency: number;\n}\n\nexport const DEFAULT_FLOW_DIALS: FlowDials = {\n attemptTimeoutMs: 10_000,\n stepTimeoutMs: 60_000,\n concurrency: 4,\n};\n\n/** What the interpreter runs a slip with: the catalog, who announces, the dials. */\nexport interface InterpreterOptions {\n readonly catalog: FragmentCatalog;\n /** The slice the `flow.*` events are announced from. */\n readonly source: string;\n readonly dials?: Partial<FlowDials>;\n /**\n * One participant's own attempt and step bounds, over `dials` — the same\n * shape the breaker's `dialsFor` and the bulkhead's `permitsFor` take, so a\n * participant's dials are one row set however many guards read them.\n */\n readonly dialsFor?: (\n participant: string,\n ) => Partial<Omit<FlowDials, 'concurrency'>> | undefined;\n}\n\n/**\n * The interpreter's options, provided to the workflow it is registered with —\n * the payload is the slip; the catalog and dials are the deployment's.\n */\nexport class InterpreterOptionsTag extends Context.Service<\n InterpreterOptionsTag,\n InterpreterOptions\n>()('@entifix/workflow/InterpreterOptions') {}\n\n/**\n * The one workflow every flow runs as: its payload is the pinned slip and the\n * idempotency key that started it\n * ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)).\n * The execution id derives from the key, so the same key is the same flow.\n *\n * A flow suspended past its commit point is resumed on the retry schedule:\n * a participant that comes back gets the step again, idempotently.\n */\nexport const SlipWorkflow = Workflow.make('entifix/slip', {\n payload: { key: Schema.String, slip: Slip },\n idempotencyKey: payload => payload.key,\n success: FlowOutcome,\n // Its failure is what suspends it past the commit point; it is never the\n // flow's result.\n error: JournaledFailure,\n // Doubling from a second, never more than a minute apart.\n suspendedRetrySchedule: Schedule.min([\n Schedule.exponential('1 second'),\n Schedule.spaced('1 minute'),\n ]),\n});\n\n/** The durable wait a `wait` step parks on, addressed by the step's name. */\nexport const waitFor = (step: string) =>\n DurableDeferred.make(`wait:${step}`, { success: Schema.Unknown });\n\n/** A step's failure, with the step it happened at. */\ninterface StepFailed {\n readonly step: SlipStep;\n readonly failure: EntifixFailure;\n}\n\nconst segmentOf = (step: SlipStep) =>\n step.segment === undefined\n ? undefined\n : [step.segment.vendor, step.segment.paymentMethod]\n .filter(Boolean)\n .join('/');\n\n/**\n * A stage's steps as the groups that run at once: one group per segment when\n * every step names one — a basket's vendors, joined before the shared pivot —\n * and otherwise one group, in order.\n */\nconst groupsOf = (steps: readonly SlipStep[]): readonly SlipStep[][] => {\n if (steps.some(step => segmentOf(step) === undefined)) return [[...steps]];\n const groups = new Map<string, SlipStep[]>();\n for (const step of steps) {\n const key = segmentOf(step) as string;\n groups.set(key, [...(groups.get(key) ?? []), step]);\n }\n return [...groups.values()];\n};\n\n/**\n * Interprets a pinned slip of grammar version 1\n * ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)):\n * each step is an Activity named after it and keyed `<flowId>:<step>`, so a\n * resumed flow replays what already ran and calls a participant at most once\n * per step. Inside the Activity the call runs under the participant's\n * breaker and bulkhead and the retry budget, each attempt bounded and the\n * step as a whole bounded; nothing retries outside it.\n *\n * - Before and at the commit point, a failure — a breaker already open\n * included, which fails fast — compensates what succeeded, in reverse, and\n * the flow ends `compensated`.\n * - After it, a failure suspends the flow at that step: the money is taken,\n * so the flow rolls forward when the participant comes back, never back.\n * - A `wait` step parks the flow on a durable deferred its signal completes,\n * raced with a durable clock when it names `timeoutMs`; it may name a\n * `correlation`, so a sender that knows the order rather than the flow can\n * complete it.\n * - The segments of a stage run at once, bounded, and join before the next.\n *\n * Every transition is announced as a `flow.*` event through the outbox, by an\n * Activity, so it is written once whatever replays. Compensation is explicit\n * rather than a workflow finalizer, so the record says `compensated` only\n * after the last undoing has run — and an undoing that fails stops the flow\n * `failed` at that step instead of pretending.\n */\nconst interpretV1 = (slip: Slip) =>\n Effect.gen(function* () {\n const options = yield* InterpreterOptionsTag;\n const dials = { ...DEFAULT_FLOW_DIALS, ...options.dials };\n const { catalog } = options;\n const steps = slipSteps(slip);\n const ordinalOf = (step: SlipStep) => steps.indexOf(step) + 1;\n const commitPoint = steps.findIndex(\n step => catalog.get(step.ref)?.kind === 'pivot',\n );\n const outputs: Record<string, unknown> = {};\n const done: SlipStep[] = [];\n\n const record = (name: string, patch: FlowRecordPatch) =>\n Activity.make({\n name,\n execute: Effect.flatMap(FlowStatusStoreTag, store =>\n store.update(slip.flowId, patch),\n ).pipe(\n Effect.andThen(\n Metric.update(\n Metric.withAttributes(flowStates, {\n state: patch.state,\n source: options.source,\n }),\n 1,\n ),\n ),\n Effect.orDie,\n ),\n });\n\n const announce = (\n name: FlowEventName,\n step: string,\n ordinal: number,\n failure?: EntifixFailure,\n ) =>\n Activity.make({\n name: `announce:${name}:${step}`,\n execute: Effect.flatMap(OutboxTag, outbox =>\n outbox.enqueue(\n flowEvent({\n name,\n source: options.source,\n at: new Date().toISOString(),\n step: `${name}:${step}`,\n ordinal,\n audience: [\n { kind: 'flow', id: slip.flowId },\n ...(slip.audience ?? []),\n ],\n data: {\n flowId: slip.flowId,\n definition: slip.recipe,\n slipVersion: slip.slipVersion,\n step,\n ...(failure === undefined\n ? {}\n : {\n failure: {\n code: failure.code,\n category: failure.category,\n },\n }),\n },\n }),\n ),\n ).pipe(Effect.orDie),\n });\n\n /** One call, bounded, under the participant's breaker, bulkhead and budget. */\n const guarded = (\n step: SlipStep,\n attempt: Effect.Effect<unknown, EntifixFailure>,\n ) =>\n Effect.gen(function* () {\n const key = step.participant ?? 'participant';\n const bounds = { ...dials, ...options.dialsFor?.(key) };\n const breaker = yield* CircuitBreakerTag;\n const bulkhead = yield* BulkheadTag;\n const timedOut = () => Effect.fail(new Timeout({ dependency: key }));\n return yield* breaker\n .guard(key)(\n bulkhead.withPermit(key)(\n attempt.pipe(\n Effect.timeoutOrElse({\n duration: bounds.attemptTimeoutMs,\n orElse: timedOut,\n }),\n ),\n ),\n )\n .pipe(\n On(Failure.isFamily('technical')).retry({\n key: { dependency: key },\n idempotent: true,\n }),\n Effect.timeoutOrElse({\n duration: bounds.stepTimeoutMs,\n orElse: timedOut,\n }),\n );\n });\n\n const call = (step: SlipStep, kind: 'action' | 'compensation') =>\n Activity.make({\n name: `${step.step}:${kind}`,\n // Whatever the participant answered, as JSON — `undefined` included,\n // which a journal cannot otherwise hold.\n success: JsonBody,\n error: JournaledFailure,\n execute: Effect.flatMap(ParticipantClientTag, participant =>\n guarded(\n step,\n participant.call({\n step,\n kind,\n idempotencyKey:\n kind === 'action'\n ? `${slip.flowId}:${step.step}`\n : `${slip.flowId}:${step.step}:compensation`,\n outputs,\n }),\n ),\n ),\n });\n\n const wait = (step: SlipStep) =>\n Effect.gen(function* () {\n const correlation = step.parameters?.['correlation'];\n yield* record(`status:${step.step}:waiting`, {\n state: 'waiting',\n step: step.step,\n waitingFor: step.step,\n ...(typeof correlation === 'string' ? { correlation } : {}),\n });\n const signalled = DurableDeferred.await(waitFor(step.step));\n const timeoutMs = step.parameters?.['timeoutMs'];\n // A durable race, so a replay answers the branch that won rather than\n // racing again.\n outputs[step.step] =\n typeof timeoutMs === 'number'\n ? yield* DurableDeferred.raceAll({\n name: `race:${step.step}`,\n success: Schema.Unknown,\n error: FlowWaitTimedOut,\n effects: [\n signalled,\n DurableClock.sleep({\n name: `timeout:${step.step}`,\n duration: timeoutMs,\n }).pipe(\n Effect.andThen(\n Effect.fail(new FlowWaitTimedOut({ step: step.step })),\n ),\n ),\n ],\n })\n : yield* signalled;\n yield* record(`status:${step.step}:resumed`, {\n state: 'running',\n step: step.step,\n });\n });\n\n /** One step, its failure tagged with where it happened. */\n const run = (step: SlipStep) =>\n Effect.gen(function* () {\n if (catalog.get(step.ref)?.kind === 'wait')\n return yield* wait(step).pipe(\n Effect.mapError((failure): StepFailed => ({ step, failure })),\n );\n yield* record(`status:${step.step}:running`, {\n state: 'running',\n step: step.step,\n });\n outputs[step.step] = yield* call(step, 'action').pipe(\n Effect.mapError((failure): StepFailed => ({ step, failure })),\n );\n if (catalog.get(step.ref)?.kind === 'compensatable') done.push(step);\n });\n\n yield* announce('flow.started', 'started', 0);\n\n for (const stage of slip.stages) {\n const exits = yield* Effect.forEach(\n groupsOf(stage.steps),\n group => Effect.exit(Effect.forEach(group, run, { discard: true })),\n { concurrency: dials.concurrency },\n );\n // The earliest step that failed decides; a group's failure is its own.\n const [first] = exits\n .flatMap(exit =>\n Exit.isFailure(exit)\n ? exit.cause.reasons.flatMap(reason =>\n // A durable race fails with its losers' interruptions beside\n // the failure that won, so the failure is looked for.\n reason._tag === 'Fail' ? [reason.error] : [],\n )\n : [],\n )\n .sort((a, b) => ordinalOf(a.step) - ordinalOf(b.step));\n if (first === undefined) continue;\n\n const { step, failure } = first;\n if (commitPoint === -1 || steps.indexOf(step) <= commitPoint) {\n for (const undone of [...done].reverse()) {\n const undoing = yield* Effect.exit(call(undone, 'compensation'));\n if (Exit.isFailure(undoing)) {\n yield* record(`status:${undone.step}:failed`, {\n state: 'failed',\n step: undone.step,\n });\n yield* announce(\n 'flow.failed',\n undone.step,\n ordinalOf(undone),\n failure,\n );\n return 'failed' as const;\n }\n }\n yield* record(`status:${step.step}:compensated`, {\n state: 'compensated',\n step: step.step,\n });\n yield* announce('flow.failed', step.step, ordinalOf(step), failure);\n return 'compensated' as const;\n }\n\n yield* record(`status:${step.step}:suspended`, {\n state: 'suspended',\n step: step.step,\n });\n yield* announce('flow.suspended', step.step, ordinalOf(step), failure);\n return yield* Effect.fail(failure).pipe(\n Effect.provideService(Workflow.SuspendOnFailure, true),\n );\n }\n\n yield* record('status:completed', { state: 'completed' });\n yield* announce('flow.completed', 'completed', steps.length + 1);\n return 'completed' as const;\n });\n\n/**\n * One interpreter per grammar version a slip can be written in. A flow runs\n * to its end under the grammar it started with, so a change to how steps are\n * walked — their order, their Activity names — is a new entry here, never an\n * edit to an existing one; the journal replay holds every entry to its\n * recorded command sequence.\n */\nconst INTERPRETERS = { 1: interpretV1 } as const satisfies Record<\n Slip['slipVersion'],\n (slip: Slip) => unknown\n>;\n\n/** Every `slipVersion` the interpreter walks — each must have a journal. */\nexport const interpretedSlipVersions: readonly number[] =\n Object.keys(INTERPRETERS).map(Number);\n\nexport const interpretSlip = (slip: Slip) =>\n INTERPRETERS[slip.slipVersion](slip);\n\n/** The interpreter registered with the workflow engine, with its options. */\nexport const SlipWorkflowLayer = (options: InterpreterOptions) =>\n SlipWorkflow.toLayer(payload =>\n interpretSlip(payload.slip).pipe(\n Effect.provideService(InterpreterOptionsTag, options),\n ),\n );\n"],"names":["Slip","slipSteps","decodeProblem","Failure","isFailure","JsonBody","problemOf","Timeout","BulkheadTag","CircuitBreakerTag","flowEvent","On","OutboxTag","ParticipantClientTag","Context","Effect","Exit","Metric","Schedule","Schema","SchemaTransformation","Activity","DurableClock","DurableDeferred","Workflow","flowStates","FlowStatusStoreTag","JournaledFailure","Unknown","pipe","decodeTo","declare","value","transform","decode","body","encode","failure","FlowOutcome","Literals","FlowWaitTimedOut","timeout","step","String","message","DEFAULT_FLOW_DIALS","attemptTimeoutMs","stepTimeoutMs","concurrency","InterpreterOptionsTag","Service","SlipWorkflow","make","payload","key","slip","idempotencyKey","success","error","suspendedRetrySchedule","min","exponential","spaced","waitFor","segmentOf","segment","undefined","vendor","paymentMethod","filter","Boolean","join","groupsOf","steps","some","groups","Map","set","get","values","interpretV1","gen","options","dials","catalog","ordinalOf","indexOf","commitPoint","findIndex","ref","kind","outputs","done","record","name","patch","execute","flatMap","store","update","flowId","andThen","withAttributes","state","source","orDie","announce","ordinal","outbox","enqueue","at","Date","toISOString","audience","id","data","definition","recipe","slipVersion","code","category","guarded","attempt","participant","bounds","dialsFor","breaker","bulkhead","timedOut","fail","dependency","guard","withPermit","timeoutOrElse","duration","orElse","isFamily","retry","idempotent","call","wait","correlation","parameters","waitingFor","signalled","await","timeoutMs","raceAll","effects","sleep","run","mapError","push","stage","stages","exits","forEach","group","exit","discard","first","cause","reasons","reason","_tag","sort","a","b","undone","reverse","undoing","provideService","SuspendOnFailure","length","INTERPRETERS","interpretedSlipVersions","Object","keys","map","Number","interpretSlip","SlipWorkflowLayer","toLayer"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/interpreter/slip-workflow.ts"],"sourcesContent":["import {\n type FragmentCatalog,\n Slip,\n type SlipStep,\n slipSteps,\n} from '@entifix/business/flow';\nimport {\n decodeProblem,\n type EntifixFailure,\n Failure,\n isFailure,\n JsonBody,\n problemOf,\n Timeout,\n} from '@entifix/core';\nimport {\n BulkheadTag,\n CircuitBreakerTag,\n flowEvent,\n type FlowEventName,\n On,\n OutboxTag,\n ParticipantClientTag,\n} from '@entifix/transactions';\nimport {\n Context,\n Effect,\n Exit,\n Metric,\n Schedule,\n Schema,\n SchemaTransformation,\n} from 'effect';\nimport {\n Activity,\n DurableClock,\n DurableDeferred,\n Workflow,\n} from 'effect/workflow';\n\nimport {\n type FlowRecordPatch,\n flowStates,\n FlowStatusStoreTag,\n} from '../status/flow-status-store.js';\nimport { makeBindings } from './bindings.js';\n\n/**\n * A failure as an Activity journals it: the problem body on the way in, the\n * failure its code names on the way out, so a resumed flow sees the typed\n * refusal a participant sent rather than a cast.\n */\nexport const JournaledFailure: Schema.Codec<EntifixFailure, unknown> =\n Schema.Unknown.pipe(\n Schema.decodeTo(\n Schema.declare((value): value is EntifixFailure => isFailure(value)),\n SchemaTransformation.transform({\n decode: body => decodeProblem(body),\n encode: failure => problemOf(failure),\n }),\n ),\n );\n\n/**\n * How a flow ended, as the workflow's own result: every step ran, or a\n * refusal before the commit point was undone, or an undoing itself failed and\n * the flow stopped where it was — which a person has to look at.\n */\nexport const FlowOutcome = Schema.Literals([\n 'completed',\n 'compensated',\n 'failed',\n]);\n\n/** A durable wait that outlived its timeout before its signal came. */\nexport class FlowWaitTimedOut extends Failure.timeout<FlowWaitTimedOut>()(\n 'FlowWaitTimedOut',\n 'flowWaitTimedOut',\n { step: Schema.String },\n { message: ({ step }) => `the wait at '${step}' timed out` },\n) {}\n\n/** How long a flow gives each participant call, and each step as a whole. */\nexport interface FlowDials {\n /** One attempt at a call. */\n readonly attemptTimeoutMs: number;\n /** Every attempt at a step together, retries included. */\n readonly stepTimeoutMs: number;\n /** Segments of one stage run at once. */\n readonly concurrency: number;\n}\n\nexport const DEFAULT_FLOW_DIALS: FlowDials = {\n attemptTimeoutMs: 10_000,\n stepTimeoutMs: 60_000,\n concurrency: 4,\n};\n\n/** What the interpreter runs a slip with: the catalog, who announces, the dials. */\nexport interface InterpreterOptions {\n readonly catalog: FragmentCatalog;\n /** The slice the `flow.*` events are announced from. */\n readonly source: string;\n readonly dials?: Partial<FlowDials>;\n /**\n * One participant's own attempt and step bounds, over `dials` — the same\n * shape the breaker's `dialsFor` and the bulkhead's `permitsFor` take, so a\n * participant's dials are one row set however many guards read them.\n */\n readonly dialsFor?: (\n participant: string,\n ) => Partial<Omit<FlowDials, 'concurrency'>> | undefined;\n}\n\n/**\n * The interpreter's options, provided to the workflow it is registered with —\n * the payload is the slip; the catalog and dials are the deployment's.\n */\nexport class InterpreterOptionsTag extends Context.Service<\n InterpreterOptionsTag,\n InterpreterOptions\n>()('@entifix/workflow/InterpreterOptions') {}\n\n/**\n * The one workflow every flow runs as: its payload is the pinned slip and the\n * idempotency key that started it\n * ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)).\n * The execution id derives from the key, so the same key is the same flow.\n *\n * A flow suspended past its commit point is resumed on the retry schedule:\n * a participant that comes back gets the step again, idempotently.\n */\nexport const SlipWorkflow = Workflow.make('entifix/slip', {\n payload: { key: Schema.String, slip: Slip },\n idempotencyKey: payload => payload.key,\n success: FlowOutcome,\n // Its failure is what suspends it past the commit point; it is never the\n // flow's result.\n error: JournaledFailure,\n // Doubling from a second, never more than a minute apart.\n suspendedRetrySchedule: Schedule.min([\n Schedule.exponential('1 second'),\n Schedule.spaced('1 minute'),\n ]),\n});\n\n/** The durable wait a `wait` step parks on, addressed by the step's name. */\nexport const waitFor = (step: string) =>\n DurableDeferred.make(`wait:${step}`, { success: Schema.Unknown });\n\n/** A step's failure, with the step it happened at. */\ninterface StepFailed {\n readonly step: SlipStep;\n readonly failure: EntifixFailure;\n}\n\nconst segmentOf = (step: SlipStep) =>\n step.segment === undefined\n ? undefined\n : [step.segment.vendor, step.segment.paymentMethod]\n .filter(Boolean)\n .join('/');\n\n/**\n * A stage's steps as the groups that run at once: one group per segment when\n * every step names one — a basket's vendors, joined before the shared pivot —\n * and otherwise one group, in order.\n */\nconst groupsOf = (steps: readonly SlipStep[]): readonly SlipStep[][] => {\n if (steps.some(step => segmentOf(step) === undefined)) return [[...steps]];\n const groups = new Map<string, SlipStep[]>();\n for (const step of steps) {\n const key = segmentOf(step) as string;\n groups.set(key, [...(groups.get(key) ?? []), step]);\n }\n return [...groups.values()];\n};\n\n/**\n * Interprets a pinned slip of grammar version 1\n * ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)):\n * each step is an Activity named after it and keyed `<flowId>:<step>`, so a\n * resumed flow replays what already ran and calls a participant at most once\n * per step. Inside the Activity the call runs under the participant's\n * breaker and bulkhead and the retry budget, each attempt bounded and the\n * step as a whole bounded; nothing retries outside it.\n *\n * - Before and at the commit point, a failure — a breaker already open\n * included, which fails fast — compensates what succeeded, in reverse, and\n * the flow ends `compensated`.\n * - After it, a failure suspends the flow at that step: the money is taken,\n * so the flow rolls forward when the participant comes back, never back.\n * - A `wait` step parks the flow on a durable deferred its signal completes,\n * raced with a durable clock when it names `timeoutMs`; it may name a\n * `correlation`, so a sender that knows the order rather than the flow can\n * complete it.\n * - The segments of a stage run at once, bounded, and join before the next.\n *\n * Every transition is announced as a `flow.*` event through the outbox, by an\n * Activity, so it is written once whatever replays. Compensation is explicit\n * rather than a workflow finalizer, so the record says `compensated` only\n * after the last undoing has run — and an undoing that fails stops the flow\n * `failed` at that step instead of pretending.\n */\nconst interpretV1 = (slip: Slip) =>\n Effect.gen(function* () {\n const options = yield* InterpreterOptionsTag;\n const dials = { ...DEFAULT_FLOW_DIALS, ...options.dials };\n const { catalog } = options;\n const steps = slipSteps(slip);\n const ordinalOf = (step: SlipStep) => steps.indexOf(step) + 1;\n const commitPoint = steps.findIndex(\n step => catalog.get(step.ref)?.kind === 'pivot',\n );\n const bindings = makeBindings();\n const done: SlipStep[] = [];\n\n const record = (name: string, patch: FlowRecordPatch) =>\n Activity.make({\n name,\n execute: Effect.flatMap(FlowStatusStoreTag, store =>\n store.update(slip.flowId, patch),\n ).pipe(\n Effect.andThen(\n Metric.update(\n Metric.withAttributes(flowStates, {\n state: patch.state,\n source: options.source,\n }),\n 1,\n ),\n ),\n Effect.orDie,\n ),\n });\n\n const announce = (\n name: FlowEventName,\n step: string,\n ordinal: number,\n failure?: EntifixFailure,\n ) =>\n Activity.make({\n name: `announce:${name}:${step}`,\n execute: Effect.flatMap(OutboxTag, outbox =>\n outbox.enqueue(\n flowEvent({\n name,\n source: options.source,\n at: new Date().toISOString(),\n step: `${name}:${step}`,\n ordinal,\n audience: [\n { kind: 'flow', id: slip.flowId },\n ...(slip.audience ?? []),\n ],\n data: {\n flowId: slip.flowId,\n definition: slip.recipe,\n slipVersion: slip.slipVersion,\n step,\n ...(failure === undefined\n ? {}\n : {\n failure: {\n code: failure.code,\n category: failure.category,\n },\n }),\n },\n }),\n ),\n ).pipe(Effect.orDie),\n });\n\n /** One call, bounded, under the participant's breaker, bulkhead and budget. */\n const guarded = (\n step: SlipStep,\n attempt: Effect.Effect<unknown, EntifixFailure>,\n ) =>\n Effect.gen(function* () {\n const key = step.participant ?? 'participant';\n const bounds = { ...dials, ...options.dialsFor?.(key) };\n const breaker = yield* CircuitBreakerTag;\n const bulkhead = yield* BulkheadTag;\n const timedOut = () => Effect.fail(new Timeout({ dependency: key }));\n return yield* breaker\n .guard(key)(\n bulkhead.withPermit(key)(\n attempt.pipe(\n Effect.timeoutOrElse({\n duration: bounds.attemptTimeoutMs,\n orElse: timedOut,\n }),\n ),\n ),\n )\n .pipe(\n On(Failure.isFamily('technical')).retry({\n key: { dependency: key },\n idempotent: true,\n }),\n Effect.timeoutOrElse({\n duration: bounds.stepTimeoutMs,\n orElse: timedOut,\n }),\n );\n });\n\n const call = (step: SlipStep, kind: 'action' | 'compensation') =>\n Activity.make({\n name: `${step.step}:${kind}`,\n // Whatever the participant answered, as JSON — `undefined` included,\n // which a journal cannot otherwise hold.\n success: JsonBody,\n error: JournaledFailure,\n execute: Effect.flatMap(ParticipantClientTag, participant =>\n guarded(\n step,\n participant.call({\n step,\n kind,\n idempotencyKey:\n kind === 'action'\n ? `${slip.flowId}:${step.step}`\n : `${slip.flowId}:${step.step}:compensation`,\n inputs: bindings.inputsFor(step, catalog.get(step.ref), kind),\n }),\n ),\n ),\n });\n\n const wait = (step: SlipStep) =>\n Effect.gen(function* () {\n const correlation = step.parameters?.['correlation'];\n yield* record(`status:${step.step}:waiting`, {\n state: 'waiting',\n step: step.step,\n waitingFor: step.step,\n ...(typeof correlation === 'string' ? { correlation } : {}),\n });\n const signalled = DurableDeferred.await(waitFor(step.step));\n const timeoutMs = step.parameters?.['timeoutMs'];\n // A durable race, so a replay answers the branch that won rather than\n // racing again.\n const answer =\n typeof timeoutMs === 'number'\n ? yield* DurableDeferred.raceAll({\n name: `race:${step.step}`,\n success: Schema.Unknown,\n error: FlowWaitTimedOut,\n effects: [\n signalled,\n DurableClock.sleep({\n name: `timeout:${step.step}`,\n duration: timeoutMs,\n }).pipe(\n Effect.andThen(\n Effect.fail(new FlowWaitTimedOut({ step: step.step })),\n ),\n ),\n ],\n })\n : yield* signalled;\n bindings.record(step, catalog.get(step.ref), answer);\n yield* record(`status:${step.step}:resumed`, {\n state: 'running',\n step: step.step,\n });\n });\n\n /** One step, its failure tagged with where it happened. */\n const run = (step: SlipStep) =>\n Effect.gen(function* () {\n if (catalog.get(step.ref)?.kind === 'wait')\n return yield* wait(step).pipe(\n Effect.mapError((failure): StepFailed => ({ step, failure })),\n );\n yield* record(`status:${step.step}:running`, {\n state: 'running',\n step: step.step,\n });\n const answer = yield* call(step, 'action').pipe(\n Effect.mapError((failure): StepFailed => ({ step, failure })),\n );\n bindings.record(step, catalog.get(step.ref), answer);\n if (catalog.get(step.ref)?.kind === 'compensatable') done.push(step);\n });\n\n yield* announce('flow.started', 'started', 0);\n\n for (const stage of slip.stages) {\n const exits = yield* Effect.forEach(\n groupsOf(stage.steps),\n group => Effect.exit(Effect.forEach(group, run, { discard: true })),\n { concurrency: dials.concurrency },\n );\n // The earliest step that failed decides; a group's failure is its own.\n const [first] = exits\n .flatMap(exit =>\n Exit.isFailure(exit)\n ? exit.cause.reasons.flatMap(reason =>\n // A durable race fails with its losers' interruptions beside\n // the failure that won, so the failure is looked for.\n reason._tag === 'Fail' ? [reason.error] : [],\n )\n : [],\n )\n .sort((a, b) => ordinalOf(a.step) - ordinalOf(b.step));\n if (first === undefined) continue;\n\n const { step, failure } = first;\n if (commitPoint === -1 || steps.indexOf(step) <= commitPoint) {\n for (const undone of [...done].reverse()) {\n const undoing = yield* Effect.exit(call(undone, 'compensation'));\n if (Exit.isFailure(undoing)) {\n yield* record(`status:${undone.step}:failed`, {\n state: 'failed',\n step: undone.step,\n });\n yield* announce(\n 'flow.failed',\n undone.step,\n ordinalOf(undone),\n failure,\n );\n return 'failed' as const;\n }\n }\n yield* record(`status:${step.step}:compensated`, {\n state: 'compensated',\n step: step.step,\n });\n yield* announce('flow.failed', step.step, ordinalOf(step), failure);\n return 'compensated' as const;\n }\n\n yield* record(`status:${step.step}:suspended`, {\n state: 'suspended',\n step: step.step,\n });\n yield* announce('flow.suspended', step.step, ordinalOf(step), failure);\n return yield* Effect.fail(failure).pipe(\n Effect.provideService(Workflow.SuspendOnFailure, true),\n );\n }\n\n yield* record('status:completed', { state: 'completed' });\n yield* announce('flow.completed', 'completed', steps.length + 1);\n return 'completed' as const;\n });\n\n/**\n * One interpreter per grammar version a slip can be written in. A flow runs\n * to its end under the grammar it started with, so a change to how steps are\n * walked — their order, their Activity names — is a new entry here, never an\n * edit to an existing one; the journal replay holds every entry to its\n * recorded command sequence.\n */\nconst INTERPRETERS = { 1: interpretV1 } as const satisfies Record<\n Slip['slipVersion'],\n (slip: Slip) => unknown\n>;\n\n/** Every `slipVersion` the interpreter walks — each must have a journal. */\nexport const interpretedSlipVersions: readonly number[] =\n Object.keys(INTERPRETERS).map(Number);\n\nexport const interpretSlip = (slip: Slip) =>\n INTERPRETERS[slip.slipVersion](slip);\n\n/** The interpreter registered with the workflow engine, with its options. */\nexport const SlipWorkflowLayer = (options: InterpreterOptions) =>\n SlipWorkflow.toLayer(payload =>\n interpretSlip(payload.slip).pipe(\n Effect.provideService(InterpreterOptionsTag, options),\n ),\n );\n"],"names":["Slip","slipSteps","decodeProblem","Failure","isFailure","JsonBody","problemOf","Timeout","BulkheadTag","CircuitBreakerTag","flowEvent","On","OutboxTag","ParticipantClientTag","Context","Effect","Exit","Metric","Schedule","Schema","SchemaTransformation","Activity","DurableClock","DurableDeferred","Workflow","flowStates","FlowStatusStoreTag","makeBindings","JournaledFailure","Unknown","pipe","decodeTo","declare","value","transform","decode","body","encode","failure","FlowOutcome","Literals","FlowWaitTimedOut","timeout","step","String","message","DEFAULT_FLOW_DIALS","attemptTimeoutMs","stepTimeoutMs","concurrency","InterpreterOptionsTag","Service","SlipWorkflow","make","payload","key","slip","idempotencyKey","success","error","suspendedRetrySchedule","min","exponential","spaced","waitFor","segmentOf","segment","undefined","vendor","paymentMethod","filter","Boolean","join","groupsOf","steps","some","groups","Map","set","get","values","interpretV1","gen","options","dials","catalog","ordinalOf","indexOf","commitPoint","findIndex","ref","kind","bindings","done","record","name","patch","execute","flatMap","store","update","flowId","andThen","withAttributes","state","source","orDie","announce","ordinal","outbox","enqueue","at","Date","toISOString","audience","id","data","definition","recipe","slipVersion","code","category","guarded","attempt","participant","bounds","dialsFor","breaker","bulkhead","timedOut","fail","dependency","guard","withPermit","timeoutOrElse","duration","orElse","isFamily","retry","idempotent","call","inputs","inputsFor","wait","correlation","parameters","waitingFor","signalled","await","timeoutMs","answer","raceAll","effects","sleep","run","mapError","push","stage","stages","exits","forEach","group","exit","discard","first","cause","reasons","reason","_tag","sort","a","b","undone","reverse","undoing","provideService","SuspendOnFailure","length","INTERPRETERS","interpretedSlipVersions","Object","keys","map","Number","interpretSlip","SlipWorkflowLayer","toLayer"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entifix/workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Durable flows: the slip interpreter on Effect Workflow, behind the flow engine port, with Postgres storage and socket runners.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -89,20 +89,20 @@
|
|
|
89
89
|
},
|
|
90
90
|
"dependencies": {
|
|
91
91
|
"@swc/helpers": "0.5.23",
|
|
92
|
-
"@entifix/
|
|
93
|
-
"@entifix/
|
|
94
|
-
"@entifix/sql": "0.
|
|
95
|
-
"@entifix/
|
|
92
|
+
"@entifix/core": "0.15.0",
|
|
93
|
+
"@entifix/transactions": "0.15.0",
|
|
94
|
+
"@entifix/sql": "0.15.0",
|
|
95
|
+
"@entifix/business": "0.15.0"
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
98
|
-
"@effect/platform-node": "4.0.
|
|
99
|
-
"@effect/sql-pg": "4.0.
|
|
100
|
-
"effect": "4.0.
|
|
101
|
-
"@entifix/testing-unit": "0.
|
|
98
|
+
"@effect/platform-node": "4.0.7",
|
|
99
|
+
"@effect/sql-pg": "4.0.7",
|
|
100
|
+
"effect": "4.0.7",
|
|
101
|
+
"@entifix/testing-unit": "0.15.0"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
|
-
"@effect/platform-node": "^4.0.
|
|
105
|
-
"effect": "^4.0.
|
|
104
|
+
"@effect/platform-node": "^4.0.7",
|
|
105
|
+
"effect": "^4.0.7"
|
|
106
106
|
},
|
|
107
107
|
"peerDependenciesMeta": {
|
|
108
108
|
"@effect/platform-node": {
|