effect-machine 0.17.1 → 0.18.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/LICENSE +21 -0
- package/README.md +50 -54
- package/dist/actor.d.ts +8 -45
- package/dist/actor.js +157 -231
- package/dist/cluster/adapters/in-memory.d.ts +0 -1
- package/dist/cluster/adapters/in-memory.js +10 -5
- package/dist/cluster/entity-actor-ref.d.ts +2 -3
- package/dist/cluster/entity-actor-ref.js +14 -17
- package/dist/cluster/entity-machine.d.ts +2 -8
- package/dist/cluster/entity-machine.js +57 -34
- package/dist/cluster/index.js +1 -1
- package/dist/cluster/persistence.d.ts +0 -1
- package/dist/cluster/to-entity.d.ts +19 -21
- package/dist/cluster/to-entity.js +18 -19
- package/dist/errors.d.ts +11 -37
- package/dist/errors.js +12 -30
- package/dist/index.d.ts +4 -5
- package/dist/index.js +4 -5
- package/dist/inspection.d.ts +0 -1
- package/dist/inspection.js +24 -13
- package/dist/internal/brands.d.ts +0 -1
- package/dist/internal/event-advancement.d.ts +50 -0
- package/dist/internal/event-advancement.js +79 -0
- package/dist/internal/inspection.d.ts +5 -9
- package/dist/internal/inspection.js +31 -10
- package/dist/internal/machine-definition.d.ts +16 -0
- package/dist/internal/runtime.d.ts +1 -161
- package/dist/internal/runtime.js +191 -150
- package/dist/internal/transition.d.ts +4 -135
- package/dist/internal/transition.js +82 -157
- package/dist/internal/utils.d.ts +3 -40
- package/dist/internal/utils.js +2 -2
- package/dist/machine.d.ts +47 -137
- package/dist/machine.js +147 -215
- package/dist/schema.d.ts +42 -21
- package/dist/schema.js +28 -18
- package/dist/supervision.d.ts +1 -24
- package/dist/supervision.js +2 -3
- package/dist/testing.d.ts +15 -29
- package/dist/testing.js +76 -95
- package/package.json +19 -38
- package/dist/slot.d.ts +0 -159
- package/dist/slot.js +0 -165
- package/v3/dist/_virtual/_rolldown/runtime.js +0 -13
- package/v3/dist/actor.d.ts +0 -250
- package/v3/dist/actor.js +0 -577
- package/v3/dist/cluster/adapters/in-memory.d.ts +0 -15
- package/v3/dist/cluster/adapters/in-memory.js +0 -62
- package/v3/dist/cluster/entity-actor-ref.d.ts +0 -49
- package/v3/dist/cluster/entity-actor-ref.js +0 -19
- package/v3/dist/cluster/entity-machine.d.ts +0 -74
- package/v3/dist/cluster/entity-machine.js +0 -166
- package/v3/dist/cluster/index.d.ts +0 -6
- package/v3/dist/cluster/index.js +0 -6
- package/v3/dist/cluster/persistence.d.ts +0 -48
- package/v3/dist/cluster/persistence.js +0 -14
- package/v3/dist/cluster/to-entity.d.ts +0 -69
- package/v3/dist/cluster/to-entity.js +0 -59
- package/v3/dist/errors.d.ts +0 -95
- package/v3/dist/errors.js +0 -54
- package/v3/dist/index.d.ts +0 -11
- package/v3/dist/index.js +0 -9
- package/v3/dist/inspection.d.ts +0 -151
- package/v3/dist/inspection.js +0 -128
- package/v3/dist/internal/brands.d.ts +0 -50
- package/v3/dist/internal/inspection.d.ts +0 -11
- package/v3/dist/internal/inspection.js +0 -20
- package/v3/dist/internal/runtime.d.ts +0 -161
- package/v3/dist/internal/runtime.js +0 -360
- package/v3/dist/internal/transition.d.ts +0 -190
- package/v3/dist/internal/transition.js +0 -278
- package/v3/dist/internal/utils.d.ts +0 -101
- package/v3/dist/internal/utils.js +0 -75
- package/v3/dist/machine.d.ts +0 -398
- package/v3/dist/machine.js +0 -487
- package/v3/dist/schema.d.ts +0 -174
- package/v3/dist/schema.js +0 -206
- package/v3/dist/slot.d.ts +0 -158
- package/v3/dist/slot.js +0 -165
- package/v3/dist/supervision.d.ts +0 -97
- package/v3/dist/supervision.js +0 -42
- package/v3/dist/testing.d.ts +0 -151
- package/v3/dist/testing.js +0 -189
- /package/{v3/dist/internal/brands.js → dist/internal/machine-definition.js} +0 -0
package/v3/dist/schema.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import { InvalidSchemaError, MissingMatchHandlerError } from "./errors.js";
|
|
2
|
-
import { Schema } from "effect";
|
|
3
|
-
//#region src/schema.ts
|
|
4
|
-
/**
|
|
5
|
-
* Schema-first State/Event definitions for effect-machine.
|
|
6
|
-
*
|
|
7
|
-
* MachineSchema provides a single source of truth that combines:
|
|
8
|
-
* - Schema for validation/serialization
|
|
9
|
-
* - Variant constructors (like Data.taggedEnum)
|
|
10
|
-
* - $is and $match helpers for pattern matching
|
|
11
|
-
* - Brand integration for compile-time safety
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```ts
|
|
15
|
-
* import { State, Event, Machine } from "effect-machine"
|
|
16
|
-
*
|
|
17
|
-
* // Define schema-first state
|
|
18
|
-
* const OrderState = State({
|
|
19
|
-
* Pending: { orderId: Schema.String },
|
|
20
|
-
* Shipped: { trackingId: Schema.String },
|
|
21
|
-
* })
|
|
22
|
-
*
|
|
23
|
-
* // Infer type from schema
|
|
24
|
-
* type OrderState = typeof OrderState.Type
|
|
25
|
-
*
|
|
26
|
-
* // Use constructors
|
|
27
|
-
* const pending = OrderState.Pending({ orderId: "123" })
|
|
28
|
-
*
|
|
29
|
-
* // Pattern match
|
|
30
|
-
* OrderState.$match(state, {
|
|
31
|
-
* Pending: (s) => `Order ${s.orderId} pending`,
|
|
32
|
-
* Shipped: (s) => `Shipped: ${s.trackingId}`,
|
|
33
|
-
* })
|
|
34
|
-
*
|
|
35
|
-
* // Use as Schema for persistence/cluster
|
|
36
|
-
* machine.pipe(Machine.persist({ stateSchema: OrderState, ... }))
|
|
37
|
-
* ```
|
|
38
|
-
*
|
|
39
|
-
* @module
|
|
40
|
-
*/
|
|
41
|
-
const ReplySchemaSymbol = Symbol.for("effect-machine/ReplySchema");
|
|
42
|
-
/**
|
|
43
|
-
* Build a schema-first definition from a record of tag -> fields
|
|
44
|
-
*/
|
|
45
|
-
const RESERVED_DERIVE_KEYS = new Set(["_tag"]);
|
|
46
|
-
const buildMachineSchema = (definition) => {
|
|
47
|
-
const variants = {};
|
|
48
|
-
const constructors = {};
|
|
49
|
-
const replySchemas = /* @__PURE__ */ new Map();
|
|
50
|
-
for (const tag of Object.keys(definition)) {
|
|
51
|
-
const fields = definition[tag];
|
|
52
|
-
if (fields === void 0) continue;
|
|
53
|
-
if (ReplySchemaSymbol in fields) {
|
|
54
|
-
const rs = fields[ReplySchemaSymbol];
|
|
55
|
-
if (rs !== void 0) replySchemas.set(tag, rs);
|
|
56
|
-
}
|
|
57
|
-
variants[tag] = Schema.TaggedStruct(tag, fields);
|
|
58
|
-
const fieldNames = new Set(Object.keys(fields));
|
|
59
|
-
if (fieldNames.size > 0) {
|
|
60
|
-
const constructor = (args) => ({
|
|
61
|
-
...args,
|
|
62
|
-
_tag: tag
|
|
63
|
-
});
|
|
64
|
-
constructor._tag = tag;
|
|
65
|
-
constructor.with = (source, partial) => {
|
|
66
|
-
const result = { _tag: tag };
|
|
67
|
-
for (const key of fieldNames) if (key in source) result[key] = source[key];
|
|
68
|
-
if (partial !== void 0) for (const [key, value] of Object.entries(partial)) {
|
|
69
|
-
if (RESERVED_DERIVE_KEYS.has(key)) continue;
|
|
70
|
-
if (!fieldNames.has(key)) continue;
|
|
71
|
-
result[key] = value;
|
|
72
|
-
}
|
|
73
|
-
return result;
|
|
74
|
-
};
|
|
75
|
-
constructors[tag] = constructor;
|
|
76
|
-
} else constructors[tag] = {
|
|
77
|
-
_tag: tag,
|
|
78
|
-
with: () => ({ _tag: tag })
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
const variantArray = Object.values(variants);
|
|
82
|
-
if (variantArray.length === 0) throw new InvalidSchemaError({ message: "Schema must have at least one variant" });
|
|
83
|
-
const unionSchema = variantArray.length === 1 ? variantArray[0] : Schema.Union(...variantArray);
|
|
84
|
-
const $is = (tag) => (u) => typeof u === "object" && u !== null && "_tag" in u && u._tag === tag;
|
|
85
|
-
const $match = (valueOrCases, maybeCases) => {
|
|
86
|
-
if (maybeCases !== void 0) {
|
|
87
|
-
const value = valueOrCases;
|
|
88
|
-
const handler = maybeCases[value._tag];
|
|
89
|
-
if (handler === void 0) throw new MissingMatchHandlerError({ tag: value._tag });
|
|
90
|
-
return handler(value);
|
|
91
|
-
}
|
|
92
|
-
const cases = valueOrCases;
|
|
93
|
-
return (value) => {
|
|
94
|
-
const handler = cases[value._tag];
|
|
95
|
-
if (handler === void 0) throw new MissingMatchHandlerError({ tag: value._tag });
|
|
96
|
-
return handler(value);
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
return {
|
|
100
|
-
schema: unionSchema,
|
|
101
|
-
variants,
|
|
102
|
-
constructors,
|
|
103
|
-
_definition: definition,
|
|
104
|
-
replySchemas,
|
|
105
|
-
$is,
|
|
106
|
-
$match
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
/**
|
|
110
|
-
* Internal helper to create a machine schema (shared by State and Event).
|
|
111
|
-
* Builds the schema object with variants, constructors, $is, and $match.
|
|
112
|
-
*/
|
|
113
|
-
const createMachineSchema = (definition) => {
|
|
114
|
-
const { schema, variants, constructors, _definition, replySchemas, $is, $match } = buildMachineSchema(definition);
|
|
115
|
-
const withFn = (source, partial) => {
|
|
116
|
-
const ctor = constructors[source._tag];
|
|
117
|
-
if (ctor === void 0) throw new MissingMatchHandlerError({ tag: source._tag });
|
|
118
|
-
const fn = ctor.with;
|
|
119
|
-
if (fn === void 0) throw new MissingMatchHandlerError({ tag: source._tag });
|
|
120
|
-
return fn(source, partial);
|
|
121
|
-
};
|
|
122
|
-
return Object.assign(Object.create(schema), {
|
|
123
|
-
variants,
|
|
124
|
-
_definition,
|
|
125
|
-
_replySchemas: replySchemas,
|
|
126
|
-
schema,
|
|
127
|
-
$is,
|
|
128
|
-
$match,
|
|
129
|
-
with: withFn,
|
|
130
|
-
...constructors
|
|
131
|
-
});
|
|
132
|
-
};
|
|
133
|
-
/**
|
|
134
|
-
* Create a schema-first State definition.
|
|
135
|
-
*
|
|
136
|
-
* The schema's definition type D creates a unique brand, preventing
|
|
137
|
-
* accidental use of constructors from different state schemas
|
|
138
|
-
* (unless they have identical definitions).
|
|
139
|
-
*
|
|
140
|
-
* @example
|
|
141
|
-
* ```ts
|
|
142
|
-
* const OrderState = MachineSchema.State({
|
|
143
|
-
* Pending: { orderId: Schema.String },
|
|
144
|
-
* Shipped: { trackingId: Schema.String },
|
|
145
|
-
* })
|
|
146
|
-
*
|
|
147
|
-
* type OrderState = typeof OrderState.Type
|
|
148
|
-
*
|
|
149
|
-
* // Construct
|
|
150
|
-
* const s = OrderState.Pending({ orderId: "123" })
|
|
151
|
-
*
|
|
152
|
-
* // Pattern match
|
|
153
|
-
* OrderState.$match(s, {
|
|
154
|
-
* Pending: (v) => v.orderId,
|
|
155
|
-
* Shipped: (v) => v.trackingId,
|
|
156
|
-
* })
|
|
157
|
-
*
|
|
158
|
-
* // Validate
|
|
159
|
-
* Schema.decodeUnknownSync(OrderState)(rawJson)
|
|
160
|
-
* ```
|
|
161
|
-
*/
|
|
162
|
-
const State = (definition) => createMachineSchema(definition);
|
|
163
|
-
/**
|
|
164
|
-
* Create a schema-first Event definition.
|
|
165
|
-
*
|
|
166
|
-
* The schema's definition type D creates a unique brand, preventing
|
|
167
|
-
* accidental use of constructors from different event schemas
|
|
168
|
-
* (unless they have identical definitions).
|
|
169
|
-
*
|
|
170
|
-
* Use `Event.reply(fields, replySchema)` to define events that support
|
|
171
|
-
* typed `ask()` replies.
|
|
172
|
-
*
|
|
173
|
-
* @example
|
|
174
|
-
* ```ts
|
|
175
|
-
* const OrderEvent = Event({
|
|
176
|
-
* Ship: { trackingId: Schema.String },
|
|
177
|
-
* Cancel: {},
|
|
178
|
-
* GetTotal: Event.reply({}, Schema.Number),
|
|
179
|
-
* })
|
|
180
|
-
*
|
|
181
|
-
* type OrderEvent = typeof OrderEvent.Type
|
|
182
|
-
*
|
|
183
|
-
* // Construct
|
|
184
|
-
* const e = OrderEvent.Ship({ trackingId: "abc" })
|
|
185
|
-
*
|
|
186
|
-
* // Typed ask
|
|
187
|
-
* const total = yield* actor.ask(OrderEvent.GetTotal) // number
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
190
|
-
const EventImpl = (definition) => createMachineSchema(definition);
|
|
191
|
-
/**
|
|
192
|
-
* Annotate event fields with a reply schema.
|
|
193
|
-
* Events defined with `Event.reply(fields, replySchema)` enable typed `ask()`.
|
|
194
|
-
*/
|
|
195
|
-
const replyFieldsFn = (fields, replySchema) => {
|
|
196
|
-
const annotated = { ...fields };
|
|
197
|
-
Object.defineProperty(annotated, ReplySchemaSymbol, {
|
|
198
|
-
value: replySchema,
|
|
199
|
-
enumerable: false,
|
|
200
|
-
writable: false
|
|
201
|
-
});
|
|
202
|
-
return annotated;
|
|
203
|
-
};
|
|
204
|
-
const Event = Object.assign(EventImpl, { reply: replyFieldsFn });
|
|
205
|
-
//#endregion
|
|
206
|
-
export { Event, State };
|
package/v3/dist/slot.d.ts
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { ActorSystem } from "./actor.js";
|
|
2
|
-
import { Context, Effect, Schema } from "effect";
|
|
3
|
-
|
|
4
|
-
//#region src/slot.d.ts
|
|
5
|
-
/** Schema fields definition (like Schema.Struct.Fields) */
|
|
6
|
-
type Fields = Record<string, Schema.Schema.All>;
|
|
7
|
-
/** Extract the type from schema fields (used for parameters) */
|
|
8
|
-
type FieldsToParams<F extends Fields> = keyof F extends never ? void : Schema.Schema.Type<Schema.Struct<F>>;
|
|
9
|
-
/**
|
|
10
|
-
* Definition of a single slot function.
|
|
11
|
-
* Created via `Slot.fn(params, returnSchema?)`.
|
|
12
|
-
*
|
|
13
|
-
* Carries both type-level information and materialized schemas
|
|
14
|
-
* for runtime validation and serialization.
|
|
15
|
-
*/
|
|
16
|
-
interface SlotFnDef<F extends Fields = Fields, _Return = void> {
|
|
17
|
-
readonly _tag: "SlotFnDef";
|
|
18
|
-
readonly fields: F;
|
|
19
|
-
/** Return schema — undefined means void */
|
|
20
|
-
readonly returnSchema: Schema.Schema.Any | undefined;
|
|
21
|
-
/** Materialized input schema (Schema.Struct of fields, or Schema.Void for empty) */
|
|
22
|
-
readonly inputSchema: Schema.Schema.Any;
|
|
23
|
-
/** Materialized output schema (returnSchema or Schema.Void) */
|
|
24
|
-
readonly outputSchema: Schema.Schema.Any;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Define a single slot function with parameter schema and optional return schema.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```ts
|
|
31
|
-
* // Guard-like: returns boolean
|
|
32
|
-
* Slot.fn({ max: Schema.Number }, Schema.Boolean)
|
|
33
|
-
*
|
|
34
|
-
* // Effect-like: returns void (default)
|
|
35
|
-
* Slot.fn({ url: Schema.String })
|
|
36
|
-
*
|
|
37
|
-
* // No params, returns boolean
|
|
38
|
-
* Slot.fn({}, Schema.Boolean)
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
declare const fn: {
|
|
42
|
-
<F extends Fields, S extends Schema.Schema.Any>(fields: F, returnSchema: S): SlotFnDef<F, Schema.Schema.Type<S>>;
|
|
43
|
-
<F extends Fields>(fields: F): SlotFnDef<F>;
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Record of slot definitions. Keys are slot names, values are SlotFnDef.
|
|
47
|
-
*/
|
|
48
|
-
type SlotsDef = Record<string, SlotFnDef<Fields, unknown>>;
|
|
49
|
-
/**
|
|
50
|
-
* Slots schema — returned by `Slot.define()`. Passed to `Machine.make({ slots })`.
|
|
51
|
-
*/
|
|
52
|
-
interface SlotsSchema<D extends SlotsDef> {
|
|
53
|
-
readonly _tag: "SlotsSchema";
|
|
54
|
-
readonly definitions: D;
|
|
55
|
-
/** Schema for slot requests `{ _tag: "SlotRequest", name, params }`. For RPC request payloads. */
|
|
56
|
-
readonly requestSchema: Schema.Schema<SlotRequest<D>>;
|
|
57
|
-
/** Schema for slot results `{ _tag: "SlotResult", name, result }`. For RPC response payloads. */
|
|
58
|
-
readonly resultSchema: Schema.Schema<SlotResult<D>>;
|
|
59
|
-
/** Schema for slot invocations `{ _tag: "SlotInvocation", name, params, result }`. For persistence/logging. */
|
|
60
|
-
readonly invocationSchema: Schema.Schema<SlotInvocation<D>>;
|
|
61
|
-
/** Create callable slot proxies (used by Machine internally) */
|
|
62
|
-
readonly _createSlots: (resolve: <N extends keyof D & string>(name: N, params: SlotParams<D[N]>) => Effect.Effect<SlotReturn<D[N]>>) => SlotCalls<D>;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* A serialized slot request — captures name and params (no result).
|
|
66
|
-
* Used for RPC request payloads.
|
|
67
|
-
*/
|
|
68
|
-
type SlotRequest<D extends SlotsDef> = { readonly [K in keyof D & string]: {
|
|
69
|
-
readonly _tag: "SlotRequest";
|
|
70
|
-
readonly name: K;
|
|
71
|
-
readonly params: SlotParams<D[K]>;
|
|
72
|
-
} }[keyof D & string];
|
|
73
|
-
/**
|
|
74
|
-
* A serialized slot result — captures name and result (no params).
|
|
75
|
-
* Used for RPC response payloads.
|
|
76
|
-
*/
|
|
77
|
-
type SlotResult<D extends SlotsDef> = { readonly [K in keyof D & string]: {
|
|
78
|
-
readonly _tag: "SlotResult";
|
|
79
|
-
readonly name: K;
|
|
80
|
-
readonly result: SlotReturn<D[K]>;
|
|
81
|
-
} }[keyof D & string];
|
|
82
|
-
/**
|
|
83
|
-
* A serialized slot invocation — captures name, params, and result.
|
|
84
|
-
* Used for persistence, logging, and audit trails.
|
|
85
|
-
*/
|
|
86
|
-
type SlotInvocation<D extends SlotsDef> = { readonly [K in keyof D & string]: {
|
|
87
|
-
readonly _tag: "SlotInvocation";
|
|
88
|
-
readonly name: K;
|
|
89
|
-
readonly params: SlotParams<D[K]>;
|
|
90
|
-
readonly result: SlotReturn<D[K]>;
|
|
91
|
-
} }[keyof D & string];
|
|
92
|
-
/** Extract params type from a SlotFnDef */
|
|
93
|
-
type SlotParams<D extends SlotFnDef<Fields, unknown>> = D extends SlotFnDef<infer F, unknown> ? FieldsToParams<F> : never;
|
|
94
|
-
/** Extract return type from a SlotFnDef */
|
|
95
|
-
type SlotReturn<D extends SlotFnDef<Fields, unknown>> = D extends SlotFnDef<Fields, infer R> ? R : never;
|
|
96
|
-
/**
|
|
97
|
-
* A callable slot — function that takes params and returns Effect<Return>.
|
|
98
|
-
*/
|
|
99
|
-
interface SlotCall<Name extends string, Params, Return> {
|
|
100
|
-
readonly _tag: "Slot";
|
|
101
|
-
readonly name: Name;
|
|
102
|
-
(params: Params): Effect.Effect<Return>;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Convert slot definitions to callable slot proxies.
|
|
106
|
-
*/
|
|
107
|
-
type SlotCalls<D extends SlotsDef> = { readonly [K in keyof D & string]: SlotCall<K, SlotParams<D[K]>, SlotReturn<D[K]>> };
|
|
108
|
-
/**
|
|
109
|
-
* Slot handler implementation.
|
|
110
|
-
* Receives only params — use `yield* machine.Context` for machine context.
|
|
111
|
-
*/
|
|
112
|
-
type SlotHandler<Params, Return, R = never> = (params: Params) => Return | Effect.Effect<Return, never, R>;
|
|
113
|
-
/**
|
|
114
|
-
* Handler implementations for all slots in a definition.
|
|
115
|
-
*/
|
|
116
|
-
type ProvideSlots<D extends SlotsDef, R = never> = { readonly [K in keyof D & string]: SlotHandler<SlotParams<D[K]>, SlotReturn<D[K]>, R> };
|
|
117
|
-
/** Check if a SlotsDef has any actual keys */
|
|
118
|
-
type HasSlotKeys<SD extends SlotsDef> = [keyof SD] extends [never] ? false : SD extends Record<string, never> ? false : true;
|
|
119
|
-
/**
|
|
120
|
-
* Type for machine context — state, event, and self reference.
|
|
121
|
-
* Shared across all machines via MachineContextTag.
|
|
122
|
-
*/
|
|
123
|
-
interface MachineContext<State, Event, Self> {
|
|
124
|
-
readonly actorId: string;
|
|
125
|
-
readonly state: State;
|
|
126
|
-
readonly event: Event;
|
|
127
|
-
readonly self: Self;
|
|
128
|
-
readonly system: ActorSystem;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Shared Context tag for all machines.
|
|
132
|
-
* Single module-level tag instead of per-machine allocation.
|
|
133
|
-
* @internal
|
|
134
|
-
*/
|
|
135
|
-
declare const MachineContextTag: Context.Tag<MachineContext<any, any, any>, MachineContext<any, any, any>>;
|
|
136
|
-
/**
|
|
137
|
-
* Define a set of slots with parameter and return schemas.
|
|
138
|
-
*
|
|
139
|
-
* @example
|
|
140
|
-
* ```ts
|
|
141
|
-
* const MySlots = Slot.define({
|
|
142
|
-
* canRetry: Slot.fn({ max: Schema.Number }, Schema.Boolean),
|
|
143
|
-
* fetchData: Slot.fn({ url: Schema.String }),
|
|
144
|
-
* notify: Slot.fn({ message: Schema.String }),
|
|
145
|
-
* })
|
|
146
|
-
* ```
|
|
147
|
-
*/
|
|
148
|
-
declare const define: <D extends SlotsDef>(definitions: D) => SlotsSchema<D>;
|
|
149
|
-
declare const Slot: {
|
|
150
|
-
readonly fn: {
|
|
151
|
-
<F extends Fields, S extends Schema.Schema.Any>(fields: F, returnSchema: S): SlotFnDef<F, Schema.Schema.Type<S>>;
|
|
152
|
-
<F extends Fields>(fields: F): SlotFnDef<F>;
|
|
153
|
-
};
|
|
154
|
-
readonly define: <D extends SlotsDef>(definitions: D) => SlotsSchema<D>;
|
|
155
|
-
readonly of: <D extends SlotsDef>(slotsSchema: SlotsSchema<D>, provided: ProvideSlots<D>) => SlotCalls<D>;
|
|
156
|
-
};
|
|
157
|
-
//#endregion
|
|
158
|
-
export { HasSlotKeys, MachineContext, MachineContextTag, ProvideSlots, Slot, SlotCall, SlotCalls, SlotFnDef, SlotHandler, SlotInvocation, SlotRequest, SlotResult, SlotsDef, SlotsSchema, define, fn };
|
package/v3/dist/slot.js
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { Context, Effect, Schema } from "effect";
|
|
2
|
-
//#region src/slot.ts
|
|
3
|
-
/**
|
|
4
|
-
* Slot module — unified, schema-based parameterized slots.
|
|
5
|
-
*
|
|
6
|
-
* Replaces the split Guards/Effects API with a single `Slot.define` + `Slot.fn`.
|
|
7
|
-
* Each slot declares its parameter schema and (optional) return schema.
|
|
8
|
-
* Handlers receive only params — machine context is accessed via `yield* machine.Context`.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* import { Slot } from "effect-machine"
|
|
13
|
-
* import { Schema } from "effect"
|
|
14
|
-
*
|
|
15
|
-
* const MySlots = Slot.define({
|
|
16
|
-
* canRetry: Slot.fn({ max: Schema.Number }, Schema.Boolean),
|
|
17
|
-
* isValid: Slot.fn({}, Schema.Boolean),
|
|
18
|
-
* fetchData: Slot.fn({ url: Schema.String }),
|
|
19
|
-
* notify: Slot.fn({ message: Schema.String }),
|
|
20
|
-
* })
|
|
21
|
-
*
|
|
22
|
-
* // Used in handlers:
|
|
23
|
-
* .on(State.X, Event.Y, ({ slots }) =>
|
|
24
|
-
* Effect.gen(function* () {
|
|
25
|
-
* if (yield* slots.canRetry({ max: 3 })) {
|
|
26
|
-
* yield* slots.fetchData({ url: "/api" })
|
|
27
|
-
* return State.Next
|
|
28
|
-
* }
|
|
29
|
-
* return state
|
|
30
|
-
* })
|
|
31
|
-
* )
|
|
32
|
-
* ```
|
|
33
|
-
*
|
|
34
|
-
* @module
|
|
35
|
-
*/
|
|
36
|
-
/**
|
|
37
|
-
* Define a single slot function with parameter schema and optional return schema.
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* ```ts
|
|
41
|
-
* // Guard-like: returns boolean
|
|
42
|
-
* Slot.fn({ max: Schema.Number }, Schema.Boolean)
|
|
43
|
-
*
|
|
44
|
-
* // Effect-like: returns void (default)
|
|
45
|
-
* Slot.fn({ url: Schema.String })
|
|
46
|
-
*
|
|
47
|
-
* // No params, returns boolean
|
|
48
|
-
* Slot.fn({}, Schema.Boolean)
|
|
49
|
-
* ```
|
|
50
|
-
*/
|
|
51
|
-
const fn = (fields, returnSchema) => {
|
|
52
|
-
return {
|
|
53
|
-
_tag: "SlotFnDef",
|
|
54
|
-
fields,
|
|
55
|
-
returnSchema,
|
|
56
|
-
inputSchema: Object.keys(fields).length > 0 ? Schema.Struct(fields) : Schema.Void,
|
|
57
|
-
outputSchema: returnSchema ?? Schema.Void
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
/**
|
|
61
|
-
* Shared Context tag for all machines.
|
|
62
|
-
* Single module-level tag instead of per-machine allocation.
|
|
63
|
-
* @internal
|
|
64
|
-
*/
|
|
65
|
-
const MachineContextTag = Context.GenericTag("@effect-machine/Context");
|
|
66
|
-
/**
|
|
67
|
-
* Define a set of slots with parameter and return schemas.
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* ```ts
|
|
71
|
-
* const MySlots = Slot.define({
|
|
72
|
-
* canRetry: Slot.fn({ max: Schema.Number }, Schema.Boolean),
|
|
73
|
-
* fetchData: Slot.fn({ url: Schema.String }),
|
|
74
|
-
* notify: Slot.fn({ message: Schema.String }),
|
|
75
|
-
* })
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
const define = (definitions) => {
|
|
79
|
-
const names = Object.keys(definitions);
|
|
80
|
-
const requestSchemas = [];
|
|
81
|
-
const resultSchemas = [];
|
|
82
|
-
const invocationSchemas = [];
|
|
83
|
-
for (const name of names) {
|
|
84
|
-
const def = definitions[name];
|
|
85
|
-
if (def === void 0) continue;
|
|
86
|
-
requestSchemas.push(Schema.TaggedStruct("SlotRequest", {
|
|
87
|
-
name: Schema.Literal(name),
|
|
88
|
-
params: def.inputSchema
|
|
89
|
-
}));
|
|
90
|
-
resultSchemas.push(Schema.TaggedStruct("SlotResult", {
|
|
91
|
-
name: Schema.Literal(name),
|
|
92
|
-
result: def.outputSchema
|
|
93
|
-
}));
|
|
94
|
-
invocationSchemas.push(Schema.TaggedStruct("SlotInvocation", {
|
|
95
|
-
name: Schema.Literal(name),
|
|
96
|
-
params: def.inputSchema,
|
|
97
|
-
result: def.outputSchema
|
|
98
|
-
}));
|
|
99
|
-
}
|
|
100
|
-
const buildUnion = (schemas) => schemas.length === 0 ? Schema.Never : Schema.Union(...schemas);
|
|
101
|
-
return {
|
|
102
|
-
_tag: "SlotsSchema",
|
|
103
|
-
definitions,
|
|
104
|
-
requestSchema: buildUnion(requestSchemas),
|
|
105
|
-
resultSchema: buildUnion(resultSchemas),
|
|
106
|
-
invocationSchema: buildUnion(invocationSchemas),
|
|
107
|
-
_createSlots: (resolve) => {
|
|
108
|
-
const slots = {};
|
|
109
|
-
for (const name of names) {
|
|
110
|
-
const slot = (params) => resolve(name, params);
|
|
111
|
-
Object.defineProperty(slot, "_tag", {
|
|
112
|
-
value: "Slot",
|
|
113
|
-
enumerable: true
|
|
114
|
-
});
|
|
115
|
-
Object.defineProperty(slot, "name", {
|
|
116
|
-
value: name,
|
|
117
|
-
enumerable: true
|
|
118
|
-
});
|
|
119
|
-
slots[name] = slot;
|
|
120
|
-
}
|
|
121
|
-
return slots;
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
};
|
|
125
|
-
/**
|
|
126
|
-
* Convert raw slot handler implementations into the callable `SlotCalls` form.
|
|
127
|
-
*
|
|
128
|
-
* Handlers that return plain values are wrapped in `Effect.succeed`.
|
|
129
|
-
* Handlers that return Effects are called directly inside `Effect.suspend`.
|
|
130
|
-
*
|
|
131
|
-
* @example
|
|
132
|
-
* ```ts
|
|
133
|
-
* const provided = yield* myExtension.slots(ctx)
|
|
134
|
-
* const slots = Slot.of(slotsSchema, provided)
|
|
135
|
-
* // slots.mySlot({ param: 1 }) returns Effect<ReturnType>
|
|
136
|
-
* ```
|
|
137
|
-
*/
|
|
138
|
-
const of = (slotsSchema, provided) => {
|
|
139
|
-
const slots = {};
|
|
140
|
-
for (const name of Object.keys(slotsSchema.definitions)) {
|
|
141
|
-
const handler = provided[name];
|
|
142
|
-
if (handler === void 0) continue;
|
|
143
|
-
const call = (params) => Effect.suspend(() => {
|
|
144
|
-
const result = handler(params);
|
|
145
|
-
return Effect.isEffect(result) ? result : Effect.succeed(result);
|
|
146
|
-
});
|
|
147
|
-
Object.defineProperty(call, "_tag", {
|
|
148
|
-
value: "Slot",
|
|
149
|
-
enumerable: true
|
|
150
|
-
});
|
|
151
|
-
Object.defineProperty(call, "name", {
|
|
152
|
-
value: name,
|
|
153
|
-
enumerable: true
|
|
154
|
-
});
|
|
155
|
-
slots[name] = call;
|
|
156
|
-
}
|
|
157
|
-
return slots;
|
|
158
|
-
};
|
|
159
|
-
const Slot = {
|
|
160
|
-
fn,
|
|
161
|
-
define,
|
|
162
|
-
of
|
|
163
|
-
};
|
|
164
|
-
//#endregion
|
|
165
|
-
export { MachineContextTag, Slot, define, fn };
|
package/v3/dist/supervision.d.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { Cause, Duration, Schedule } from "effect";
|
|
2
|
-
|
|
3
|
-
//#region src/supervision.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Where in the actor lifecycle a defect occurred.
|
|
6
|
-
*
|
|
7
|
-
* - `transition` — during event handler execution
|
|
8
|
-
* - `spawn` — during state spawn effect execution
|
|
9
|
-
* - `background` — in a background effect fiber
|
|
10
|
-
* - `initial-spawn` — during initial state spawn effects (before event loop)
|
|
11
|
-
*/
|
|
12
|
-
type DefectPhase = "transition" | "spawn" | "background" | "initial-spawn";
|
|
13
|
-
/**
|
|
14
|
-
* Terminal exit reason for an actor generation.
|
|
15
|
-
*
|
|
16
|
-
* - `Final` — machine reached a final state normally
|
|
17
|
-
* - `Stopped` — explicit `actor.stop` or `actor.drain`
|
|
18
|
-
* - `Defect` — unhandled error in the runtime
|
|
19
|
-
*/
|
|
20
|
-
type ActorExit<S> = {
|
|
21
|
-
readonly _tag: "Final";
|
|
22
|
-
readonly state: S;
|
|
23
|
-
} | {
|
|
24
|
-
readonly _tag: "Stopped";
|
|
25
|
-
} | {
|
|
26
|
-
readonly _tag: "Defect";
|
|
27
|
-
readonly cause: Cause.Cause<unknown>;
|
|
28
|
-
readonly phase: DefectPhase;
|
|
29
|
-
};
|
|
30
|
-
/** Constructors for ActorExit */
|
|
31
|
-
declare const ActorExit: {
|
|
32
|
-
readonly Final: <S>(state: S) => ActorExit<S>;
|
|
33
|
-
readonly Stopped: ActorExit<never>;
|
|
34
|
-
readonly Defect: <S = never>(cause: Cause.Cause<unknown>, phase: DefectPhase) => ActorExit<S>;
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* Phase state for supervised actors. Serializes concurrent stop/restart/drain.
|
|
38
|
-
*
|
|
39
|
-
* Transitions:
|
|
40
|
-
* - `Running` → crash → `Restarting` → new runtime → `Running`
|
|
41
|
-
* - `Running` → explicit stop/drain → `Stopping` → `Terminated`
|
|
42
|
-
* - `Restarting` → explicit stop → `Stopping` → `Terminated`
|
|
43
|
-
*
|
|
44
|
-
* @internal
|
|
45
|
-
*/
|
|
46
|
-
type CellPhase<S> = {
|
|
47
|
-
readonly _tag: "Running";
|
|
48
|
-
readonly generation: number;
|
|
49
|
-
} | {
|
|
50
|
-
readonly _tag: "Restarting";
|
|
51
|
-
readonly generation: number;
|
|
52
|
-
} | {
|
|
53
|
-
readonly _tag: "Stopping";
|
|
54
|
-
} | {
|
|
55
|
-
readonly _tag: "Terminated";
|
|
56
|
-
readonly exit: ActorExit<S>;
|
|
57
|
-
};
|
|
58
|
-
declare namespace Supervision {
|
|
59
|
-
/**
|
|
60
|
-
* Supervision policy for actor restart behavior.
|
|
61
|
-
*
|
|
62
|
-
* `schedule` controls restart timing and budget — schedule exhaustion means terminal stop.
|
|
63
|
-
* `shouldRestart` optionally classifies defects — return `false` to stop immediately
|
|
64
|
-
* without consuming the schedule.
|
|
65
|
-
*/
|
|
66
|
-
interface Policy {
|
|
67
|
-
/** Schedule that controls restart timing. Exhaustion = terminal stop. */
|
|
68
|
-
readonly schedule: Schedule.Schedule<unknown>;
|
|
69
|
-
/**
|
|
70
|
-
* Optional classifier: given a defect exit, decide whether to restart or stop immediately.
|
|
71
|
-
* Default: always restart (let schedule handle budget).
|
|
72
|
-
*/
|
|
73
|
-
readonly shouldRestart?: (exit: Extract<ActorExit<unknown>, {
|
|
74
|
-
readonly _tag: "Defect";
|
|
75
|
-
}>) => boolean;
|
|
76
|
-
}
|
|
77
|
-
/** No supervision — crashes are terminal. */
|
|
78
|
-
const none: Policy;
|
|
79
|
-
/**
|
|
80
|
-
* Restart on defect with max restarts within a window, optional backoff.
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* ```ts
|
|
84
|
-
* Supervision.restart() // unlimited restarts, no backoff
|
|
85
|
-
* Supervision.restart({ maxRestarts: 3 }) // 3 restarts then terminal
|
|
86
|
-
* Supervision.restart({ maxRestarts: 3, within: "1 minute" }) // 3 within 1 min
|
|
87
|
-
* Supervision.restart({ backoff: Schedule.exponential("100 millis") })
|
|
88
|
-
* ```
|
|
89
|
-
*/
|
|
90
|
-
const restart: (options?: {
|
|
91
|
-
readonly maxRestarts?: number;
|
|
92
|
-
readonly within?: Duration.DurationInput;
|
|
93
|
-
readonly backoff?: Schedule.Schedule<unknown>;
|
|
94
|
-
}) => Policy;
|
|
95
|
-
}
|
|
96
|
-
//#endregion
|
|
97
|
-
export { ActorExit, CellPhase, DefectPhase, Supervision };
|
package/v3/dist/supervision.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { Schedule } from "effect";
|
|
2
|
-
//#region src/supervision.ts
|
|
3
|
-
/**
|
|
4
|
-
* Supervision types for actor lifecycle management.
|
|
5
|
-
*
|
|
6
|
-
* Core concepts:
|
|
7
|
-
* - `ActorExit<S>` — why an actor stopped (final, explicit stop, or defect)
|
|
8
|
-
* - `DefectPhase` — where in the lifecycle a defect occurred
|
|
9
|
-
* - `Supervision.Policy` — Schedule-based restart policy
|
|
10
|
-
* - `CellPhase<S>` — internal phase machine for serializing stop/restart/drain
|
|
11
|
-
*
|
|
12
|
-
* @module
|
|
13
|
-
*/
|
|
14
|
-
/** Constructors for ActorExit */
|
|
15
|
-
const ActorExit = {
|
|
16
|
-
Final: (state) => ({
|
|
17
|
-
_tag: "Final",
|
|
18
|
-
state
|
|
19
|
-
}),
|
|
20
|
-
Stopped: { _tag: "Stopped" },
|
|
21
|
-
Defect: (cause, phase) => ({
|
|
22
|
-
_tag: "Defect",
|
|
23
|
-
cause,
|
|
24
|
-
phase
|
|
25
|
-
})
|
|
26
|
-
};
|
|
27
|
-
let Supervision;
|
|
28
|
-
(function(_Supervision) {
|
|
29
|
-
_Supervision.none = { schedule: Schedule.recurs(0) };
|
|
30
|
-
_Supervision.restart = (options) => {
|
|
31
|
-
let schedule = Schedule.forever;
|
|
32
|
-
if (options?.maxRestarts !== void 0) {
|
|
33
|
-
const recurs = Schedule.recurs(options.maxRestarts);
|
|
34
|
-
if (options.within !== void 0) schedule = Schedule.intersect(recurs, Schedule.windowed(options.within));
|
|
35
|
-
else schedule = recurs;
|
|
36
|
-
}
|
|
37
|
-
if (options?.backoff !== void 0) schedule = Schedule.intersect(schedule, options.backoff);
|
|
38
|
-
return { schedule };
|
|
39
|
-
};
|
|
40
|
-
})(Supervision || (Supervision = {}));
|
|
41
|
-
//#endregion
|
|
42
|
-
export { ActorExit, Supervision };
|