@plures/praxis 0.2.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 (263) hide show
  1. package/FRAMEWORK.md +420 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1310 -0
  4. package/dist/adapters/cli.d.ts +43 -0
  5. package/dist/adapters/cli.d.ts.map +1 -0
  6. package/dist/adapters/cli.js +126 -0
  7. package/dist/adapters/cli.js.map +1 -0
  8. package/dist/cli/commands/auth.d.ts +26 -0
  9. package/dist/cli/commands/auth.d.ts.map +1 -0
  10. package/dist/cli/commands/auth.js +233 -0
  11. package/dist/cli/commands/auth.js.map +1 -0
  12. package/dist/cli/commands/cloud.d.ts +27 -0
  13. package/dist/cli/commands/cloud.d.ts.map +1 -0
  14. package/dist/cli/commands/cloud.js +232 -0
  15. package/dist/cli/commands/cloud.js.map +1 -0
  16. package/dist/cli/commands/generate.d.ts +25 -0
  17. package/dist/cli/commands/generate.d.ts.map +1 -0
  18. package/dist/cli/commands/generate.js +168 -0
  19. package/dist/cli/commands/generate.js.map +1 -0
  20. package/dist/cli/index.d.ts +8 -0
  21. package/dist/cli/index.d.ts.map +1 -0
  22. package/dist/cli/index.js +179 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/cloud/auth.d.ts +51 -0
  25. package/dist/cloud/auth.d.ts.map +1 -0
  26. package/dist/cloud/auth.js +194 -0
  27. package/dist/cloud/auth.js.map +1 -0
  28. package/dist/cloud/billing.d.ts +184 -0
  29. package/dist/cloud/billing.d.ts.map +1 -0
  30. package/dist/cloud/billing.js +179 -0
  31. package/dist/cloud/billing.js.map +1 -0
  32. package/dist/cloud/client.d.ts +39 -0
  33. package/dist/cloud/client.d.ts.map +1 -0
  34. package/dist/cloud/client.js +176 -0
  35. package/dist/cloud/client.js.map +1 -0
  36. package/dist/cloud/index.d.ts +44 -0
  37. package/dist/cloud/index.d.ts.map +1 -0
  38. package/dist/cloud/index.js +44 -0
  39. package/dist/cloud/index.js.map +1 -0
  40. package/dist/cloud/marketplace.d.ts +166 -0
  41. package/dist/cloud/marketplace.d.ts.map +1 -0
  42. package/dist/cloud/marketplace.js +159 -0
  43. package/dist/cloud/marketplace.js.map +1 -0
  44. package/dist/cloud/provisioning.d.ts +110 -0
  45. package/dist/cloud/provisioning.d.ts.map +1 -0
  46. package/dist/cloud/provisioning.js +148 -0
  47. package/dist/cloud/provisioning.js.map +1 -0
  48. package/dist/cloud/relay/endpoints.d.ts +62 -0
  49. package/dist/cloud/relay/endpoints.d.ts.map +1 -0
  50. package/dist/cloud/relay/endpoints.js +217 -0
  51. package/dist/cloud/relay/endpoints.js.map +1 -0
  52. package/dist/cloud/relay/health/index.d.ts +5 -0
  53. package/dist/cloud/relay/health/index.d.ts.map +1 -0
  54. package/dist/cloud/relay/health/index.js +9 -0
  55. package/dist/cloud/relay/health/index.js.map +1 -0
  56. package/dist/cloud/relay/stats/index.d.ts +5 -0
  57. package/dist/cloud/relay/stats/index.d.ts.map +1 -0
  58. package/dist/cloud/relay/stats/index.js +9 -0
  59. package/dist/cloud/relay/stats/index.js.map +1 -0
  60. package/dist/cloud/relay/sync/index.d.ts +5 -0
  61. package/dist/cloud/relay/sync/index.d.ts.map +1 -0
  62. package/dist/cloud/relay/sync/index.js +9 -0
  63. package/dist/cloud/relay/sync/index.js.map +1 -0
  64. package/dist/cloud/relay/usage/index.d.ts +5 -0
  65. package/dist/cloud/relay/usage/index.d.ts.map +1 -0
  66. package/dist/cloud/relay/usage/index.js +9 -0
  67. package/dist/cloud/relay/usage/index.js.map +1 -0
  68. package/dist/cloud/sponsors.d.ts +81 -0
  69. package/dist/cloud/sponsors.d.ts.map +1 -0
  70. package/dist/cloud/sponsors.js +130 -0
  71. package/dist/cloud/sponsors.js.map +1 -0
  72. package/dist/cloud/types.d.ts +169 -0
  73. package/dist/cloud/types.d.ts.map +1 -0
  74. package/dist/cloud/types.js +7 -0
  75. package/dist/cloud/types.js.map +1 -0
  76. package/dist/components/index.d.ts +43 -0
  77. package/dist/components/index.d.ts.map +1 -0
  78. package/dist/components/index.js +17 -0
  79. package/dist/components/index.js.map +1 -0
  80. package/dist/core/actors.d.ts +95 -0
  81. package/dist/core/actors.d.ts.map +1 -0
  82. package/dist/core/actors.js +158 -0
  83. package/dist/core/actors.js.map +1 -0
  84. package/dist/core/component/generator.d.ts +122 -0
  85. package/dist/core/component/generator.d.ts.map +1 -0
  86. package/dist/core/component/generator.js +307 -0
  87. package/dist/core/component/generator.js.map +1 -0
  88. package/dist/core/engine.d.ts +92 -0
  89. package/dist/core/engine.d.ts.map +1 -0
  90. package/dist/core/engine.js +199 -0
  91. package/dist/core/engine.js.map +1 -0
  92. package/dist/core/introspection.d.ts +141 -0
  93. package/dist/core/introspection.d.ts.map +1 -0
  94. package/dist/core/introspection.js +208 -0
  95. package/dist/core/introspection.js.map +1 -0
  96. package/dist/core/logic/generator.d.ts +76 -0
  97. package/dist/core/logic/generator.d.ts.map +1 -0
  98. package/dist/core/logic/generator.js +339 -0
  99. package/dist/core/logic/generator.js.map +1 -0
  100. package/dist/core/pluresdb/generator.d.ts +58 -0
  101. package/dist/core/pluresdb/generator.d.ts.map +1 -0
  102. package/dist/core/pluresdb/generator.js +162 -0
  103. package/dist/core/pluresdb/generator.js.map +1 -0
  104. package/dist/core/protocol.d.ts +121 -0
  105. package/dist/core/protocol.d.ts.map +1 -0
  106. package/dist/core/protocol.js +46 -0
  107. package/dist/core/protocol.js.map +1 -0
  108. package/dist/core/rules.d.ts +120 -0
  109. package/dist/core/rules.d.ts.map +1 -0
  110. package/dist/core/rules.js +81 -0
  111. package/dist/core/rules.js.map +1 -0
  112. package/dist/core/schema/loader.d.ts +47 -0
  113. package/dist/core/schema/loader.d.ts.map +1 -0
  114. package/dist/core/schema/loader.js +189 -0
  115. package/dist/core/schema/loader.js.map +1 -0
  116. package/dist/core/schema/normalize.d.ts +72 -0
  117. package/dist/core/schema/normalize.d.ts.map +1 -0
  118. package/dist/core/schema/normalize.js +190 -0
  119. package/dist/core/schema/normalize.js.map +1 -0
  120. package/dist/core/schema/types.d.ts +370 -0
  121. package/dist/core/schema/types.d.ts.map +1 -0
  122. package/dist/core/schema/types.js +161 -0
  123. package/dist/core/schema/types.js.map +1 -0
  124. package/dist/dsl/index.d.ts +152 -0
  125. package/dist/dsl/index.d.ts.map +1 -0
  126. package/dist/dsl/index.js +132 -0
  127. package/dist/dsl/index.js.map +1 -0
  128. package/dist/dsl.d.ts +124 -0
  129. package/dist/dsl.d.ts.map +1 -0
  130. package/dist/dsl.js +130 -0
  131. package/dist/dsl.js.map +1 -0
  132. package/dist/examples/advanced-todo/index.d.ts +55 -0
  133. package/dist/examples/advanced-todo/index.d.ts.map +1 -0
  134. package/dist/examples/advanced-todo/index.js +222 -0
  135. package/dist/examples/advanced-todo/index.js.map +1 -0
  136. package/dist/examples/auth-basic/index.d.ts +17 -0
  137. package/dist/examples/auth-basic/index.d.ts.map +1 -0
  138. package/dist/examples/auth-basic/index.js +122 -0
  139. package/dist/examples/auth-basic/index.js.map +1 -0
  140. package/dist/examples/cart/index.d.ts +19 -0
  141. package/dist/examples/cart/index.d.ts.map +1 -0
  142. package/dist/examples/cart/index.js +202 -0
  143. package/dist/examples/cart/index.js.map +1 -0
  144. package/dist/examples/hero-ecommerce/index.d.ts +39 -0
  145. package/dist/examples/hero-ecommerce/index.d.ts.map +1 -0
  146. package/dist/examples/hero-ecommerce/index.js +506 -0
  147. package/dist/examples/hero-ecommerce/index.js.map +1 -0
  148. package/dist/examples/svelte-counter/index.d.ts +31 -0
  149. package/dist/examples/svelte-counter/index.d.ts.map +1 -0
  150. package/dist/examples/svelte-counter/index.js +123 -0
  151. package/dist/examples/svelte-counter/index.js.map +1 -0
  152. package/dist/flows.d.ts +125 -0
  153. package/dist/flows.d.ts.map +1 -0
  154. package/dist/flows.js +160 -0
  155. package/dist/flows.js.map +1 -0
  156. package/dist/index.d.ts +67 -0
  157. package/dist/index.d.ts.map +1 -0
  158. package/dist/index.js +59 -0
  159. package/dist/index.js.map +1 -0
  160. package/dist/integrations/pluresdb.d.ts +56 -0
  161. package/dist/integrations/pluresdb.d.ts.map +1 -0
  162. package/dist/integrations/pluresdb.js +46 -0
  163. package/dist/integrations/pluresdb.js.map +1 -0
  164. package/dist/integrations/svelte.d.ts +306 -0
  165. package/dist/integrations/svelte.d.ts.map +1 -0
  166. package/dist/integrations/svelte.js +447 -0
  167. package/dist/integrations/svelte.js.map +1 -0
  168. package/dist/registry.d.ts +94 -0
  169. package/dist/registry.d.ts.map +1 -0
  170. package/dist/registry.js +181 -0
  171. package/dist/registry.js.map +1 -0
  172. package/dist/runtime/terminal-adapter.d.ts +105 -0
  173. package/dist/runtime/terminal-adapter.d.ts.map +1 -0
  174. package/dist/runtime/terminal-adapter.js +113 -0
  175. package/dist/runtime/terminal-adapter.js.map +1 -0
  176. package/dist/step.d.ts +34 -0
  177. package/dist/step.d.ts.map +1 -0
  178. package/dist/step.js +111 -0
  179. package/dist/step.js.map +1 -0
  180. package/dist/types.d.ts +63 -0
  181. package/dist/types.d.ts.map +1 -0
  182. package/dist/types.js +6 -0
  183. package/dist/types.js.map +1 -0
  184. package/docs/MONETIZATION.md +394 -0
  185. package/docs/TERMINAL_NODE.md +588 -0
  186. package/docs/guides/canvas.md +389 -0
  187. package/docs/guides/getting-started.md +347 -0
  188. package/docs/guides/history-state-pattern.md +618 -0
  189. package/docs/guides/orchestration.md +617 -0
  190. package/docs/guides/parallel-state-pattern.md +767 -0
  191. package/docs/guides/svelte-integration.md +691 -0
  192. package/package.json +96 -0
  193. package/src/__tests__/actors.test.ts +270 -0
  194. package/src/__tests__/billing.test.ts +175 -0
  195. package/src/__tests__/cloud.test.ts +247 -0
  196. package/src/__tests__/dsl.test.ts +154 -0
  197. package/src/__tests__/edge-cases.test.ts +475 -0
  198. package/src/__tests__/engine.test.ts +137 -0
  199. package/src/__tests__/generators.test.ts +270 -0
  200. package/src/__tests__/introspection.test.ts +321 -0
  201. package/src/__tests__/protocol.test.ts +40 -0
  202. package/src/__tests__/provisioning.test.ts +162 -0
  203. package/src/__tests__/schema.test.ts +241 -0
  204. package/src/__tests__/svelte-integration.test.ts +431 -0
  205. package/src/__tests__/terminal-node.test.ts +352 -0
  206. package/src/adapters/cli.ts +175 -0
  207. package/src/cli/commands/auth.ts +271 -0
  208. package/src/cli/commands/cloud.ts +281 -0
  209. package/src/cli/commands/generate.ts +225 -0
  210. package/src/cli/index.ts +190 -0
  211. package/src/cloud/README.md +383 -0
  212. package/src/cloud/auth.ts +245 -0
  213. package/src/cloud/billing.ts +336 -0
  214. package/src/cloud/client.ts +221 -0
  215. package/src/cloud/index.ts +121 -0
  216. package/src/cloud/marketplace.ts +303 -0
  217. package/src/cloud/provisioning.ts +254 -0
  218. package/src/cloud/relay/endpoints.ts +307 -0
  219. package/src/cloud/relay/health/function.json +17 -0
  220. package/src/cloud/relay/health/index.ts +10 -0
  221. package/src/cloud/relay/host.json +15 -0
  222. package/src/cloud/relay/local.settings.json +8 -0
  223. package/src/cloud/relay/stats/function.json +17 -0
  224. package/src/cloud/relay/stats/index.ts +10 -0
  225. package/src/cloud/relay/sync/function.json +17 -0
  226. package/src/cloud/relay/sync/index.ts +10 -0
  227. package/src/cloud/relay/usage/function.json +17 -0
  228. package/src/cloud/relay/usage/index.ts +10 -0
  229. package/src/cloud/sponsors.ts +213 -0
  230. package/src/cloud/types.ts +198 -0
  231. package/src/components/README.md +125 -0
  232. package/src/components/TerminalNode.svelte +457 -0
  233. package/src/components/index.ts +46 -0
  234. package/src/core/actors.ts +205 -0
  235. package/src/core/component/generator.ts +432 -0
  236. package/src/core/engine.ts +243 -0
  237. package/src/core/introspection.ts +329 -0
  238. package/src/core/logic/generator.ts +420 -0
  239. package/src/core/pluresdb/generator.ts +229 -0
  240. package/src/core/protocol.ts +132 -0
  241. package/src/core/rules.ts +167 -0
  242. package/src/core/schema/loader.ts +247 -0
  243. package/src/core/schema/normalize.ts +322 -0
  244. package/src/core/schema/types.ts +557 -0
  245. package/src/dsl/index.ts +218 -0
  246. package/src/dsl.ts +214 -0
  247. package/src/examples/advanced-todo/App.svelte +506 -0
  248. package/src/examples/advanced-todo/README.md +371 -0
  249. package/src/examples/advanced-todo/index.ts +309 -0
  250. package/src/examples/auth-basic/index.ts +163 -0
  251. package/src/examples/cart/index.ts +259 -0
  252. package/src/examples/hero-ecommerce/index.ts +657 -0
  253. package/src/examples/svelte-counter/index.ts +168 -0
  254. package/src/flows.ts +268 -0
  255. package/src/index.ts +154 -0
  256. package/src/integrations/pluresdb.ts +93 -0
  257. package/src/integrations/svelte.ts +617 -0
  258. package/src/registry.ts +223 -0
  259. package/src/runtime/terminal-adapter.ts +175 -0
  260. package/src/step.ts +151 -0
  261. package/src/types.ts +70 -0
  262. package/templates/basic-app/README.md +147 -0
  263. package/templates/fullstack-app/README.md +279 -0
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Svelte Counter Example
3
+ *
4
+ * Demonstrates Svelte v5 integration with a simple counter.
5
+ * Shows how to connect Praxis logic to reactive Svelte stores.
6
+ */
7
+
8
+ import {
9
+ createPraxisEngine,
10
+ PraxisRegistry,
11
+ defineFact,
12
+ defineEvent,
13
+ defineRule,
14
+ findEvent,
15
+ } from "../../index.js";
16
+ import { createPraxisStore, createDerivedStore } from "../../integrations/svelte.js";
17
+
18
+ // Define the context type
19
+ interface CounterContext {
20
+ count: number;
21
+ history: number[];
22
+ }
23
+
24
+ // Define facts
25
+ const CountIncremented = defineFact<"CountIncremented", { amount: number }>(
26
+ "CountIncremented"
27
+ );
28
+ const CountDecremented = defineFact<"CountDecremented", { amount: number }>(
29
+ "CountDecremented"
30
+ );
31
+ const CountReset = defineFact<"CountReset", {}>("CountReset");
32
+
33
+ // Define events
34
+ const Increment = defineEvent<"INCREMENT", { amount?: number }>("INCREMENT");
35
+ const Decrement = defineEvent<"DECREMENT", { amount?: number }>("DECREMENT");
36
+ const Reset = defineEvent<"RESET", {}>("RESET");
37
+
38
+ // Define rules
39
+ const incrementRule = defineRule<CounterContext>({
40
+ id: "counter.increment",
41
+ description: "Increment the counter",
42
+ impl: (state, events) => {
43
+ const incrementEvent = findEvent(events, Increment);
44
+ if (!incrementEvent) {
45
+ return [];
46
+ }
47
+
48
+ const amount = incrementEvent.payload.amount ?? 1;
49
+ state.context.count += amount;
50
+ state.context.history.push(state.context.count);
51
+
52
+ return [CountIncremented.create({ amount })];
53
+ },
54
+ });
55
+
56
+ const decrementRule = defineRule<CounterContext>({
57
+ id: "counter.decrement",
58
+ description: "Decrement the counter",
59
+ impl: (state, events) => {
60
+ const decrementEvent = findEvent(events, Decrement);
61
+ if (!decrementEvent) {
62
+ return [];
63
+ }
64
+
65
+ const amount = decrementEvent.payload.amount ?? 1;
66
+ state.context.count -= amount;
67
+ state.context.history.push(state.context.count);
68
+
69
+ return [CountDecremented.create({ amount })];
70
+ },
71
+ });
72
+
73
+ const resetRule = defineRule<CounterContext>({
74
+ id: "counter.reset",
75
+ description: "Reset the counter",
76
+ impl: (state, events) => {
77
+ const resetEvent = findEvent(events, Reset);
78
+ if (!resetEvent) {
79
+ return [];
80
+ }
81
+
82
+ state.context.count = 0;
83
+ state.context.history = [0];
84
+
85
+ return [CountReset.create({})];
86
+ },
87
+ });
88
+
89
+ // Create and configure the engine
90
+ function createCounterEngine() {
91
+ const registry = new PraxisRegistry<CounterContext>();
92
+ registry.registerRule(incrementRule);
93
+ registry.registerRule(decrementRule);
94
+ registry.registerRule(resetRule);
95
+
96
+ const engine = createPraxisEngine<CounterContext>({
97
+ initialContext: {
98
+ count: 0,
99
+ history: [0],
100
+ },
101
+ registry,
102
+ });
103
+
104
+ return engine;
105
+ }
106
+
107
+ // Create Svelte stores
108
+ function createCounterStores() {
109
+ const engine = createCounterEngine();
110
+
111
+ const stateStore = createPraxisStore(engine);
112
+ const countStore = createDerivedStore(engine, (ctx: CounterContext) => ctx.count);
113
+ const historyStore = createDerivedStore(engine, (ctx: CounterContext) => ctx.history);
114
+
115
+ return {
116
+ engine,
117
+ stateStore,
118
+ countStore,
119
+ historyStore,
120
+ // Helper methods
121
+ increment: (amount?: number) => {
122
+ engine.step([Increment.create({ amount })]);
123
+ },
124
+ decrement: (amount?: number) => {
125
+ engine.step([Decrement.create({ amount })]);
126
+ },
127
+ reset: () => {
128
+ engine.step([Reset.create({})]);
129
+ },
130
+ };
131
+ }
132
+
133
+ // Example usage (non-Svelte demonstration)
134
+ function runExample() {
135
+ console.log("=== Svelte Counter Example ===\n");
136
+
137
+ const { engine, countStore } = createCounterStores();
138
+
139
+ // Subscribe to count changes
140
+ console.log("Subscribing to count changes...\n");
141
+ const unsubscribe = countStore.subscribe((count) => {
142
+ console.log(`Count changed: ${count}`);
143
+ });
144
+
145
+ // Dispatch some events
146
+ console.log("\nIncrementing by 1:");
147
+ engine.step([Increment.create({})]);
148
+
149
+ console.log("\nIncrementing by 5:");
150
+ engine.step([Increment.create({ amount: 5 })]);
151
+
152
+ console.log("\nDecrementing by 2:");
153
+ engine.step([Decrement.create({ amount: 2 })]);
154
+
155
+ console.log("\nResetting:");
156
+ engine.step([Reset.create({})]);
157
+
158
+ console.log("\nContext:", engine.getContext());
159
+
160
+ unsubscribe();
161
+ }
162
+
163
+ // Run example if executed directly
164
+ if (import.meta.url === `file://${process.argv[1]}`) {
165
+ runExample();
166
+ }
167
+
168
+ export { createCounterEngine, createCounterStores, runExample };
package/src/flows.ts ADDED
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Flows and actors for orchestrating state transitions in Praxis.
3
+ * Flows represent sequences of state transitions.
4
+ * Actors are entities that maintain their own state and respond to events.
5
+ */
6
+
7
+ import type { PraxisState, PraxisEvent, StepResult, StepFunction } from './types.js';
8
+
9
+ /**
10
+ * A flow represents a sequence of events that need to occur.
11
+ */
12
+ export interface Flow<E extends PraxisEvent = PraxisEvent> {
13
+ /** Unique identifier for the flow */
14
+ id: string;
15
+ /** Description of what the flow accomplishes */
16
+ description?: string;
17
+ /** Steps in the flow */
18
+ steps: FlowStep<E>[];
19
+ /** Current step index */
20
+ currentStep: number;
21
+ /** Whether the flow is complete */
22
+ complete: boolean;
23
+ /** Optional metadata */
24
+ metadata?: Record<string, unknown>;
25
+ }
26
+
27
+ /**
28
+ * A step in a flow.
29
+ */
30
+ export interface FlowStep<E extends PraxisEvent = PraxisEvent> {
31
+ /** Step identifier */
32
+ id: string;
33
+ /** Expected event type for this step */
34
+ expectedEventType: string;
35
+ /** Optional validation function */
36
+ validate?: (event: E) => boolean;
37
+ /** Optional timeout in milliseconds */
38
+ timeout?: number;
39
+ }
40
+
41
+ /**
42
+ * An actor maintains its own state and responds to events.
43
+ */
44
+ export interface Actor<
45
+ S extends PraxisState = PraxisState,
46
+ E extends PraxisEvent = PraxisEvent
47
+ > {
48
+ /** Unique identifier for the actor */
49
+ id: string;
50
+ /** Current state of the actor */
51
+ state: S;
52
+ /** Step function for processing events */
53
+ step: StepFunction<S, E>;
54
+ /** Optional metadata */
55
+ metadata?: {
56
+ type?: string;
57
+ created?: number;
58
+ [key: string]: unknown;
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Create a new flow.
64
+ */
65
+ export function createFlow<E extends PraxisEvent = PraxisEvent>(
66
+ id: string,
67
+ steps: FlowStep<E>[],
68
+ description?: string
69
+ ): Flow<E> {
70
+ return {
71
+ id,
72
+ description,
73
+ steps,
74
+ currentStep: 0,
75
+ complete: false,
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Advance a flow with an event.
81
+ * Returns an updated flow and whether the flow accepted the event.
82
+ */
83
+ export function advanceFlow<E extends PraxisEvent = PraxisEvent>(
84
+ flow: Flow<E>,
85
+ event: E
86
+ ): { flow: Flow<E>; accepted: boolean } {
87
+ if (flow.complete) {
88
+ return { flow, accepted: false };
89
+ }
90
+
91
+ const currentStep = flow.steps[flow.currentStep];
92
+ if (!currentStep) {
93
+ return { flow, accepted: false };
94
+ }
95
+
96
+ // Check if event matches expected type
97
+ if (currentStep.expectedEventType !== event.type) {
98
+ return { flow, accepted: false };
99
+ }
100
+
101
+ // Validate event if validator is provided
102
+ if (currentStep.validate && !currentStep.validate(event)) {
103
+ return { flow, accepted: false };
104
+ }
105
+
106
+ // Advance to next step
107
+ const nextStep = flow.currentStep + 1;
108
+ const complete = nextStep >= flow.steps.length;
109
+
110
+ const updatedFlow: Flow<E> = {
111
+ ...flow,
112
+ currentStep: nextStep,
113
+ complete,
114
+ };
115
+
116
+ return { flow: updatedFlow, accepted: true };
117
+ }
118
+
119
+ /**
120
+ * Check if a flow is waiting for a specific event type.
121
+ */
122
+ export function isFlowWaitingFor<E extends PraxisEvent = PraxisEvent>(
123
+ flow: Flow<E>,
124
+ eventType: string
125
+ ): boolean {
126
+ if (flow.complete) {
127
+ return false;
128
+ }
129
+ const currentStep = flow.steps[flow.currentStep];
130
+ return currentStep?.expectedEventType === eventType;
131
+ }
132
+
133
+ /**
134
+ * Create a new actor.
135
+ */
136
+ export function createActor<
137
+ S extends PraxisState = PraxisState,
138
+ E extends PraxisEvent = PraxisEvent
139
+ >(
140
+ id: string,
141
+ initialState: S,
142
+ stepFunction: StepFunction<S, E>,
143
+ type?: string
144
+ ): Actor<S, E> {
145
+ return {
146
+ id,
147
+ state: initialState,
148
+ step: stepFunction,
149
+ metadata: {
150
+ type,
151
+ created: Date.now(),
152
+ },
153
+ };
154
+ }
155
+
156
+ /**
157
+ * Process an event through an actor.
158
+ * Returns the updated actor and any effects.
159
+ */
160
+ export function processActorEvent<
161
+ S extends PraxisState = PraxisState,
162
+ E extends PraxisEvent = PraxisEvent
163
+ >(actor: Actor<S, E>, event: E): { actor: Actor<S, E>; result: StepResult<S> } {
164
+ const result = actor.step(actor.state, event);
165
+
166
+ const updatedActor: Actor<S, E> = {
167
+ ...actor,
168
+ state: result.state,
169
+ };
170
+
171
+ return { actor: updatedActor, result };
172
+ }
173
+
174
+ /**
175
+ * Actor system for managing multiple actors.
176
+ */
177
+ export class ActorSystem<
178
+ S extends PraxisState = PraxisState,
179
+ E extends PraxisEvent = PraxisEvent
180
+ > {
181
+ private actors: Map<string, Actor<S, E>> = new Map();
182
+
183
+ /**
184
+ * Register an actor in the system.
185
+ */
186
+ register(actor: Actor<S, E>): void {
187
+ if (this.actors.has(actor.id)) {
188
+ throw new Error(`Actor with id '${actor.id}' already exists`);
189
+ }
190
+ this.actors.set(actor.id, actor);
191
+ }
192
+
193
+ /**
194
+ * Unregister an actor from the system.
195
+ */
196
+ unregister(id: string): boolean {
197
+ return this.actors.delete(id);
198
+ }
199
+
200
+ /**
201
+ * Get an actor by ID.
202
+ */
203
+ get(id: string): Actor<S, E> | undefined {
204
+ return this.actors.get(id);
205
+ }
206
+
207
+ /**
208
+ * Get all actors.
209
+ */
210
+ getAll(): Actor<S, E>[] {
211
+ return Array.from(this.actors.values());
212
+ }
213
+
214
+ /**
215
+ * Send an event to a specific actor.
216
+ */
217
+ send(actorId: string, event: E): StepResult<S> | undefined {
218
+ const actor = this.actors.get(actorId);
219
+ if (!actor) {
220
+ return undefined;
221
+ }
222
+
223
+ const { actor: updatedActor, result } = processActorEvent(actor, event);
224
+ this.actors.set(actorId, updatedActor);
225
+
226
+ return result;
227
+ }
228
+
229
+ /**
230
+ * Broadcast an event to all actors.
231
+ * Returns a map of actor IDs to their results.
232
+ */
233
+ broadcast(event: E): Map<string, StepResult<S>> {
234
+ const results = new Map<string, StepResult<S>>();
235
+
236
+ for (const [id, actor] of this.actors) {
237
+ const { actor: updatedActor, result } = processActorEvent(actor, event);
238
+ this.actors.set(id, updatedActor);
239
+ results.set(id, result);
240
+ }
241
+
242
+ return results;
243
+ }
244
+
245
+ /**
246
+ * Clear all actors from the system.
247
+ */
248
+ clear(): void {
249
+ this.actors.clear();
250
+ }
251
+
252
+ /**
253
+ * Get the number of actors in the system.
254
+ */
255
+ size(): number {
256
+ return this.actors.size;
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Create a new actor system.
262
+ */
263
+ export function createActorSystem<
264
+ S extends PraxisState = PraxisState,
265
+ E extends PraxisEvent = PraxisEvent
266
+ >(): ActorSystem<S, E> {
267
+ return new ActorSystem<S, E>();
268
+ }
package/src/index.ts ADDED
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Praxis - Practical, Provable Application Logic
3
+ *
4
+ * A typed, functional application logic engine built on strong types.
5
+ *
6
+ * Core concepts:
7
+ * - Facts: typed propositions about the domain
8
+ * - Events: temporally ordered facts meant to drive change
9
+ * - Rules: pure functions that derive new facts from context + events
10
+ * - Constraints: invariants that must always hold
11
+ * - Flows: orchestrated behaviors
12
+ * - Actors: effectful units that perform side effects
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { createPraxisEngine, PraxisRegistry, defineFact, defineEvent, defineRule } from "@plures/praxis";
17
+ *
18
+ * // Define facts and events
19
+ * const UserLoggedIn = defineFact<"UserLoggedIn", { userId: string }>("UserLoggedIn");
20
+ * const Login = defineEvent<"LOGIN", { username: string }>("LOGIN");
21
+ *
22
+ * // Define rules
23
+ * const loginRule = defineRule({
24
+ * id: "auth.login",
25
+ * description: "Process login event",
26
+ * impl: (state, events) => {
27
+ * const loginEvent = events.find(Login.is);
28
+ * if (loginEvent) {
29
+ * return [UserLoggedIn.create({ userId: loginEvent.payload.username })];
30
+ * }
31
+ * return [];
32
+ * }
33
+ * });
34
+ *
35
+ * // Create engine
36
+ * const registry = new PraxisRegistry();
37
+ * registry.registerRule(loginRule);
38
+ *
39
+ * const engine = createPraxisEngine({
40
+ * initialContext: {},
41
+ * registry
42
+ * });
43
+ *
44
+ * // Dispatch events
45
+ * const result = engine.step([Login.create({ username: "alice" })]);
46
+ * console.log(result.state.facts); // [{ tag: "UserLoggedIn", payload: { userId: "alice" } }]
47
+ * ```
48
+ */
49
+
50
+ // Core protocol (language-neutral types)
51
+ export type {
52
+ PraxisFact,
53
+ PraxisEvent,
54
+ PraxisState,
55
+ PraxisDiagnostics,
56
+ PraxisStepConfig,
57
+ PraxisStepResult,
58
+ PraxisStepFn,
59
+ } from "./core/protocol.js";
60
+ export { PRAXIS_PROTOCOL_VERSION } from "./core/protocol.js";
61
+
62
+ // Rules and constraints
63
+ export type {
64
+ RuleId,
65
+ ConstraintId,
66
+ RuleFn,
67
+ ConstraintFn,
68
+ RuleDescriptor,
69
+ ConstraintDescriptor,
70
+ PraxisModule,
71
+ } from "./core/rules.js";
72
+ export { PraxisRegistry } from "./core/rules.js";
73
+
74
+ // Engine
75
+ export type { PraxisEngineOptions } from "./core/engine.js";
76
+ export { LogicEngine, createPraxisEngine } from "./core/engine.js";
77
+
78
+ // Actors
79
+ export type { Actor } from "./core/actors.js";
80
+ export { ActorManager, createTimerActor } from "./core/actors.js";
81
+
82
+ // Introspection
83
+ export type {
84
+ RuleNode,
85
+ ConstraintNode,
86
+ GraphEdge,
87
+ RegistryGraph,
88
+ RuleSchema,
89
+ ConstraintSchema,
90
+ RegistrySchema,
91
+ RegistryStats,
92
+ } from "./core/introspection.js";
93
+ export { RegistryIntrospector, createIntrospector } from "./core/introspection.js";
94
+
95
+ // DSL helpers
96
+ export {
97
+ defineFact,
98
+ defineEvent,
99
+ defineRule,
100
+ defineConstraint,
101
+ defineModule,
102
+ filterEvents,
103
+ filterFacts,
104
+ findEvent,
105
+ findFact,
106
+ } from "./dsl/index.js";
107
+ export type {
108
+ FactDefinition,
109
+ EventDefinition,
110
+ DefineRuleOptions,
111
+ DefineConstraintOptions,
112
+ DefineModuleOptions,
113
+ } from "./dsl/index.js";
114
+
115
+ // Terminal Node Runtime
116
+ export type {
117
+ TerminalExecutionResult,
118
+ TerminalNodeState,
119
+ TerminalAdapterOptions,
120
+ } from "./runtime/terminal-adapter.js";
121
+ export {
122
+ TerminalAdapter,
123
+ createTerminalAdapter,
124
+ runTerminalCommand,
125
+ } from "./runtime/terminal-adapter.js";
126
+
127
+ // Schema Types (including Terminal Node types)
128
+ export type {
129
+ PraxisSchema,
130
+ NodeDefinition,
131
+ NodeBindings,
132
+ TerminalNodeProps,
133
+ OrchestrationDefinition,
134
+ ValidationResult,
135
+ ValidationError,
136
+ ModelDefinition,
137
+ ComponentDefinition,
138
+ LogicDefinition,
139
+ } from "./core/schema/types.js";
140
+ export { validateSchema, createSchemaTemplate } from "./core/schema/types.js";
141
+
142
+ // Schema Loader (supports JSON, YAML, and TS)
143
+ export type {
144
+ LoaderOptions,
145
+ LoaderResult,
146
+ } from "./core/schema/loader.js";
147
+ export {
148
+ loadSchema,
149
+ loadSchemaFromJson,
150
+ loadSchemaFromYaml,
151
+ loadSchemaFromFile,
152
+ validateForGeneration,
153
+ } from "./core/schema/loader.js";
154
+
@@ -0,0 +1,93 @@
1
+ /**
2
+ * PluresDB Integration (Placeholder)
3
+ *
4
+ * Future integration with pluresdb - reactive graph datastore and event source/sink.
5
+ * This module will provide adapters for:
6
+ * - Storing Praxis state in pluresdb
7
+ * - Sourcing events from pluresdb
8
+ * - Sinking events to pluresdb
9
+ * - Reactive queries and subscriptions
10
+ */
11
+
12
+ import type { LogicEngine } from "../core/engine.js";
13
+ import type { PraxisEvent, PraxisFact } from "../core/protocol.js";
14
+
15
+ /**
16
+ * Placeholder for pluresdb adapter
17
+ *
18
+ * Future implementation will provide:
19
+ * - Event sourcing (persist events to pluresdb)
20
+ * - State snapshots (persist state to pluresdb)
21
+ * - Event replay (rebuild state from events)
22
+ * - Reactive queries (subscribe to state changes)
23
+ */
24
+ export interface PluresDBAdapter<TContext = unknown> {
25
+ /**
26
+ * Persist events to pluresdb
27
+ */
28
+ persistEvents(events: PraxisEvent[]): Promise<void>;
29
+
30
+ /**
31
+ * Persist facts to pluresdb
32
+ */
33
+ persistFacts(facts: PraxisFact[]): Promise<void>;
34
+
35
+ /**
36
+ * Load events from pluresdb
37
+ */
38
+ loadEvents(query?: unknown): Promise<PraxisEvent[]>;
39
+
40
+ /**
41
+ * Subscribe to new events from pluresdb
42
+ */
43
+ subscribeToEvents(
44
+ callback: (events: PraxisEvent[]) => void,
45
+ query?: unknown
46
+ ): () => void;
47
+
48
+ /**
49
+ * Attach the adapter to an engine
50
+ */
51
+ attachEngine(engine: LogicEngine<TContext>): void;
52
+ }
53
+
54
+ /**
55
+ * Create a pluresdb adapter (placeholder implementation)
56
+ *
57
+ * @example
58
+ * // Future usage:
59
+ * const adapter = createPluresDBAdapter({
60
+ * connection: pluresdbClient,
61
+ * collection: "myapp-events"
62
+ * });
63
+ * adapter.attachEngine(engine);
64
+ */
65
+ export function createPluresDBAdapter<TContext = unknown>(
66
+ _options: unknown
67
+ ): PluresDBAdapter<TContext> {
68
+ return {
69
+ async persistEvents(_events: PraxisEvent[]): Promise<void> {
70
+ // TODO: Implement pluresdb event persistence
71
+ throw new Error("PluresDB integration not yet implemented");
72
+ },
73
+ async persistFacts(_facts: PraxisFact[]): Promise<void> {
74
+ // TODO: Implement pluresdb fact persistence
75
+ throw new Error("PluresDB integration not yet implemented");
76
+ },
77
+ async loadEvents(_query?: unknown): Promise<PraxisEvent[]> {
78
+ // TODO: Implement pluresdb event loading
79
+ throw new Error("PluresDB integration not yet implemented");
80
+ },
81
+ subscribeToEvents(
82
+ _callback: (events: PraxisEvent[]) => void,
83
+ _query?: unknown
84
+ ): () => void {
85
+ // TODO: Implement pluresdb event subscription
86
+ throw new Error("PluresDB integration not yet implemented");
87
+ },
88
+ attachEngine(_engine: LogicEngine<TContext>): void {
89
+ // TODO: Implement engine attachment
90
+ throw new Error("PluresDB integration not yet implemented");
91
+ },
92
+ };
93
+ }