@pithos/core 2.3.0 → 2.5.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.
Files changed (108) hide show
  1. package/README.md +1 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/autocompletion.d.ts +135 -1
  4. package/dist/eidos/abstract-factory/abstract-factory.d.ts +125 -0
  5. package/dist/eidos/abstract-factory/abstract-factory.d.ts.map +1 -0
  6. package/dist/eidos/abstract-factory/abstract-factory.js +128 -0
  7. package/dist/eidos/abstract-factory/abstract-factory.js.map +1 -0
  8. package/dist/eidos/adapter/adapter.d.ts +97 -0
  9. package/dist/eidos/adapter/adapter.d.ts.map +1 -0
  10. package/dist/eidos/adapter/adapter.js +90 -0
  11. package/dist/eidos/adapter/adapter.js.map +1 -0
  12. package/dist/eidos/bridge/bridge.d.ts +81 -0
  13. package/dist/eidos/bridge/bridge.d.ts.map +1 -0
  14. package/dist/eidos/bridge/bridge.js +75 -0
  15. package/dist/eidos/bridge/bridge.js.map +1 -0
  16. package/dist/eidos/builder/builder.d.ts +181 -0
  17. package/dist/eidos/builder/builder.d.ts.map +1 -0
  18. package/dist/eidos/builder/builder.js +139 -0
  19. package/dist/eidos/builder/builder.js.map +1 -0
  20. package/dist/eidos/chain/chain.d.ts +99 -0
  21. package/dist/eidos/chain/chain.d.ts.map +1 -0
  22. package/dist/eidos/chain/chain.js +111 -0
  23. package/dist/eidos/chain/chain.js.map +1 -0
  24. package/dist/eidos/command/command.d.ts +267 -0
  25. package/dist/eidos/command/command.d.ts.map +1 -0
  26. package/dist/eidos/command/command.js +298 -0
  27. package/dist/eidos/command/command.js.map +1 -0
  28. package/dist/eidos/composite/composite.d.ts +168 -0
  29. package/dist/eidos/composite/composite.d.ts.map +1 -0
  30. package/dist/eidos/composite/composite.js +157 -0
  31. package/dist/eidos/composite/composite.js.map +1 -0
  32. package/dist/eidos/decorator/decorator.d.ts +138 -0
  33. package/dist/eidos/decorator/decorator.d.ts.map +1 -0
  34. package/dist/eidos/decorator/decorator.js +143 -0
  35. package/dist/eidos/decorator/decorator.js.map +1 -0
  36. package/dist/eidos/facade/facade.d.ts +61 -0
  37. package/dist/eidos/facade/facade.d.ts.map +1 -0
  38. package/dist/eidos/facade/facade.js +63 -0
  39. package/dist/eidos/facade/facade.js.map +1 -0
  40. package/dist/eidos/factory-method/factory-method.d.ts +76 -0
  41. package/dist/eidos/factory-method/factory-method.d.ts.map +1 -0
  42. package/dist/eidos/factory-method/factory-method.js +60 -0
  43. package/dist/eidos/factory-method/factory-method.js.map +1 -0
  44. package/dist/eidos/flyweight/flyweight.d.ts +40 -0
  45. package/dist/eidos/flyweight/flyweight.d.ts.map +1 -0
  46. package/dist/eidos/flyweight/flyweight.js +41 -0
  47. package/dist/eidos/flyweight/flyweight.js.map +1 -0
  48. package/dist/eidos/interpreter/interpreter.d.ts +82 -0
  49. package/dist/eidos/interpreter/interpreter.d.ts.map +1 -0
  50. package/dist/eidos/interpreter/interpreter.js +84 -0
  51. package/dist/eidos/interpreter/interpreter.js.map +1 -0
  52. package/dist/eidos/iterator/iterator.d.ts +164 -0
  53. package/dist/eidos/iterator/iterator.d.ts.map +1 -0
  54. package/dist/eidos/iterator/iterator.js +258 -0
  55. package/dist/eidos/iterator/iterator.js.map +1 -0
  56. package/dist/eidos/mediator/mediator.d.ts +102 -0
  57. package/dist/eidos/mediator/mediator.d.ts.map +1 -0
  58. package/dist/eidos/mediator/mediator.js +112 -0
  59. package/dist/eidos/mediator/mediator.js.map +1 -0
  60. package/dist/eidos/memento/memento.d.ts +103 -0
  61. package/dist/eidos/memento/memento.d.ts.map +1 -0
  62. package/dist/eidos/memento/memento.js +114 -0
  63. package/dist/eidos/memento/memento.js.map +1 -0
  64. package/dist/eidos/observer/observer-lite.d.ts +49 -0
  65. package/dist/eidos/observer/observer-lite.d.ts.map +1 -0
  66. package/dist/eidos/observer/observer-lite.js +55 -0
  67. package/dist/eidos/observer/observer-lite.js.map +1 -0
  68. package/dist/eidos/observer/observer.d.ts +96 -0
  69. package/dist/eidos/observer/observer.d.ts.map +1 -0
  70. package/dist/eidos/observer/observer.js +117 -0
  71. package/dist/eidos/observer/observer.js.map +1 -0
  72. package/dist/eidos/prototype/prototype.d.ts +32 -0
  73. package/dist/eidos/prototype/prototype.d.ts.map +1 -0
  74. package/dist/eidos/prototype/prototype.js +33 -0
  75. package/dist/eidos/prototype/prototype.js.map +1 -0
  76. package/dist/eidos/proxy/proxy.d.ts +108 -0
  77. package/dist/eidos/proxy/proxy.d.ts.map +1 -0
  78. package/dist/eidos/proxy/proxy.js +121 -0
  79. package/dist/eidos/proxy/proxy.js.map +1 -0
  80. package/dist/eidos/singleton/singleton.d.ts +76 -0
  81. package/dist/eidos/singleton/singleton.d.ts.map +1 -0
  82. package/dist/eidos/singleton/singleton.js +77 -0
  83. package/dist/eidos/singleton/singleton.js.map +1 -0
  84. package/dist/eidos/state/state-lite.d.ts +102 -0
  85. package/dist/eidos/state/state-lite.d.ts.map +1 -0
  86. package/dist/eidos/state/state-lite.js +69 -0
  87. package/dist/eidos/state/state-lite.js.map +1 -0
  88. package/dist/eidos/state/state.d.ts +152 -0
  89. package/dist/eidos/state/state.d.ts.map +1 -0
  90. package/dist/eidos/state/state.js +85 -0
  91. package/dist/eidos/state/state.js.map +1 -0
  92. package/dist/eidos/strategy/strategy.d.ts +148 -0
  93. package/dist/eidos/strategy/strategy.d.ts.map +1 -0
  94. package/dist/eidos/strategy/strategy.js +167 -0
  95. package/dist/eidos/strategy/strategy.js.map +1 -0
  96. package/dist/eidos/template/template.d.ts +95 -0
  97. package/dist/eidos/template/template.d.ts.map +1 -0
  98. package/dist/eidos/template/template.js +110 -0
  99. package/dist/eidos/template/template.js.map +1 -0
  100. package/dist/eidos/visitor/visitor.d.ts +78 -0
  101. package/dist/eidos/visitor/visitor.d.ts.map +1 -0
  102. package/dist/eidos/visitor/visitor.js +80 -0
  103. package/dist/eidos/visitor/visitor.js.map +1 -0
  104. package/dist/zygos/result/index.d.ts +19 -0
  105. package/dist/zygos/result/index.d.ts.map +1 -0
  106. package/dist/zygos/result/index.js +29 -0
  107. package/dist/zygos/result/index.js.map +1 -0
  108. package/package.json +28 -3
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Functional Proxy Pattern.
3
+ *
4
+ * In OOP, the Proxy pattern requires a Subject interface, a RealSubject class,
5
+ * and a Proxy class that wraps it to control access (lazy init, caching,
6
+ * access control, logging...).
7
+ * In functional TypeScript, Proxy provides ready-made higher-order functions
8
+ * for the most common proxy use cases.
9
+ *
10
+ * Compared to Decorator (generic hooks via before/after/around), Proxy
11
+ * offers opinionated, named wrappers for specific access-control scenarios.
12
+ *
13
+ * Several proxy use cases are already covered by arkhe utilities,
14
+ * re-exported here for discoverability:
15
+ * - `memoize` - caching proxy with custom key resolvers, cache injection (LRU, TTL)
16
+ * - `once` - single-use proxy, executes once then caches the result
17
+ * - `throttle` - rate-limiting proxy, at most one call per time window
18
+ * - `debounce` - debounce proxy, defers execution until inactivity
19
+ *
20
+ * @module eidos/proxy
21
+ * @since 2.4.0
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import { lazy, memoize, once, throttle, guarded } from "@pithos/core/eidos/proxy/proxy";
26
+ *
27
+ * // Lazy initialization proxy
28
+ * const query = lazy(() => {
29
+ * const conn = createConnection();
30
+ * return (sql: string) => conn.execute(sql);
31
+ * });
32
+ *
33
+ * // Caching proxy
34
+ * const fetchUser = memoize((id: string) => db.query(id));
35
+ *
36
+ * // Single-use proxy
37
+ * const init = once(() => bootstrap());
38
+ *
39
+ * // Rate-limiting proxy
40
+ * const onScroll = throttle(() => recalcLayout(), 200);
41
+ *
42
+ * // Access control proxy
43
+ * const deleteUser = guarded(
44
+ * (id: string) => db.delete(id),
45
+ * (id) => id !== "admin" ? true : "Cannot delete admin",
46
+ * );
47
+ * ```
48
+ */
49
+ import { ok, err } from "../../zygos/result/result.js";
50
+ /** Caching proxy - re-exported from arkhe for discoverability. */
51
+ export { memoize } from "../../arkhe/function/memoize.js";
52
+ /** Single-use proxy - re-exported from arkhe for discoverability. */
53
+ export { once } from "../../arkhe/function/once.js";
54
+ /** Rate-limiting proxy - re-exported from arkhe for discoverability. */
55
+ export { throttle } from "../../arkhe/function/throttle.js";
56
+ /** Debounce proxy - re-exported from arkhe for discoverability. */
57
+ export { debounce } from "../../arkhe/function/debounce.js";
58
+ /**
59
+ * Lazy proxy - defers function creation until first call.
60
+ * The factory is called once on the first invocation, then
61
+ * the created function is used directly for all subsequent calls.
62
+ *
63
+ * @template In - The input type
64
+ * @template Out - The output type
65
+ * @param factory - A function that creates the real function on demand
66
+ * @returns A proxy that initializes lazily
67
+ * @since 2.4.0
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * // Expensive connection is only created when first needed
72
+ * const query = lazy(() => {
73
+ * const conn = createConnection(); // heavy init
74
+ * return (sql: string) => conn.execute(sql);
75
+ * });
76
+ *
77
+ * // Nothing happens yet...
78
+ * query("SELECT 1"); // NOW the connection is created, then query runs
79
+ * query("SELECT 2"); // reuses the same connection
80
+ * ```
81
+ */
82
+ export function lazy(factory) {
83
+ let fn = null;
84
+ return (input) => {
85
+ if (!fn)
86
+ fn = factory();
87
+ return fn(input);
88
+ };
89
+ }
90
+ /**
91
+ * Guarded proxy - checks access before calling the function.
92
+ * The check returns `true` to allow, or a rejection reason string to deny.
93
+ * Returns a zygos `Result`: `Ok(output)` if allowed, `Err(reason)` if denied.
94
+ *
95
+ * @template In - The input type
96
+ * @template Out - The output type
97
+ * @param fn - The function to guard
98
+ * @param check - Access check. Return `true` to allow, or a string reason to deny.
99
+ * @returns A proxy returning `Result<Out, string>`
100
+ * @since 2.4.0
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const deleteUser = guarded(
105
+ * (id: string) => db.delete(id),
106
+ * (id) => id !== "admin" ? true : "Cannot delete admin user",
107
+ * );
108
+ *
109
+ * deleteUser("user-1"); // Ok(void)
110
+ * deleteUser("admin"); // Err("Cannot delete admin user")
111
+ * ```
112
+ */
113
+ export function guarded(fn, check) {
114
+ return (input) => {
115
+ const result = check(input);
116
+ if (result !== true)
117
+ return err(result);
118
+ return ok(fn(input));
119
+ };
120
+ }
121
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../../src/eidos/proxy/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAG/C,kEAAkE;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAGlD,qEAAqE;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAE5C,wEAAwE;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,mEAAmE;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,IAAI,CAClB,OAAiC;IAEjC,IAAI,EAAE,GAAgC,IAAI,CAAC;IAC3C,OAAO,CAAC,KAAS,EAAO,EAAE;QACxB,IAAI,CAAC,EAAE;YAAE,EAAE,GAAG,OAAO,EAAE,CAAC;QACxB,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,OAAO,CACrB,EAAsB,EACtB,KAAmC;IAEnC,OAAO,CAAC,KAAS,EAAE,EAAE;QACnB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC;QACxC,OAAO,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACvB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Functional Singleton Pattern.
3
+ *
4
+ * In OOP, the Singleton pattern requires a class with a private constructor
5
+ * and a static `getInstance()` method to ensure only one instance exists.
6
+ *
7
+ * In functional TypeScript, this is absorbed by the ES module system:
8
+ * - A module is evaluated exactly once
9
+ * - `export const instance = create()` is a singleton by default
10
+ * - No pattern needed — it's native module behavior
11
+ *
12
+ * For lazy initialization, Arkhe provides `once` which caches the first call.
13
+ *
14
+ * ## Why Singleton is considered an anti-pattern
15
+ *
16
+ * The Singleton appears in the GoF book (1994), but the community has since
17
+ * largely recognized it as an anti-pattern:
18
+ *
19
+ * - **Global state in disguise** — A singleton is just a global variable with
20
+ * extra steps. It creates implicit coupling throughout your codebase.
21
+ *
22
+ * - **Testability nightmare** — You can't easily mock a singleton. Every test
23
+ * shares the same instance and its state, leading to flaky tests.
24
+ *
25
+ * - **Hidden dependencies** — Code using `getInstance()` has invisible deps.
26
+ * You can't tell what a function needs just by looking at its signature.
27
+ *
28
+ * - **Concurrency issues** — Lazy initialization is a race condition waiting
29
+ * to happen (less relevant in single-threaded JS, but still a code smell).
30
+ *
31
+ * ## The modern alternative: Dependency Injection
32
+ *
33
+ * Instead of reaching for a global singleton, pass dependencies explicitly:
34
+ *
35
+ * ```ts
36
+ * // ❌ Singleton — hidden dependency
37
+ * const fetchUsers = () => {
38
+ * const db = Database.getInstance();
39
+ * return db.query("SELECT * FROM users");
40
+ * };
41
+ *
42
+ * // ✅ Dependency injection — explicit, testable
43
+ * const fetchUsers = (db: Database) => {
44
+ * return db.query("SELECT * FROM users");
45
+ * };
46
+ * ```
47
+ *
48
+ * This module re-exports `once` from Arkhe for discoverability.
49
+ *
50
+ * @module eidos/singleton
51
+ * @since 2.4.0
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * import { once } from "@pithos/core/eidos/singleton/singleton";
56
+ * // or directly from Arkhe:
57
+ * import { once } from "../../arkhe/function/once.js";
58
+ *
59
+ * // Lazy singleton initialization
60
+ * const getDb = once(() => connectToDatabase());
61
+ *
62
+ * getDb(); // connects
63
+ * getDb(); // returns cached connection
64
+ *
65
+ * // But consider: could this be passed as a parameter instead?
66
+ * ```
67
+ */
68
+ export { once } from "../../arkhe/function/once.js";
69
+ /**
70
+ * Alias for `once` — creates a lazy singleton from a factory function.
71
+ * Re-exported for discoverability when searching for "singleton".
72
+ *
73
+ * @see once
74
+ */
75
+ export { once as singleton } from "../../arkhe/function/once.js";
76
+ //# sourceMappingURL=singleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.d.ts","sourceRoot":"","sources":["../../../src/eidos/singleton/singleton.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAE5C;;;;;GAKG;AACH,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Functional Singleton Pattern.
3
+ *
4
+ * In OOP, the Singleton pattern requires a class with a private constructor
5
+ * and a static `getInstance()` method to ensure only one instance exists.
6
+ *
7
+ * In functional TypeScript, this is absorbed by the ES module system:
8
+ * - A module is evaluated exactly once
9
+ * - `export const instance = create()` is a singleton by default
10
+ * - No pattern needed — it's native module behavior
11
+ *
12
+ * For lazy initialization, Arkhe provides `once` which caches the first call.
13
+ *
14
+ * ## Why Singleton is considered an anti-pattern
15
+ *
16
+ * The Singleton appears in the GoF book (1994), but the community has since
17
+ * largely recognized it as an anti-pattern:
18
+ *
19
+ * - **Global state in disguise** — A singleton is just a global variable with
20
+ * extra steps. It creates implicit coupling throughout your codebase.
21
+ *
22
+ * - **Testability nightmare** — You can't easily mock a singleton. Every test
23
+ * shares the same instance and its state, leading to flaky tests.
24
+ *
25
+ * - **Hidden dependencies** — Code using `getInstance()` has invisible deps.
26
+ * You can't tell what a function needs just by looking at its signature.
27
+ *
28
+ * - **Concurrency issues** — Lazy initialization is a race condition waiting
29
+ * to happen (less relevant in single-threaded JS, but still a code smell).
30
+ *
31
+ * ## The modern alternative: Dependency Injection
32
+ *
33
+ * Instead of reaching for a global singleton, pass dependencies explicitly:
34
+ *
35
+ * ```ts
36
+ * // ❌ Singleton — hidden dependency
37
+ * const fetchUsers = () => {
38
+ * const db = Database.getInstance();
39
+ * return db.query("SELECT * FROM users");
40
+ * };
41
+ *
42
+ * // ✅ Dependency injection — explicit, testable
43
+ * const fetchUsers = (db: Database) => {
44
+ * return db.query("SELECT * FROM users");
45
+ * };
46
+ * ```
47
+ *
48
+ * This module re-exports `once` from Arkhe for discoverability.
49
+ *
50
+ * @module eidos/singleton
51
+ * @since 2.4.0
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * import { once } from "@pithos/core/eidos/singleton/singleton";
56
+ * // or directly from Arkhe:
57
+ * import { once } from "../../arkhe/function/once.js";
58
+ *
59
+ * // Lazy singleton initialization
60
+ * const getDb = once(() => connectToDatabase());
61
+ *
62
+ * getDb(); // connects
63
+ * getDb(); // returns cached connection
64
+ *
65
+ * // But consider: could this be passed as a parameter instead?
66
+ * ```
67
+ */
68
+ // Re-export from Arkhe for discoverability
69
+ export { once } from "../../arkhe/function/once.js";
70
+ /**
71
+ * Alias for `once` — creates a lazy singleton from a factory function.
72
+ * Re-exported for discoverability when searching for "singleton".
73
+ *
74
+ * @see once
75
+ */
76
+ export { once as singleton } from "../../arkhe/function/once.js";
77
+ //# sourceMappingURL=singleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.js","sourceRoot":"","sources":["../../../src/eidos/singleton/singleton.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AAEH,2CAA2C;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAE5C;;;;;GAKG;AACH,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Lightweight State Machine — zero external dependencies.
3
+ *
4
+ * Same core API as {@link createMachine} (`current`, `send`, `matches`,
5
+ * `onTransition`, `reset`) but without `trySend` (which pulls `@zygos/option`).
6
+ *
7
+ * @module eidos/state/state-lite
8
+ * @since 2.5.0
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { createLiteMachine } from "@pithos/core/eidos/state/state-lite";
13
+ *
14
+ * const light = createLiteMachine({
15
+ * green: { timer: { to: "yellow" } },
16
+ * yellow: { timer: { to: "red" } },
17
+ * red: { timer: { to: "green" } },
18
+ * }, "green");
19
+ *
20
+ * light.current(); // "green"
21
+ * light.send("timer"); // "yellow"
22
+ * ```
23
+ */
24
+ /** A simple transition to a target state. */
25
+ export interface SimpleTransition<S extends string> {
26
+ readonly to: S;
27
+ }
28
+ /**
29
+ * A transition that also updates context.
30
+ *
31
+ * @since 2.5.0
32
+ */
33
+ export interface ContextTransition<S extends string, C> {
34
+ readonly to: S;
35
+ readonly update: (ctx: C) => C;
36
+ }
37
+ /**
38
+ * A transition is either simple (just target) or with context update.
39
+ *
40
+ * @since 2.5.0
41
+ */
42
+ export type Transition<S extends string, C> = SimpleTransition<S> | ContextTransition<S, C>;
43
+ /**
44
+ * A transition map for a single state.
45
+ *
46
+ * @since 2.5.0
47
+ */
48
+ export type Transitions<S extends string, E extends string, C> = {
49
+ readonly [K in E]?: Transition<S, C>;
50
+ };
51
+ /**
52
+ * Full state machine definition.
53
+ *
54
+ * @since 2.5.0
55
+ */
56
+ export type MachineDefinition<S extends string, E extends string, C> = {
57
+ readonly [K in S]: Transitions<S, E, C>;
58
+ };
59
+ /**
60
+ * A transition listener receives the previous state, the event, and the new state.
61
+ *
62
+ * @since 2.5.0
63
+ */
64
+ export type TransitionListener<S extends string, E extends string> = (from: S, event: E, to: S) => void;
65
+ /**
66
+ * Creates a lightweight finite state machine (no `trySend`, no `@zygos/option` dependency).
67
+ *
68
+ * @template S - Union of state names
69
+ * @template E - Union of event names
70
+ * @param definition - The state/transition map
71
+ * @param initial - The initial state
72
+ * @returns A machine with `current`, `send`, `matches`, `onTransition`, `reset`
73
+ * @since 2.5.0
74
+ */
75
+ export declare function createLiteMachine<S extends string, E extends string>(definition: MachineDefinition<S, E, undefined>, initial: S): {
76
+ current: () => S;
77
+ send: (event: E) => S;
78
+ matches: (state: S) => boolean;
79
+ onTransition: (listener: TransitionListener<S, E>) => () => void;
80
+ reset: () => void;
81
+ };
82
+ /**
83
+ * Creates a lightweight finite state machine with context.
84
+ *
85
+ * @template S - Union of state names
86
+ * @template E - Union of event names
87
+ * @template C - Context type
88
+ * @param definition - The state/transition map
89
+ * @param initial - The initial state
90
+ * @param initialContext - The initial context value
91
+ * @returns A machine with `current`, `context`, `send`, `matches`, `onTransition`, `reset`
92
+ * @since 2.5.0
93
+ */
94
+ export declare function createLiteMachine<S extends string, E extends string, C>(definition: MachineDefinition<S, E, C>, initial: S, initialContext: C): {
95
+ current: () => S;
96
+ context: () => C;
97
+ send: (event: E) => S;
98
+ matches: (state: S) => boolean;
99
+ onTransition: (listener: TransitionListener<S, E>) => () => void;
100
+ reset: () => void;
101
+ };
102
+ //# sourceMappingURL=state-lite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-lite.d.ts","sourceRoot":"","sources":["../../../src/eidos/state/state-lite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM;IAChD,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC;IACpD,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IACf,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;CAChC;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,IACtC,gBAAgB,CAAC,CAAC,CAAC,GACnB,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE5B;;;;GAIG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI;IAC/D,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC;CACrC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI;IACrE,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,IAAI,CACnE,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,CAAC,EACR,EAAE,EAAE,CAAC,KACF,IAAI,CAAC;AAQV;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAClE,UAAU,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,EAC9C,OAAO,EAAE,CAAC,GACT;IACD,OAAO,EAAE,MAAM,CAAC,CAAC;IACjB,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IACtB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAC/B,YAAY,EAAE,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC;IACjE,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,EACrE,UAAU,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACtC,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,CAAC,GAChB;IACD,OAAO,EAAE,MAAM,CAAC,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,CAAC;IACjB,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IACtB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAC/B,YAAY,EAAE,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC;IACjE,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Lightweight State Machine — zero external dependencies.
3
+ *
4
+ * Same core API as {@link createMachine} (`current`, `send`, `matches`,
5
+ * `onTransition`, `reset`) but without `trySend` (which pulls `@zygos/option`).
6
+ *
7
+ * @module eidos/state/state-lite
8
+ * @since 2.5.0
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { createLiteMachine } from "@pithos/core/eidos/state/state-lite";
13
+ *
14
+ * const light = createLiteMachine({
15
+ * green: { timer: { to: "yellow" } },
16
+ * yellow: { timer: { to: "red" } },
17
+ * red: { timer: { to: "green" } },
18
+ * }, "green");
19
+ *
20
+ * light.current(); // "green"
21
+ * light.send("timer"); // "yellow"
22
+ * ```
23
+ */
24
+ function hasUpdate(t) {
25
+ return "update" in t;
26
+ }
27
+ export function createLiteMachine(definition, initial, initialContext) {
28
+ let state = initial;
29
+ let ctx = initialContext;
30
+ const listeners = new Set();
31
+ const send = (event) => {
32
+ const transitions = definition[state];
33
+ const transition = transitions[event];
34
+ if (transition === undefined)
35
+ return state;
36
+ const from = state;
37
+ state = transition.to;
38
+ // Stryker disable next-line ConditionalExpression: ctx check is defensive - TypeScript prevents update on machines without context
39
+ if (hasUpdate(transition) && ctx !== undefined) {
40
+ ctx = transition.update(ctx);
41
+ }
42
+ for (const listener of listeners) {
43
+ listener(from, event, state);
44
+ }
45
+ return state;
46
+ };
47
+ const onTransition = (listener) => {
48
+ listeners.add(listener);
49
+ return () => { listeners.delete(listener); };
50
+ };
51
+ const base = {
52
+ current: () => state,
53
+ send,
54
+ matches: (s) => state === s,
55
+ onTransition,
56
+ reset: () => {
57
+ state = initial;
58
+ ctx = initialContext;
59
+ },
60
+ };
61
+ if (initialContext !== undefined) {
62
+ return {
63
+ ...base,
64
+ context: () => ctx,
65
+ };
66
+ }
67
+ return base;
68
+ }
69
+ //# sourceMappingURL=state-lite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-lite.js","sourceRoot":"","sources":["../../../src/eidos/state/state-lite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAuDH,SAAS,SAAS,CAChB,CAAmB;IAEnB,OAAO,QAAQ,IAAI,CAAC,CAAC;AACvB,CAAC;AAgDD,MAAM,UAAU,iBAAiB,CAC/B,UAAsC,EACtC,OAAU,EACV,cAAkB;IAElB,IAAI,KAAK,GAAM,OAAO,CAAC;IACvB,IAAI,GAAG,GAAkB,cAAc,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;IAEtD,MAAM,IAAI,GAAG,CAAC,KAAQ,EAAK,EAAE;QAC3B,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,UAAU,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAE3C,MAAM,IAAI,GAAG,KAAK,CAAC;QACnB,KAAK,GAAG,UAAU,CAAC,EAAE,CAAC;QAEtB,mIAAmI;QACnI,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC/C,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,QAAkC,EAAgB,EAAE;QACxE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxB,OAAO,GAAG,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG;QACX,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;QACpB,IAAI;QACJ,OAAO,EAAE,CAAC,CAAI,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC;QAC9B,YAAY;QACZ,KAAK,EAAE,GAAG,EAAE;YACV,KAAK,GAAG,OAAO,CAAC;YAChB,GAAG,GAAG,cAAc,CAAC;QACvB,CAAC;KACF,CAAC;IAEF,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO;YACL,GAAG,IAAI;YACP,OAAO,EAAE,GAAG,EAAE,CAAC,GAAQ;SACxB,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Functional State Pattern.
3
+ *
4
+ * In OOP, the State pattern requires a Context class, a State interface,
5
+ * and concrete State subclasses that the Context delegates to.
6
+ * In functional TypeScript, a state machine is a record of transitions
7
+ * keyed by state, where each transition maps an event to the next state
8
+ * (and optionally updates context).
9
+ *
10
+ * @module eidos/state
11
+ * @since 2.4.0
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { createMachine } from "@pithos/core/eidos/state/state";
16
+ *
17
+ * const light = createMachine({
18
+ * green: { timer: { to: "yellow" } },
19
+ * yellow: { timer: { to: "red" } },
20
+ * red: { timer: { to: "green" } },
21
+ * }, "green");
22
+ *
23
+ * light.current(); // "green"
24
+ * light.send("timer"); // "yellow"
25
+ * light.send("timer"); // "red"
26
+ * ```
27
+ */
28
+ import type { Option } from "../../zygos/option.js";
29
+ /**
30
+ * A simple transition to a target state.
31
+ *
32
+ * @template S - Union of state names
33
+ * @since 2.4.0
34
+ */
35
+ export interface SimpleTransition<S extends string> {
36
+ readonly to: S;
37
+ }
38
+ /**
39
+ * A transition that updates context.
40
+ *
41
+ * @template S - Union of state names
42
+ * @template C - Context type
43
+ * @since 2.4.0
44
+ */
45
+ export interface ContextTransition<S extends string, C> {
46
+ readonly to: S;
47
+ readonly update: (ctx: C) => C;
48
+ }
49
+ /**
50
+ * A transition is either simple (just target) or with context update.
51
+ *
52
+ * @template S - Union of state names
53
+ * @template C - Context type
54
+ * @since 2.4.0
55
+ */
56
+ export type Transition<S extends string, C> = SimpleTransition<S> | ContextTransition<S, C>;
57
+ /**
58
+ * A transition map for a single state.
59
+ *
60
+ * @template S - Union of state names
61
+ * @template E - Union of event names
62
+ * @template C - Context type
63
+ * @since 2.4.0
64
+ */
65
+ export type Transitions<S extends string, E extends string, C> = {
66
+ readonly [K in E]?: Transition<S, C>;
67
+ };
68
+ /**
69
+ * Full state machine definition.
70
+ *
71
+ * @template S - Union of state names
72
+ * @template E - Union of event names
73
+ * @template C - Context type
74
+ * @since 2.4.0
75
+ */
76
+ export type MachineDefinition<S extends string, E extends string, C> = {
77
+ readonly [K in S]: Transitions<S, E, C>;
78
+ };
79
+ /**
80
+ * A transition listener receives the previous state, the event, and the new state.
81
+ *
82
+ * @template S - Union of state names
83
+ * @template E - Union of event names
84
+ * @since 2.4.0
85
+ */
86
+ export type TransitionListener<S extends string, E extends string> = (from: S, event: E, to: S) => void;
87
+ /**
88
+ * Creates a finite state machine.
89
+ *
90
+ * @template S - Union of state names
91
+ * @template E - Union of event names
92
+ * @param definition - The state/transition map
93
+ * @param initial - The initial state
94
+ * @returns A machine with `current`, `send`, `matches`, `trySend`, `onTransition`, `reset`
95
+ * @since 2.4.0
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * const door = createMachine({
100
+ * locked: { unlock: { to: "closed" } },
101
+ * closed: { open: { to: "opened" }, lock: { to: "locked" } },
102
+ * opened: { close: { to: "closed" } },
103
+ * }, "locked");
104
+ *
105
+ * door.send("unlock"); // "closed"
106
+ * door.send("open"); // "opened"
107
+ * door.matches("opened"); // true
108
+ * ```
109
+ */
110
+ export declare function createMachine<S extends string, E extends string>(definition: MachineDefinition<S, E, undefined>, initial: S): {
111
+ current: () => S;
112
+ send: (event: E) => S;
113
+ matches: (state: S) => boolean;
114
+ trySend: (event: E) => Option<S>;
115
+ onTransition: (listener: TransitionListener<S, E>) => () => void;
116
+ reset: () => void;
117
+ };
118
+ /**
119
+ * Creates a finite state machine with context.
120
+ *
121
+ * @template S - Union of state names
122
+ * @template E - Union of event names
123
+ * @template C - Context type
124
+ * @param definition - The state/transition map
125
+ * @param initial - The initial state
126
+ * @param initialContext - The initial context value
127
+ * @returns A machine with `current`, `context`, `send`, `matches`, `trySend`, `onTransition`, `reset`
128
+ * @since 2.4.0
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * const counter = createMachine({
133
+ * active: {
134
+ * increment: { to: "active", update: (ctx: number) => ctx + 1 },
135
+ * reset: { to: "active", update: () => 0 },
136
+ * },
137
+ * }, "active", 0);
138
+ *
139
+ * counter.send("increment"); // "active"
140
+ * counter.context(); // 1
141
+ * ```
142
+ */
143
+ export declare function createMachine<S extends string, E extends string, C>(definition: MachineDefinition<S, E, C>, initial: S, initialContext: C): {
144
+ current: () => S;
145
+ context: () => C;
146
+ send: (event: E) => S;
147
+ matches: (state: S) => boolean;
148
+ trySend: (event: E) => Option<S>;
149
+ onTransition: (listener: TransitionListener<S, E>) => () => void;
150
+ reset: () => void;
151
+ };
152
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/eidos/state/state.ts"],"names":[],"mappings":"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"}