@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.
- package/FRAMEWORK.md +420 -0
- package/LICENSE +21 -0
- package/README.md +1310 -0
- package/dist/adapters/cli.d.ts +43 -0
- package/dist/adapters/cli.d.ts.map +1 -0
- package/dist/adapters/cli.js +126 -0
- package/dist/adapters/cli.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +26 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +233 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/cloud.d.ts +27 -0
- package/dist/cli/commands/cloud.d.ts.map +1 -0
- package/dist/cli/commands/cloud.js +232 -0
- package/dist/cli/commands/cloud.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +25 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +168 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +179 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cloud/auth.d.ts +51 -0
- package/dist/cloud/auth.d.ts.map +1 -0
- package/dist/cloud/auth.js +194 -0
- package/dist/cloud/auth.js.map +1 -0
- package/dist/cloud/billing.d.ts +184 -0
- package/dist/cloud/billing.d.ts.map +1 -0
- package/dist/cloud/billing.js +179 -0
- package/dist/cloud/billing.js.map +1 -0
- package/dist/cloud/client.d.ts +39 -0
- package/dist/cloud/client.d.ts.map +1 -0
- package/dist/cloud/client.js +176 -0
- package/dist/cloud/client.js.map +1 -0
- package/dist/cloud/index.d.ts +44 -0
- package/dist/cloud/index.d.ts.map +1 -0
- package/dist/cloud/index.js +44 -0
- package/dist/cloud/index.js.map +1 -0
- package/dist/cloud/marketplace.d.ts +166 -0
- package/dist/cloud/marketplace.d.ts.map +1 -0
- package/dist/cloud/marketplace.js +159 -0
- package/dist/cloud/marketplace.js.map +1 -0
- package/dist/cloud/provisioning.d.ts +110 -0
- package/dist/cloud/provisioning.d.ts.map +1 -0
- package/dist/cloud/provisioning.js +148 -0
- package/dist/cloud/provisioning.js.map +1 -0
- package/dist/cloud/relay/endpoints.d.ts +62 -0
- package/dist/cloud/relay/endpoints.d.ts.map +1 -0
- package/dist/cloud/relay/endpoints.js +217 -0
- package/dist/cloud/relay/endpoints.js.map +1 -0
- package/dist/cloud/relay/health/index.d.ts +5 -0
- package/dist/cloud/relay/health/index.d.ts.map +1 -0
- package/dist/cloud/relay/health/index.js +9 -0
- package/dist/cloud/relay/health/index.js.map +1 -0
- package/dist/cloud/relay/stats/index.d.ts +5 -0
- package/dist/cloud/relay/stats/index.d.ts.map +1 -0
- package/dist/cloud/relay/stats/index.js +9 -0
- package/dist/cloud/relay/stats/index.js.map +1 -0
- package/dist/cloud/relay/sync/index.d.ts +5 -0
- package/dist/cloud/relay/sync/index.d.ts.map +1 -0
- package/dist/cloud/relay/sync/index.js +9 -0
- package/dist/cloud/relay/sync/index.js.map +1 -0
- package/dist/cloud/relay/usage/index.d.ts +5 -0
- package/dist/cloud/relay/usage/index.d.ts.map +1 -0
- package/dist/cloud/relay/usage/index.js +9 -0
- package/dist/cloud/relay/usage/index.js.map +1 -0
- package/dist/cloud/sponsors.d.ts +81 -0
- package/dist/cloud/sponsors.d.ts.map +1 -0
- package/dist/cloud/sponsors.js +130 -0
- package/dist/cloud/sponsors.js.map +1 -0
- package/dist/cloud/types.d.ts +169 -0
- package/dist/cloud/types.d.ts.map +1 -0
- package/dist/cloud/types.js +7 -0
- package/dist/cloud/types.js.map +1 -0
- package/dist/components/index.d.ts +43 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +17 -0
- package/dist/components/index.js.map +1 -0
- package/dist/core/actors.d.ts +95 -0
- package/dist/core/actors.d.ts.map +1 -0
- package/dist/core/actors.js +158 -0
- package/dist/core/actors.js.map +1 -0
- package/dist/core/component/generator.d.ts +122 -0
- package/dist/core/component/generator.d.ts.map +1 -0
- package/dist/core/component/generator.js +307 -0
- package/dist/core/component/generator.js.map +1 -0
- package/dist/core/engine.d.ts +92 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +199 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/introspection.d.ts +141 -0
- package/dist/core/introspection.d.ts.map +1 -0
- package/dist/core/introspection.js +208 -0
- package/dist/core/introspection.js.map +1 -0
- package/dist/core/logic/generator.d.ts +76 -0
- package/dist/core/logic/generator.d.ts.map +1 -0
- package/dist/core/logic/generator.js +339 -0
- package/dist/core/logic/generator.js.map +1 -0
- package/dist/core/pluresdb/generator.d.ts +58 -0
- package/dist/core/pluresdb/generator.d.ts.map +1 -0
- package/dist/core/pluresdb/generator.js +162 -0
- package/dist/core/pluresdb/generator.js.map +1 -0
- package/dist/core/protocol.d.ts +121 -0
- package/dist/core/protocol.d.ts.map +1 -0
- package/dist/core/protocol.js +46 -0
- package/dist/core/protocol.js.map +1 -0
- package/dist/core/rules.d.ts +120 -0
- package/dist/core/rules.d.ts.map +1 -0
- package/dist/core/rules.js +81 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/schema/loader.d.ts +47 -0
- package/dist/core/schema/loader.d.ts.map +1 -0
- package/dist/core/schema/loader.js +189 -0
- package/dist/core/schema/loader.js.map +1 -0
- package/dist/core/schema/normalize.d.ts +72 -0
- package/dist/core/schema/normalize.d.ts.map +1 -0
- package/dist/core/schema/normalize.js +190 -0
- package/dist/core/schema/normalize.js.map +1 -0
- package/dist/core/schema/types.d.ts +370 -0
- package/dist/core/schema/types.d.ts.map +1 -0
- package/dist/core/schema/types.js +161 -0
- package/dist/core/schema/types.js.map +1 -0
- package/dist/dsl/index.d.ts +152 -0
- package/dist/dsl/index.d.ts.map +1 -0
- package/dist/dsl/index.js +132 -0
- package/dist/dsl/index.js.map +1 -0
- package/dist/dsl.d.ts +124 -0
- package/dist/dsl.d.ts.map +1 -0
- package/dist/dsl.js +130 -0
- package/dist/dsl.js.map +1 -0
- package/dist/examples/advanced-todo/index.d.ts +55 -0
- package/dist/examples/advanced-todo/index.d.ts.map +1 -0
- package/dist/examples/advanced-todo/index.js +222 -0
- package/dist/examples/advanced-todo/index.js.map +1 -0
- package/dist/examples/auth-basic/index.d.ts +17 -0
- package/dist/examples/auth-basic/index.d.ts.map +1 -0
- package/dist/examples/auth-basic/index.js +122 -0
- package/dist/examples/auth-basic/index.js.map +1 -0
- package/dist/examples/cart/index.d.ts +19 -0
- package/dist/examples/cart/index.d.ts.map +1 -0
- package/dist/examples/cart/index.js +202 -0
- package/dist/examples/cart/index.js.map +1 -0
- package/dist/examples/hero-ecommerce/index.d.ts +39 -0
- package/dist/examples/hero-ecommerce/index.d.ts.map +1 -0
- package/dist/examples/hero-ecommerce/index.js +506 -0
- package/dist/examples/hero-ecommerce/index.js.map +1 -0
- package/dist/examples/svelte-counter/index.d.ts +31 -0
- package/dist/examples/svelte-counter/index.d.ts.map +1 -0
- package/dist/examples/svelte-counter/index.js +123 -0
- package/dist/examples/svelte-counter/index.js.map +1 -0
- package/dist/flows.d.ts +125 -0
- package/dist/flows.d.ts.map +1 -0
- package/dist/flows.js +160 -0
- package/dist/flows.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/pluresdb.d.ts +56 -0
- package/dist/integrations/pluresdb.d.ts.map +1 -0
- package/dist/integrations/pluresdb.js +46 -0
- package/dist/integrations/pluresdb.js.map +1 -0
- package/dist/integrations/svelte.d.ts +306 -0
- package/dist/integrations/svelte.d.ts.map +1 -0
- package/dist/integrations/svelte.js +447 -0
- package/dist/integrations/svelte.js.map +1 -0
- package/dist/registry.d.ts +94 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +181 -0
- package/dist/registry.js.map +1 -0
- package/dist/runtime/terminal-adapter.d.ts +105 -0
- package/dist/runtime/terminal-adapter.d.ts.map +1 -0
- package/dist/runtime/terminal-adapter.js +113 -0
- package/dist/runtime/terminal-adapter.js.map +1 -0
- package/dist/step.d.ts +34 -0
- package/dist/step.d.ts.map +1 -0
- package/dist/step.js +111 -0
- package/dist/step.js.map +1 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/docs/MONETIZATION.md +394 -0
- package/docs/TERMINAL_NODE.md +588 -0
- package/docs/guides/canvas.md +389 -0
- package/docs/guides/getting-started.md +347 -0
- package/docs/guides/history-state-pattern.md +618 -0
- package/docs/guides/orchestration.md +617 -0
- package/docs/guides/parallel-state-pattern.md +767 -0
- package/docs/guides/svelte-integration.md +691 -0
- package/package.json +96 -0
- package/src/__tests__/actors.test.ts +270 -0
- package/src/__tests__/billing.test.ts +175 -0
- package/src/__tests__/cloud.test.ts +247 -0
- package/src/__tests__/dsl.test.ts +154 -0
- package/src/__tests__/edge-cases.test.ts +475 -0
- package/src/__tests__/engine.test.ts +137 -0
- package/src/__tests__/generators.test.ts +270 -0
- package/src/__tests__/introspection.test.ts +321 -0
- package/src/__tests__/protocol.test.ts +40 -0
- package/src/__tests__/provisioning.test.ts +162 -0
- package/src/__tests__/schema.test.ts +241 -0
- package/src/__tests__/svelte-integration.test.ts +431 -0
- package/src/__tests__/terminal-node.test.ts +352 -0
- package/src/adapters/cli.ts +175 -0
- package/src/cli/commands/auth.ts +271 -0
- package/src/cli/commands/cloud.ts +281 -0
- package/src/cli/commands/generate.ts +225 -0
- package/src/cli/index.ts +190 -0
- package/src/cloud/README.md +383 -0
- package/src/cloud/auth.ts +245 -0
- package/src/cloud/billing.ts +336 -0
- package/src/cloud/client.ts +221 -0
- package/src/cloud/index.ts +121 -0
- package/src/cloud/marketplace.ts +303 -0
- package/src/cloud/provisioning.ts +254 -0
- package/src/cloud/relay/endpoints.ts +307 -0
- package/src/cloud/relay/health/function.json +17 -0
- package/src/cloud/relay/health/index.ts +10 -0
- package/src/cloud/relay/host.json +15 -0
- package/src/cloud/relay/local.settings.json +8 -0
- package/src/cloud/relay/stats/function.json +17 -0
- package/src/cloud/relay/stats/index.ts +10 -0
- package/src/cloud/relay/sync/function.json +17 -0
- package/src/cloud/relay/sync/index.ts +10 -0
- package/src/cloud/relay/usage/function.json +17 -0
- package/src/cloud/relay/usage/index.ts +10 -0
- package/src/cloud/sponsors.ts +213 -0
- package/src/cloud/types.ts +198 -0
- package/src/components/README.md +125 -0
- package/src/components/TerminalNode.svelte +457 -0
- package/src/components/index.ts +46 -0
- package/src/core/actors.ts +205 -0
- package/src/core/component/generator.ts +432 -0
- package/src/core/engine.ts +243 -0
- package/src/core/introspection.ts +329 -0
- package/src/core/logic/generator.ts +420 -0
- package/src/core/pluresdb/generator.ts +229 -0
- package/src/core/protocol.ts +132 -0
- package/src/core/rules.ts +167 -0
- package/src/core/schema/loader.ts +247 -0
- package/src/core/schema/normalize.ts +322 -0
- package/src/core/schema/types.ts +557 -0
- package/src/dsl/index.ts +218 -0
- package/src/dsl.ts +214 -0
- package/src/examples/advanced-todo/App.svelte +506 -0
- package/src/examples/advanced-todo/README.md +371 -0
- package/src/examples/advanced-todo/index.ts +309 -0
- package/src/examples/auth-basic/index.ts +163 -0
- package/src/examples/cart/index.ts +259 -0
- package/src/examples/hero-ecommerce/index.ts +657 -0
- package/src/examples/svelte-counter/index.ts +168 -0
- package/src/flows.ts +268 -0
- package/src/index.ts +154 -0
- package/src/integrations/pluresdb.ts +93 -0
- package/src/integrations/svelte.ts +617 -0
- package/src/registry.ts +223 -0
- package/src/runtime/terminal-adapter.ts +175 -0
- package/src/step.ts +151 -0
- package/src/types.ts +70 -0
- package/templates/basic-app/README.md +147 -0
- package/templates/fullstack-app/README.md +279 -0
package/README.md
ADDED
|
@@ -0,0 +1,1310 @@
|
|
|
1
|
+
# Praxis
|
|
2
|
+
|
|
3
|
+
[](https://github.com/plures/praxis/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/plures/praxis/actions/workflows/codeql.yml)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.npmjs.com/package/@plures/praxis)
|
|
7
|
+
[](https://jsr.io/@plures/praxis)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
[](https://deno.land/)
|
|
10
|
+
|
|
11
|
+
**The Full Plures Application Framework**
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 📊 Project Dashboard
|
|
16
|
+
|
|
17
|
+
### Quick Links
|
|
18
|
+
- 📖 [Documentation](./docs/) | [Getting Started](./GETTING_STARTED.md) | [Framework Guide](./FRAMEWORK.md)
|
|
19
|
+
- 💬 [Discussions](https://github.com/plures/praxis/discussions) | [Issues](https://github.com/plures/praxis/issues)
|
|
20
|
+
- 🚀 [Contributing](./CONTRIBUTING.md) | [Security Policy](./SECURITY.md)
|
|
21
|
+
- 📋 [Changelog](./CHANGELOG.md) | [Roadmap](https://github.com/plures/praxis/issues?q=is%3Aissue+is%3Aopen+label%3Aroadmap)
|
|
22
|
+
|
|
23
|
+
### Project Status
|
|
24
|
+
|
|
25
|
+
| Category | Status |
|
|
26
|
+
|----------|--------|
|
|
27
|
+
| **CI/CD** | ✅ Automated testing & builds |
|
|
28
|
+
| **Version** | 0.1.0 (Alpha) |
|
|
29
|
+
| **Runtime Support** | Node.js 18+, Deno (experimental) |
|
|
30
|
+
| **Package Registries** | npm ✅ / JSR 🚧 (coming soon) |
|
|
31
|
+
| **Test Coverage** | 165 tests passing |
|
|
32
|
+
| **Documentation** | 📚 Comprehensive guides available |
|
|
33
|
+
|
|
34
|
+
### Integration Status
|
|
35
|
+
|
|
36
|
+
| Integration | Status | Notes |
|
|
37
|
+
|------------|--------|-------|
|
|
38
|
+
| **Praxis Cloud** | ✅ Available | Azure-hosted relay for sync & monetization |
|
|
39
|
+
| **PluresDB** | 🚧 In Development | Local-first reactive datastore |
|
|
40
|
+
| **Unum** | 🚧 Planned | Identity & channels |
|
|
41
|
+
| **Svelte 5** | ✅ Full Support | Runes API, stores, history, time-travel |
|
|
42
|
+
| **Tauri** | 🚧 Planned | Cross-platform runtime |
|
|
43
|
+
| **CodeCanvas** | 🚧 Planned | Visual schema editor |
|
|
44
|
+
| **State-Docs** | 🚧 Planned | Documentation generation |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Overview
|
|
49
|
+
|
|
50
|
+
Praxis is not just a logic engine—it's a **complete framework** for building modern, local-first, distributed applications. It provides:
|
|
51
|
+
|
|
52
|
+
- **Declarative Schemas**: Define your data models, logic, and components in a unified schema format
|
|
53
|
+
- **Logic/State Machines**: Pure, functional application logic with facts, events, rules, and constraints
|
|
54
|
+
- **Component Generation**: Automatically generate Svelte components from schemas
|
|
55
|
+
- **Local-First Data**: Integrated PluresDB for reactive, offline-capable data storage
|
|
56
|
+
- **Documentation Generation**: Automatic State-Docs generation from your schemas
|
|
57
|
+
- **Visual Design**: CodeCanvas integration for visual schema and logic editing
|
|
58
|
+
- **Orchestration**: DSC/MCP support for distributed system coordination
|
|
59
|
+
- **Cross-Platform Runtime**: Web, desktop, and mobile via Svelte + Tauri
|
|
60
|
+
|
|
61
|
+
### Framework Philosophy
|
|
62
|
+
|
|
63
|
+
### Core Framework Components
|
|
64
|
+
|
|
65
|
+
Praxis provides these integrated capabilities:
|
|
66
|
+
|
|
67
|
+
- **Schema System** – Declarative definitions that generate models, components, and documentation
|
|
68
|
+
- **Logic Engine** – Typed facts, events, rules, and constraints for application logic
|
|
69
|
+
- **Component Factory** – Generate Svelte components from schemas with data bindings
|
|
70
|
+
- **Data Layer** – PluresDB integration for reactive, local-first data storage
|
|
71
|
+
- **State Machines** – Flows and scenarios for orchestrated behaviors
|
|
72
|
+
- **Actors** – Effectful units for side effects and external system integration
|
|
73
|
+
- **Terminal Nodes** – Execute commands and scripts within the Praxis framework (NEW!)
|
|
74
|
+
- **Documentation** – Automatic State-Docs generation from schemas and logic
|
|
75
|
+
- **Visual IDE** – CodeCanvas integration for schema and logic editing
|
|
76
|
+
- **Orchestration** – DSC/MCP support for distributed coordination
|
|
77
|
+
- **CLI Tools** – Command-line interface for scaffolding and generation
|
|
78
|
+
|
|
79
|
+
### Design Philosophy
|
|
80
|
+
|
|
81
|
+
1. **Schema-Driven Development**
|
|
82
|
+
- Define once, generate everywhere (models, components, docs, orchestration)
|
|
83
|
+
- Single source of truth for your application structure
|
|
84
|
+
- Type-safe by default across all layers
|
|
85
|
+
|
|
86
|
+
2. **Local-First Architecture**
|
|
87
|
+
- Offline-capable by default with PluresDB
|
|
88
|
+
- Sync when connected, work always
|
|
89
|
+
- Data ownership and privacy built-in
|
|
90
|
+
|
|
91
|
+
3. **Strong typing and functional programming**
|
|
92
|
+
- Core abstractions are strongly typed: `Fact<Tag, Payload>`, `Event<Tag, Payload>`, `Rule<Context, InFact, OutFact>`
|
|
93
|
+
- Pure functions for testability and reasoning
|
|
94
|
+
- Immutable state updates
|
|
95
|
+
|
|
96
|
+
4. **Visual and Code Workflows**
|
|
97
|
+
- CodeCanvas for visual schema and logic editing
|
|
98
|
+
- Full code-level control when needed
|
|
99
|
+
- Seamless transitions between visual and code
|
|
100
|
+
|
|
101
|
+
5. **Cross-Platform and Cross-Language**
|
|
102
|
+
- TypeScript-first with C# and PowerShell support
|
|
103
|
+
- Web, desktop, mobile via Svelte + Tauri
|
|
104
|
+
- Language-agnostic core protocol for maximum portability
|
|
105
|
+
|
|
106
|
+
## Framework Features
|
|
107
|
+
|
|
108
|
+
### 🏗️ Full Application Framework
|
|
109
|
+
- **Schema-Driven**: Define data models, logic, and UI in unified schemas
|
|
110
|
+
- **Component Generation**: Auto-generate Svelte components from schemas
|
|
111
|
+
- **CLI Tools**: `praxis create`, `praxis generate`, `praxis canvas` commands
|
|
112
|
+
- **Templates**: Pre-built app templates (basic, fullstack, distributed)
|
|
113
|
+
- **Integrated Stack**: PluresDB + Unum + ADP + State-Docs + Canvas
|
|
114
|
+
|
|
115
|
+
### 🎨 Visual Development
|
|
116
|
+
- **CodeCanvas Integration**: Visual schema and logic editor
|
|
117
|
+
- **Component Preview**: See generated components in real-time
|
|
118
|
+
- **Flow Visualization**: Visualize state machines and orchestration
|
|
119
|
+
- **Interactive Docs**: Navigate documentation with State-Docs
|
|
120
|
+
|
|
121
|
+
### 🔌 Ecosystem Integration
|
|
122
|
+
- **PluresDB**: Local-first reactive data storage
|
|
123
|
+
- **Unum**: Identity and channels for distributed systems
|
|
124
|
+
- **ADP**: Architectural guardrails and decision tracking
|
|
125
|
+
- **State-Docs**: Living documentation generation
|
|
126
|
+
- **Svelte 5**: Full runes support with history and time-travel
|
|
127
|
+
- **Tauri**: Cross-platform runtime (web/desktop/mobile)
|
|
128
|
+
|
|
129
|
+
### ⚡ Svelte 5 Integration (NEW!)
|
|
130
|
+
- **Runes API**: Modern `$state`, `$derived`, `$effect` support
|
|
131
|
+
- **History States**: Built-in undo/redo and time-travel debugging
|
|
132
|
+
- **Store API**: Backward-compatible stores for Svelte 4/5
|
|
133
|
+
- **Type Safety**: Full TypeScript support with composables
|
|
134
|
+
- **Zero Config**: Works out of the box with Svelte 5
|
|
135
|
+
|
|
136
|
+
## Logic Engine Features
|
|
137
|
+
|
|
138
|
+
- 🎯 **Logic-First Design**: Build applications around facts, events, rules, and constraints
|
|
139
|
+
- 🔄 **Pure Functional Core**: State transitions via pure `step` functions
|
|
140
|
+
- 📝 **Fluent DSL**: Intuitive API for defining rules and constraints
|
|
141
|
+
- 🗂️ **Registry System**: Centralized management of rules and constraints
|
|
142
|
+
- 🌊 **Flows & Actors**: Orchestrate complex state transitions
|
|
143
|
+
- 📦 **JSON-Friendly**: All types are serializable for cross-platform use
|
|
144
|
+
- 🔒 **Type-Safe**: Full TypeScript support with strict typing
|
|
145
|
+
- 🔍 **Introspection**: Generate schemas, graphs, and visualizations of your logic
|
|
146
|
+
- 🌐 **Cross-Language**: PowerShell adapter with protocol versioning (C# coming soon)
|
|
147
|
+
- 📊 **Comprehensive Testing**: 165+ tests covering all features
|
|
148
|
+
- 🎭 **Hero Example**: Full e-commerce demo with auth, cart, features, and actors
|
|
149
|
+
|
|
150
|
+
## What's New in v0.1.0
|
|
151
|
+
|
|
152
|
+
### 🎉 Major Features
|
|
153
|
+
|
|
154
|
+
#### Svelte 5 Integration (@plures/praxis/svelte)
|
|
155
|
+
- **Runes Composables**: `usePraxisEngine`, `usePraxisContext`, `usePraxisSubscription`
|
|
156
|
+
- **History State Pattern**: `HistoryStateManager`, `createHistoryEngine`
|
|
157
|
+
- **Time-Travel Debugging**: Navigate through state snapshots
|
|
158
|
+
- **Undo/Redo**: Built-in with configurable history size
|
|
159
|
+
- **Store API**: Compatible with Svelte 4 and 5
|
|
160
|
+
- **16 new tests** ensuring rock-solid reliability
|
|
161
|
+
|
|
162
|
+
#### Documentation & Guides
|
|
163
|
+
- **[Svelte Integration Guide](docs/guides/svelte-integration.md)**: Complete guide to Svelte 5 integration
|
|
164
|
+
- **[History State Pattern](docs/guides/history-state-pattern.md)**: Undo/redo and time-travel patterns
|
|
165
|
+
- **[Parallel State Pattern](docs/guides/parallel-state-pattern.md)**: Multiple engine coordination
|
|
166
|
+
- **[Advanced Todo Example](src/examples/advanced-todo/)**: Full-featured demo with history
|
|
167
|
+
|
|
168
|
+
### 🧪 Hardened TypeScript Core
|
|
169
|
+
- **165 comprehensive tests** (up from 63) covering:
|
|
170
|
+
- Svelte integration with runes and stores
|
|
171
|
+
- History state management and navigation
|
|
172
|
+
- Edge cases and failure paths
|
|
173
|
+
- Actor lifecycle and state change notifications
|
|
174
|
+
- Constraint violations and rule errors
|
|
175
|
+
- Registry operations and module composition
|
|
176
|
+
- Full test coverage ensures production-ready reliability
|
|
177
|
+
|
|
178
|
+
### 📖 Protocol Versioning (v1.0.0)
|
|
179
|
+
- **Explicit protocol version** (`protocolVersion` field in state)
|
|
180
|
+
- **Stability guarantees** for cross-language compatibility
|
|
181
|
+
- **Semantic versioning** with migration paths
|
|
182
|
+
- See [PROTOCOL_VERSIONING.md](./PROTOCOL_VERSIONING.md) for details
|
|
183
|
+
|
|
184
|
+
### 🔍 Visualization & Introspection
|
|
185
|
+
- **Registry introspection API** for examining rules and constraints
|
|
186
|
+
- **Graph export** in DOT (Graphviz) and Mermaid formats
|
|
187
|
+
- **JSON schema generation** for documentation and tooling
|
|
188
|
+
- **Search and query** capabilities for rules and constraints
|
|
189
|
+
- **Dependency tracking** and relationship visualization
|
|
190
|
+
|
|
191
|
+
### 💻 PowerShell Adapter
|
|
192
|
+
- **Full PowerShell module** (`Praxis.psm1`) for cross-language usage
|
|
193
|
+
- **CLI boundary** via JSON stdin/stdout
|
|
194
|
+
- **Protocol version checking** ensures compatibility
|
|
195
|
+
- **Complete example** with counter application
|
|
196
|
+
- See [powershell/README.md](./powershell/README.md) for usage
|
|
197
|
+
|
|
198
|
+
### 🎭 Hero Example: E-Commerce Platform
|
|
199
|
+
A comprehensive example demonstrating all Praxis features:
|
|
200
|
+
- **Authentication** with session management and timeouts
|
|
201
|
+
- **Shopping cart** with item management and calculations
|
|
202
|
+
- **Feature flags** for A/B testing (free shipping, loyalty program)
|
|
203
|
+
- **Discount rules** with conditional logic
|
|
204
|
+
- **Loyalty points** and order history
|
|
205
|
+
- **Actors** for logging and analytics
|
|
206
|
+
- **Constraints** enforcing business rules
|
|
207
|
+
- See [src/examples/hero-ecommerce/](./src/examples/hero-ecommerce/) for code
|
|
208
|
+
|
|
209
|
+
## Installation
|
|
210
|
+
|
|
211
|
+
### npm (Node.js)
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npm install @plures/praxis
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### JSR (Deno)
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Coming soon - JSR publishing in progress
|
|
221
|
+
deno add @plures/praxis
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
For now, you can use Praxis with Deno via import maps:
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
// import_map.json
|
|
228
|
+
{
|
|
229
|
+
"imports": {
|
|
230
|
+
"@plures/praxis": "npm:@plures/praxis@^0.1.0"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### From Source
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Clone the repository
|
|
239
|
+
git clone https://github.com/plures/praxis.git
|
|
240
|
+
cd praxis
|
|
241
|
+
|
|
242
|
+
# Install dependencies
|
|
243
|
+
npm install
|
|
244
|
+
|
|
245
|
+
# Build
|
|
246
|
+
npm run build
|
|
247
|
+
|
|
248
|
+
# Run tests
|
|
249
|
+
npm test
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Quick Start
|
|
253
|
+
|
|
254
|
+
### Using the Praxis CLI
|
|
255
|
+
|
|
256
|
+
The Praxis CLI provides commands for creating and managing applications.
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Install Praxis globally
|
|
260
|
+
npm install -g @plures/praxis
|
|
261
|
+
|
|
262
|
+
# Create a new application
|
|
263
|
+
praxis create app my-app
|
|
264
|
+
cd my-app
|
|
265
|
+
npm install
|
|
266
|
+
|
|
267
|
+
# Generate code from schemas
|
|
268
|
+
praxis generate --schema src/schemas/app.schema.ts
|
|
269
|
+
|
|
270
|
+
# Open CodeCanvas for visual editing
|
|
271
|
+
praxis canvas src/schemas/app.schema.ts
|
|
272
|
+
|
|
273
|
+
# Start development server
|
|
274
|
+
npm run dev
|
|
275
|
+
|
|
276
|
+
# Build for production
|
|
277
|
+
npm run build
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Available CLI commands:
|
|
281
|
+
- `praxis login` - Authenticate with GitHub (device flow or token)
|
|
282
|
+
- `praxis logout` - Log out from Praxis Cloud
|
|
283
|
+
- `praxis whoami` - Show current authenticated user
|
|
284
|
+
- `praxis create app [name]` - Create new application
|
|
285
|
+
- `praxis create component [name]` - Create new component
|
|
286
|
+
- `praxis generate` - Generate code from schemas
|
|
287
|
+
- `praxis canvas [schema]` - Open visual editor
|
|
288
|
+
- `praxis orchestrate` - Manage distributed systems
|
|
289
|
+
- `praxis cloud init` - Connect to Praxis Cloud
|
|
290
|
+
- `praxis cloud status` - Check cloud connection
|
|
291
|
+
- `praxis cloud sync` - Manually sync to cloud
|
|
292
|
+
- `praxis cloud usage` - View cloud usage metrics
|
|
293
|
+
- `praxis dev` - Start development server
|
|
294
|
+
- `praxis build` - Build for production
|
|
295
|
+
|
|
296
|
+
See [docs/guides/getting-started.md](./docs/guides/getting-started.md) for detailed instructions.
|
|
297
|
+
|
|
298
|
+
### Praxis Cloud (NEW!)
|
|
299
|
+
|
|
300
|
+
Connect your application to Praxis Cloud for automatic synchronization with GitHub-native authentication and billing:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Authenticate with GitHub
|
|
304
|
+
npx praxis login
|
|
305
|
+
|
|
306
|
+
# Initialize cloud connection
|
|
307
|
+
npx praxis cloud init
|
|
308
|
+
|
|
309
|
+
# In your code
|
|
310
|
+
import { connectRelay } from "@plures/praxis/cloud";
|
|
311
|
+
|
|
312
|
+
const relay = await connectRelay("https://praxis-relay.azurewebsites.net", {
|
|
313
|
+
appId: "my-app",
|
|
314
|
+
authToken: process.env.GITHUB_TOKEN,
|
|
315
|
+
autoSync: true
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Sync automatically handles CRDT merge
|
|
319
|
+
await relay.sync({
|
|
320
|
+
type: "delta",
|
|
321
|
+
appId: "my-app",
|
|
322
|
+
clock: {},
|
|
323
|
+
facts: [...],
|
|
324
|
+
timestamp: Date.now()
|
|
325
|
+
});
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
See [src/cloud/README.md](./src/cloud/README.md) and [examples/cloud-sync](./examples/cloud-sync) for details.
|
|
329
|
+
|
|
330
|
+
### Basic Example (Logic Engine)
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
import {
|
|
334
|
+
createPraxisEngine,
|
|
335
|
+
PraxisRegistry,
|
|
336
|
+
defineFact,
|
|
337
|
+
defineEvent,
|
|
338
|
+
defineRule,
|
|
339
|
+
} from "@plures/praxis";
|
|
340
|
+
|
|
341
|
+
// Define the context type
|
|
342
|
+
interface AuthContext {
|
|
343
|
+
currentUser: string | null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Define facts and events
|
|
347
|
+
const UserLoggedIn = defineFact<"UserLoggedIn", { userId: string }>("UserLoggedIn");
|
|
348
|
+
const Login = defineEvent<"LOGIN", { username: string }>("LOGIN");
|
|
349
|
+
|
|
350
|
+
// Define rules
|
|
351
|
+
const loginRule = defineRule<AuthContext>({
|
|
352
|
+
id: "auth.login",
|
|
353
|
+
description: "Process login event",
|
|
354
|
+
impl: (state, events) => {
|
|
355
|
+
const loginEvent = events.find(Login.is);
|
|
356
|
+
if (loginEvent) {
|
|
357
|
+
state.context.currentUser = loginEvent.payload.username;
|
|
358
|
+
return [UserLoggedIn.create({ userId: loginEvent.payload.username })];
|
|
359
|
+
}
|
|
360
|
+
return [];
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// Create engine
|
|
365
|
+
const registry = new PraxisRegistry<AuthContext>();
|
|
366
|
+
registry.registerRule(loginRule);
|
|
367
|
+
|
|
368
|
+
const engine = createPraxisEngine({
|
|
369
|
+
initialContext: { currentUser: null },
|
|
370
|
+
registry,
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Dispatch events
|
|
374
|
+
const result = engine.step([Login.create({ username: "alice" })]);
|
|
375
|
+
console.log(result.state.facts); // [{ tag: "UserLoggedIn", payload: { userId: "alice" } }]
|
|
376
|
+
console.log(engine.getContext()); // { currentUser: "alice" }
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### With Constraints
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
import { defineConstraint } from "@plures/praxis";
|
|
383
|
+
|
|
384
|
+
const maxSessionsConstraint = defineConstraint<AuthContext>({
|
|
385
|
+
id: "auth.maxSessions",
|
|
386
|
+
description: "Only one user can be logged in at a time",
|
|
387
|
+
impl: (state) => {
|
|
388
|
+
return state.context.currentUser === null || "User already logged in";
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
registry.registerConstraint(maxSessionsConstraint);
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Svelte 5 Integration (NEW!)
|
|
396
|
+
|
|
397
|
+
#### Store API (Svelte 4/5 Compatible)
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
import { createPraxisStore, createDerivedStore } from "@plures/praxis/svelte";
|
|
401
|
+
|
|
402
|
+
const stateStore = createPraxisStore(engine);
|
|
403
|
+
const userStore = createDerivedStore(engine, (ctx) => ctx.currentUser);
|
|
404
|
+
|
|
405
|
+
// In Svelte component:
|
|
406
|
+
// $: currentUser = $userStore;
|
|
407
|
+
// <button on:click={() => stateStore.dispatch([Login.create({ username: "alice" })])}>
|
|
408
|
+
// Login
|
|
409
|
+
// </button>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
#### Runes API (Svelte 5 Only)
|
|
413
|
+
|
|
414
|
+
```svelte
|
|
415
|
+
<script lang="ts">
|
|
416
|
+
import { usePraxisEngine } from '@plures/praxis/svelte';
|
|
417
|
+
import { createMyEngine, Login } from './my-engine';
|
|
418
|
+
|
|
419
|
+
const engine = createMyEngine();
|
|
420
|
+
const {
|
|
421
|
+
context, // Reactive context
|
|
422
|
+
dispatch, // Dispatch events
|
|
423
|
+
undo, // Undo last action
|
|
424
|
+
redo, // Redo action
|
|
425
|
+
canUndo, // Boolean: can undo?
|
|
426
|
+
canRedo, // Boolean: can redo?
|
|
427
|
+
} = usePraxisEngine(engine, {
|
|
428
|
+
enableHistory: true, // Enable undo/redo
|
|
429
|
+
maxHistorySize: 50, // Keep last 50 snapshots
|
|
430
|
+
});
|
|
431
|
+
</script>
|
|
432
|
+
|
|
433
|
+
<div>
|
|
434
|
+
<p>User: {context.currentUser || 'Guest'}</p>
|
|
435
|
+
|
|
436
|
+
<button onclick={() => dispatch([Login.create({ username: 'alice' })])}>
|
|
437
|
+
Login
|
|
438
|
+
</button>
|
|
439
|
+
|
|
440
|
+
<button onclick={undo} disabled={!canUndo}>
|
|
441
|
+
⟲ Undo
|
|
442
|
+
</button>
|
|
443
|
+
|
|
444
|
+
<button onclick={redo} disabled={!canRedo}>
|
|
445
|
+
⟳ Redo
|
|
446
|
+
</button>
|
|
447
|
+
</div>
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
See the [Advanced Todo Example](src/examples/advanced-todo/) for a complete demo with:
|
|
451
|
+
- Undo/redo functionality
|
|
452
|
+
- Time-travel debugging
|
|
453
|
+
- Keyboard shortcuts
|
|
454
|
+
- Beautiful UI
|
|
455
|
+
|
|
456
|
+
For comprehensive guides:
|
|
457
|
+
- [Svelte Integration Guide](docs/guides/svelte-integration.md)
|
|
458
|
+
- [History State Pattern](docs/guides/history-state-pattern.md)
|
|
459
|
+
- [Parallel State Pattern](docs/guides/parallel-state-pattern.md)
|
|
460
|
+
|
|
461
|
+
## Core Protocol
|
|
462
|
+
|
|
463
|
+
The language-neutral core protocol forms the foundation of Praxis:
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
// Facts and Events
|
|
467
|
+
interface PraxisFact {
|
|
468
|
+
tag: string;
|
|
469
|
+
payload: unknown;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
interface PraxisEvent {
|
|
473
|
+
tag: string;
|
|
474
|
+
payload: unknown;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// State
|
|
478
|
+
interface PraxisState {
|
|
479
|
+
context: unknown;
|
|
480
|
+
facts: PraxisFact[];
|
|
481
|
+
meta?: Record<string, unknown>;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Step Function (the conceptual core)
|
|
485
|
+
type PraxisStepFn = (
|
|
486
|
+
state: PraxisState,
|
|
487
|
+
events: PraxisEvent[],
|
|
488
|
+
config: PraxisStepConfig
|
|
489
|
+
) => PraxisStepResult;
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
This protocol is:
|
|
493
|
+
- Pure and deterministic (data in → data out)
|
|
494
|
+
- No side effects, no global state
|
|
495
|
+
- JSON-friendly for cross-language compatibility
|
|
496
|
+
- The foundation for all higher-level TypeScript APIs
|
|
497
|
+
|
|
498
|
+
## Framework Architecture
|
|
499
|
+
|
|
500
|
+
```
|
|
501
|
+
/praxis
|
|
502
|
+
├── core/ # Core framework
|
|
503
|
+
│ ├── schema/ # Schema system
|
|
504
|
+
│ │ └── types.ts # Schema type definitions
|
|
505
|
+
│ ├── logic/ # Logic engine (existing src/core/)
|
|
506
|
+
│ │ ├── protocol.ts # Language-neutral protocol
|
|
507
|
+
│ │ ├── rules.ts # Rules, constraints, and registry
|
|
508
|
+
│ │ ├── engine.ts # LogicEngine implementation
|
|
509
|
+
│ │ ├── actors.ts # Actor system
|
|
510
|
+
│ │ └── introspection.ts # Introspection and visualization
|
|
511
|
+
│ ├── component/ # Component generation
|
|
512
|
+
│ │ └── generator.ts # Svelte component generator
|
|
513
|
+
│ └── runtime/ # Runtime abstractions
|
|
514
|
+
├── integrations/ # Ecosystem integrations
|
|
515
|
+
│ ├── pluresdb/ # PluresDB reactive datastore
|
|
516
|
+
│ ├── unum/ # Unum identity and channels
|
|
517
|
+
│ ├── adp/ # Architectural Decision Protocol
|
|
518
|
+
│ ├── state-docs/ # State-Docs documentation
|
|
519
|
+
│ └── canvas/ # CodeCanvas visual editor
|
|
520
|
+
├── cli/ # Command-line interface
|
|
521
|
+
│ ├── index.ts # CLI entry point
|
|
522
|
+
│ └── commands/ # Command implementations
|
|
523
|
+
├── templates/ # Project templates
|
|
524
|
+
│ ├── basic-app/ # Basic application template
|
|
525
|
+
│ ├── fullstack-app/ # Full-stack template
|
|
526
|
+
│ ├── component/ # Component template
|
|
527
|
+
│ └── orchestrator/ # Distributed orchestration template
|
|
528
|
+
├── examples/ # Example applications
|
|
529
|
+
│ ├── offline-chat/ # Offline-first chat demo
|
|
530
|
+
│ ├── knowledge-canvas/ # Knowledge management with Canvas
|
|
531
|
+
│ ├── distributed-node/ # Self-orchestrating node demo
|
|
532
|
+
│ ├── auth-basic/ # Login/logout example
|
|
533
|
+
│ ├── cart/ # Shopping cart example
|
|
534
|
+
│ ├── svelte-counter/ # Svelte integration example
|
|
535
|
+
│ └── hero-ecommerce/ # Comprehensive e-commerce demo
|
|
536
|
+
└── docs/ # Framework documentation
|
|
537
|
+
├── guides/ # User guides
|
|
538
|
+
│ ├── getting-started.md # Getting started guide
|
|
539
|
+
│ ├── canvas.md # CodeCanvas guide
|
|
540
|
+
│ └── orchestration.md # Orchestration guide
|
|
541
|
+
├── api/ # API reference
|
|
542
|
+
└── architecture/ # Architecture documentation
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
See [FRAMEWORK.md](./FRAMEWORK.md) for complete architecture documentation.
|
|
546
|
+
|
|
547
|
+
## Examples
|
|
548
|
+
|
|
549
|
+
The repository includes four complete examples:
|
|
550
|
+
|
|
551
|
+
### 1. Hero E-Commerce (`src/examples/hero-ecommerce`)
|
|
552
|
+
**NEW!** Comprehensive example demonstrating all Praxis features in a single application:
|
|
553
|
+
- Authentication with session management
|
|
554
|
+
- Shopping cart with discount rules
|
|
555
|
+
- Feature flags for A/B testing
|
|
556
|
+
- Loyalty program with points
|
|
557
|
+
- Actors for logging and analytics
|
|
558
|
+
- Constraints enforcing business rules
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
npm run build
|
|
562
|
+
node dist/examples/hero-ecommerce/index.js
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### 2. Offline-First Chat (`examples/offline-chat`)
|
|
566
|
+
**NEW!** Demonstrates local-first architecture with PluresDB:
|
|
567
|
+
- Offline message composition and storage
|
|
568
|
+
- Automatic sync when connected
|
|
569
|
+
- Message queue for offline messages
|
|
570
|
+
- Conflict resolution for concurrent edits
|
|
571
|
+
- Real-time features (typing indicators, read receipts)
|
|
572
|
+
|
|
573
|
+
See [examples/offline-chat/README.md](./examples/offline-chat/README.md)
|
|
574
|
+
|
|
575
|
+
### 3. Knowledge Canvas (`examples/knowledge-canvas`)
|
|
576
|
+
**NEW!** Showcases CodeCanvas integration for visual knowledge management:
|
|
577
|
+
- Visual knowledge graph editing
|
|
578
|
+
- Schema-driven content types
|
|
579
|
+
- Generated UI components
|
|
580
|
+
- State-Docs integration
|
|
581
|
+
- Collaborative editing
|
|
582
|
+
|
|
583
|
+
See [examples/knowledge-canvas/README.md](./examples/knowledge-canvas/README.md)
|
|
584
|
+
|
|
585
|
+
### 4. Self-Orchestrating Node (`examples/distributed-node`)
|
|
586
|
+
**NEW!** Demonstrates distributed orchestration with DSC/MCP:
|
|
587
|
+
- Automatic node discovery
|
|
588
|
+
- Self-healing behavior
|
|
589
|
+
- State synchronization across nodes
|
|
590
|
+
- Health monitoring and auto-scaling
|
|
591
|
+
- Failover and recovery
|
|
592
|
+
|
|
593
|
+
See [examples/distributed-node/README.md](./examples/distributed-node/README.md)
|
|
594
|
+
|
|
595
|
+
### 5. Terminal Node (`examples/terminal-node`)
|
|
596
|
+
**NEW!** Demonstrates the terminal node feature for command execution:
|
|
597
|
+
- Terminal adapter creation and configuration
|
|
598
|
+
- Command execution and history tracking
|
|
599
|
+
- YAML schema loading with terminal nodes
|
|
600
|
+
- PluresDB binding configuration (ready for integration)
|
|
601
|
+
- Both text and widget input modes
|
|
602
|
+
|
|
603
|
+
```bash
|
|
604
|
+
npm run build
|
|
605
|
+
node examples/terminal-node/index.js
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
See [examples/terminal-node/README.md](./examples/terminal-node/README.md) and [docs/TERMINAL_NODE.md](./docs/TERMINAL_NODE.md)
|
|
609
|
+
|
|
610
|
+
### 6. Auth Basic (`src/examples/auth-basic`)
|
|
611
|
+
Login/logout with facts, rules, and constraints.
|
|
612
|
+
|
|
613
|
+
```bash
|
|
614
|
+
npm run build
|
|
615
|
+
node dist/examples/auth-basic/index.js
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
### 7. Cart (`src/examples/cart`)
|
|
619
|
+
Shopping cart with multiple rules, constraints, and complex state management.
|
|
620
|
+
|
|
621
|
+
```bash
|
|
622
|
+
npm run build
|
|
623
|
+
node dist/examples/cart/index.js
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
### 8. Svelte Counter (`src/examples/svelte-counter`)
|
|
627
|
+
Counter example showing Svelte v5 integration with reactive stores.
|
|
628
|
+
|
|
629
|
+
```bash
|
|
630
|
+
npm run build
|
|
631
|
+
node dist/examples/svelte-counter/index.js
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
## API Reference
|
|
635
|
+
|
|
636
|
+
### Core Types
|
|
637
|
+
|
|
638
|
+
- `PraxisFact`, `PraxisEvent`, `PraxisState` - Protocol types
|
|
639
|
+
- `LogicEngine<TContext>` - Main engine class
|
|
640
|
+
- `PraxisRegistry<TContext>` - Rule and constraint registry
|
|
641
|
+
- `Actor<TContext>` - Actor interface
|
|
642
|
+
- `ActorManager<TContext>` - Actor lifecycle management
|
|
643
|
+
|
|
644
|
+
### DSL Functions
|
|
645
|
+
|
|
646
|
+
- `defineFact<TTag, TPayload>(tag)` - Define a typed fact
|
|
647
|
+
- `defineEvent<TTag, TPayload>(tag)` - Define a typed event
|
|
648
|
+
- `defineRule<TContext>(options)` - Define a rule
|
|
649
|
+
- `defineConstraint<TContext>(options)` - Define a constraint
|
|
650
|
+
- `defineModule<TContext>(options)` - Bundle rules and constraints
|
|
651
|
+
|
|
652
|
+
### Helpers
|
|
653
|
+
|
|
654
|
+
- `findEvent(events, definition)` - Find first matching event
|
|
655
|
+
- `findFact(facts, definition)` - Find first matching fact
|
|
656
|
+
- `filterEvents(events, definition)` - Filter events by type
|
|
657
|
+
- `filterFacts(facts, definition)` - Filter facts by type
|
|
658
|
+
|
|
659
|
+
### Introspection & Visualization
|
|
660
|
+
|
|
661
|
+
**NEW!** Tools for examining and visualizing your Praxis logic:
|
|
662
|
+
|
|
663
|
+
```typescript
|
|
664
|
+
import { createIntrospector, PRAXIS_PROTOCOL_VERSION } from "@plures/praxis";
|
|
665
|
+
|
|
666
|
+
const introspector = createIntrospector(registry);
|
|
667
|
+
|
|
668
|
+
// Get statistics
|
|
669
|
+
const stats = introspector.getStats();
|
|
670
|
+
console.log(`Rules: ${stats.ruleCount}, Constraints: ${stats.constraintCount}`);
|
|
671
|
+
|
|
672
|
+
// Generate JSON schema
|
|
673
|
+
const schema = introspector.generateSchema(PRAXIS_PROTOCOL_VERSION);
|
|
674
|
+
|
|
675
|
+
// Generate graph visualization
|
|
676
|
+
const graph = introspector.generateGraph();
|
|
677
|
+
|
|
678
|
+
// Export to Graphviz DOT format
|
|
679
|
+
const dot = introspector.exportDOT();
|
|
680
|
+
fs.writeFileSync('registry.dot', dot);
|
|
681
|
+
|
|
682
|
+
// Export to Mermaid format
|
|
683
|
+
const mermaid = introspector.exportMermaid();
|
|
684
|
+
|
|
685
|
+
// Search rules and constraints
|
|
686
|
+
const authRules = introspector.searchRules('auth');
|
|
687
|
+
const maxConstraints = introspector.searchConstraints('max');
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
**Available methods:**
|
|
691
|
+
- `getStats()` - Get registry statistics
|
|
692
|
+
- `generateSchema(protocolVersion)` - Generate JSON schema
|
|
693
|
+
- `generateGraph()` - Generate graph representation
|
|
694
|
+
- `exportDOT()` - Export to Graphviz DOT format
|
|
695
|
+
- `exportMermaid()` - Export to Mermaid diagram format
|
|
696
|
+
- `getRuleInfo(id)` - Get detailed rule information
|
|
697
|
+
- `getConstraintInfo(id)` - Get detailed constraint information
|
|
698
|
+
- `searchRules(query)` - Search rules by text
|
|
699
|
+
- `searchConstraints(query)` - Search constraints by text
|
|
700
|
+
|
|
701
|
+
## Ecosystem Integration
|
|
702
|
+
|
|
703
|
+
Praxis integrates with the full Plures ecosystem:
|
|
704
|
+
|
|
705
|
+
### PluresDB Integration
|
|
706
|
+
|
|
707
|
+
Local-first reactive datastore for offline-capable applications.
|
|
708
|
+
|
|
709
|
+
```typescript
|
|
710
|
+
import { createPluresDB } from '@plures/pluresdb';
|
|
711
|
+
|
|
712
|
+
// Create database from schema
|
|
713
|
+
const db = createPluresDB({
|
|
714
|
+
name: 'my-app',
|
|
715
|
+
version: 1,
|
|
716
|
+
stores: {
|
|
717
|
+
// Generated from Praxis schema
|
|
718
|
+
users: { keyPath: 'id', indexes: ['email'] },
|
|
719
|
+
tasks: { keyPath: 'id', indexes: ['status', 'createdAt'] },
|
|
720
|
+
},
|
|
721
|
+
sync: {
|
|
722
|
+
enabled: true,
|
|
723
|
+
endpoint: 'ws://localhost:8080/sync',
|
|
724
|
+
conflictResolution: 'last-write-wins',
|
|
725
|
+
},
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
// Use with Praxis logic engine
|
|
729
|
+
engine.step([TaskCreated.create({ taskId, title })]);
|
|
730
|
+
await db.tasks.add({ id: taskId, title, status: 'pending' });
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
**Status**: Foundation in place (`src/integrations/pluresdb.ts`)
|
|
734
|
+
**Documentation**: [docs/guides/pluresdb.md](./docs/guides/pluresdb.md)
|
|
735
|
+
|
|
736
|
+
### Unum Integration
|
|
737
|
+
|
|
738
|
+
Identity and channels for distributed systems.
|
|
739
|
+
|
|
740
|
+
```typescript
|
|
741
|
+
import { createUnumIdentity, createChannel } from '@plures/unum';
|
|
742
|
+
|
|
743
|
+
// Create identity
|
|
744
|
+
const identity = await createUnumIdentity({
|
|
745
|
+
name: 'my-app-node',
|
|
746
|
+
keys: await generateKeys(),
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
// Create channel for messaging
|
|
750
|
+
const channel = await createChannel({
|
|
751
|
+
name: 'app-events',
|
|
752
|
+
participants: [identity.id],
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
// Integrate with Praxis actors
|
|
756
|
+
const unumActor = createActor('unum-bridge', identity, async (event) => {
|
|
757
|
+
// Bridge Praxis events to Unum channels
|
|
758
|
+
await channel.publish(event);
|
|
759
|
+
});
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
**Status**: Planned
|
|
763
|
+
**Use Cases**: Distributed messaging, identity management, authentication
|
|
764
|
+
|
|
765
|
+
### ADP Integration
|
|
766
|
+
|
|
767
|
+
Architectural Decision Protocol for guardrails and governance.
|
|
768
|
+
|
|
769
|
+
```typescript
|
|
770
|
+
import { createADP } from '@plures/adp';
|
|
771
|
+
|
|
772
|
+
// Track architectural decisions from schemas
|
|
773
|
+
const adp = createADP({
|
|
774
|
+
source: 'praxis-schema',
|
|
775
|
+
decisions: [
|
|
776
|
+
{
|
|
777
|
+
id: 'ADR-001',
|
|
778
|
+
title: 'Use PluresDB for local-first storage',
|
|
779
|
+
context: 'Need offline-capable data storage',
|
|
780
|
+
decision: 'Adopt PluresDB',
|
|
781
|
+
consequences: ['Offline support', 'Sync complexity'],
|
|
782
|
+
},
|
|
783
|
+
],
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
// Enforce guardrails
|
|
787
|
+
adp.enforce({
|
|
788
|
+
rule: 'no-direct-database-access',
|
|
789
|
+
check: (code) => !code.includes('direct-sql'),
|
|
790
|
+
});
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
**Status**: Planned
|
|
794
|
+
**Use Cases**: Architecture documentation, compliance checking, guardrails
|
|
795
|
+
|
|
796
|
+
### State-Docs Integration
|
|
797
|
+
|
|
798
|
+
Living documentation generated from Praxis schemas.
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
import { generateStateDocs } from '@plures/state-docs';
|
|
802
|
+
|
|
803
|
+
// Generate documentation from schema
|
|
804
|
+
const docs = await generateStateDocs({
|
|
805
|
+
schema: appSchema,
|
|
806
|
+
logic: logicDefinitions,
|
|
807
|
+
components: componentDefinitions,
|
|
808
|
+
output: './docs',
|
|
809
|
+
format: 'markdown', // or 'html', 'pdf'
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
// Documentation includes:
|
|
813
|
+
// - Data model diagrams
|
|
814
|
+
// - Logic flow diagrams
|
|
815
|
+
// - Component catalog
|
|
816
|
+
// - API reference
|
|
817
|
+
// - Usage examples
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
**Status**: Planned
|
|
821
|
+
**Documentation**: See examples for State-Docs integration patterns
|
|
822
|
+
|
|
823
|
+
### CodeCanvas Integration
|
|
824
|
+
|
|
825
|
+
Visual IDE for schema and logic editing.
|
|
826
|
+
|
|
827
|
+
```bash
|
|
828
|
+
# Open Canvas for visual editing
|
|
829
|
+
praxis canvas src/schemas/app.schema.ts
|
|
830
|
+
|
|
831
|
+
# Features:
|
|
832
|
+
# - Visual schema design
|
|
833
|
+
# - Logic flow editor
|
|
834
|
+
# - Component preview
|
|
835
|
+
# - Real-time collaboration
|
|
836
|
+
# - Export to code
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
**Status**: Planned
|
|
840
|
+
**Documentation**: [docs/guides/canvas.md](./docs/guides/canvas.md)
|
|
841
|
+
|
|
842
|
+
### Svelte + Tauri Runtime
|
|
843
|
+
|
|
844
|
+
Cross-platform runtime for web, desktop, and mobile.
|
|
845
|
+
|
|
846
|
+
```typescript
|
|
847
|
+
// Svelte v5 integration (available now)
|
|
848
|
+
import { createPraxisStore } from '@plures/praxis/svelte';
|
|
849
|
+
|
|
850
|
+
const stateStore = createPraxisStore(engine);
|
|
851
|
+
const userStore = createDerivedStore(engine, (ctx) => ctx.currentUser);
|
|
852
|
+
|
|
853
|
+
// In Svelte component:
|
|
854
|
+
// $: currentUser = $userStore;
|
|
855
|
+
|
|
856
|
+
// Desktop app with Tauri
|
|
857
|
+
npm run tauri:dev // Development
|
|
858
|
+
npm run tauri:build // Production
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
**Status**: Svelte integration available, Tauri templates planned
|
|
862
|
+
**Platform Support**: Web (now), Desktop (planned), Mobile (future)
|
|
863
|
+
|
|
864
|
+
## Cross-Language Usage
|
|
865
|
+
|
|
866
|
+
### PowerShell
|
|
867
|
+
|
|
868
|
+
**NEW!** Full PowerShell adapter for using Praxis from PowerShell scripts:
|
|
869
|
+
|
|
870
|
+
```powershell
|
|
871
|
+
# Import module
|
|
872
|
+
Import-Module ./powershell/Praxis.psm1
|
|
873
|
+
|
|
874
|
+
# Initialize adapter
|
|
875
|
+
Initialize-PraxisAdapter -EnginePath "./dist/adapters/cli.js"
|
|
876
|
+
|
|
877
|
+
# Create state and events
|
|
878
|
+
$state = New-PraxisState -Context @{ count = 0 }
|
|
879
|
+
$event = New-PraxisEvent -Tag "INCREMENT" -Payload @{}
|
|
880
|
+
|
|
881
|
+
# Process step
|
|
882
|
+
$result = Invoke-PraxisStep -State $state -Events @($event) -ConfigPath "./config.json"
|
|
883
|
+
|
|
884
|
+
# Use result
|
|
885
|
+
Write-Host "Count: $($result.state.context.count)"
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
See [powershell/README.md](./powershell/README.md) for complete documentation and examples.
|
|
889
|
+
|
|
890
|
+
### C# (Coming Soon)
|
|
891
|
+
|
|
892
|
+
Cross-language adapter for C# is planned with similar JSON-based protocol.
|
|
893
|
+
|
|
894
|
+
## Future Roadmap
|
|
895
|
+
|
|
896
|
+
### Short Term (v0.2.0)
|
|
897
|
+
- Complete CLI implementation
|
|
898
|
+
- Basic project templates
|
|
899
|
+
- Component generation MVP
|
|
900
|
+
- Enhanced PluresDB integration
|
|
901
|
+
|
|
902
|
+
### Medium Term (v0.3.0 - v0.5.0)
|
|
903
|
+
- Full CodeCanvas integration
|
|
904
|
+
- Unum identity support
|
|
905
|
+
- State-Docs generation
|
|
906
|
+
- Multi-language schemas
|
|
907
|
+
- C# adapter
|
|
908
|
+
|
|
909
|
+
### Long Term (v1.0.0+)
|
|
910
|
+
- Mobile templates (iOS, Android)
|
|
911
|
+
- Enterprise features
|
|
912
|
+
- Advanced orchestration
|
|
913
|
+
- Performance optimizations
|
|
914
|
+
- Plugin ecosystem
|
|
915
|
+
|
|
916
|
+
## Future Directions
|
|
917
|
+
|
|
918
|
+
### Ecosystem Integration
|
|
919
|
+
|
|
920
|
+
- **Svelte v5**: Full reactive binding support (foundation in place)
|
|
921
|
+
- **pluresdb**: Reactive datastore integration, event sourcing
|
|
922
|
+
- **unum**: Identity/channels and messaging
|
|
923
|
+
- **Visualization**: VSCode extension, docs generator, canvas tools (introspection API ready)
|
|
924
|
+
- **ADP**: Architectural guardrails and static checks
|
|
925
|
+
|
|
926
|
+
### Cross-Language Support
|
|
927
|
+
|
|
928
|
+
The core protocol is designed to be implemented in other languages:
|
|
929
|
+
|
|
930
|
+
**C# (future)**:
|
|
931
|
+
```csharp
|
|
932
|
+
PraxisState Step(PraxisState state, IEnumerable<PraxisEvent> events);
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
**PowerShell (future)**:
|
|
936
|
+
```powershell
|
|
937
|
+
$newState = Invoke-PraxisStep -State $state -Events $events
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
### Advanced Features
|
|
941
|
+
|
|
942
|
+
- Prolog/CLP-inspired features (facts, rules, declarative constraints, goal-style interactions)
|
|
943
|
+
- Backtracking/search over state space
|
|
944
|
+
- Property-based testing support
|
|
945
|
+
- Automatic documentation generation
|
|
946
|
+
- Static analysis tools
|
|
947
|
+
```typescript
|
|
948
|
+
import {
|
|
949
|
+
createRegistry,
|
|
950
|
+
createStepFunction,
|
|
951
|
+
rule,
|
|
952
|
+
constraint,
|
|
953
|
+
type PraxisState,
|
|
954
|
+
type PraxisEvent,
|
|
955
|
+
} from '@plures/praxis';
|
|
956
|
+
|
|
957
|
+
// Define your state
|
|
958
|
+
interface AppState extends PraxisState {
|
|
959
|
+
facts: {
|
|
960
|
+
count: number;
|
|
961
|
+
lastAction?: string;
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// Create a registry
|
|
966
|
+
const registry = createRegistry<AppState, PraxisEvent>();
|
|
967
|
+
|
|
968
|
+
// Define rules using the DSL
|
|
969
|
+
const incrementRule = rule<AppState, PraxisEvent>()
|
|
970
|
+
.id('increment')
|
|
971
|
+
.describe('Increment counter when increment event occurs')
|
|
972
|
+
.on('INCREMENT')
|
|
973
|
+
.when((state, event) => true)
|
|
974
|
+
.then((state, event) => [{
|
|
975
|
+
type: 'LOG',
|
|
976
|
+
payload: { message: 'Counter incremented' }
|
|
977
|
+
}])
|
|
978
|
+
.build();
|
|
979
|
+
|
|
980
|
+
// Define constraints
|
|
981
|
+
const positiveCountConstraint = constraint<AppState>()
|
|
982
|
+
.id('positive-count')
|
|
983
|
+
.describe('Count must be non-negative')
|
|
984
|
+
.check((state) => state.facts.count >= 0)
|
|
985
|
+
.message('Count cannot be negative')
|
|
986
|
+
.build();
|
|
987
|
+
|
|
988
|
+
// Register rules and constraints
|
|
989
|
+
registry.registerRule(incrementRule);
|
|
990
|
+
registry.registerConstraint(positiveCountConstraint);
|
|
991
|
+
|
|
992
|
+
// Create a step function with custom reducer
|
|
993
|
+
const step = createStepFunction<AppState, PraxisEvent>({
|
|
994
|
+
registry,
|
|
995
|
+
checkConstraints: true,
|
|
996
|
+
reducer: (state, event) => {
|
|
997
|
+
if (event.type === 'INCREMENT') {
|
|
998
|
+
return {
|
|
999
|
+
...state,
|
|
1000
|
+
facts: {
|
|
1001
|
+
...state.facts,
|
|
1002
|
+
count: state.facts.count + 1,
|
|
1003
|
+
lastAction: 'increment',
|
|
1004
|
+
},
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
return state;
|
|
1008
|
+
},
|
|
1009
|
+
});
|
|
1010
|
+
|
|
1011
|
+
// Use the step function
|
|
1012
|
+
const initialState: AppState = {
|
|
1013
|
+
facts: { count: 0 },
|
|
1014
|
+
};
|
|
1015
|
+
|
|
1016
|
+
const event: PraxisEvent = {
|
|
1017
|
+
type: 'INCREMENT',
|
|
1018
|
+
timestamp: Date.now(),
|
|
1019
|
+
};
|
|
1020
|
+
|
|
1021
|
+
const result = step(initialState, event);
|
|
1022
|
+
console.log(result.state.facts.count); // 1
|
|
1023
|
+
console.log(result.effects); // [{ type: 'LOG', payload: { message: 'Counter incremented' } }]
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
## Core Concepts
|
|
1027
|
+
|
|
1028
|
+
### State and Events
|
|
1029
|
+
|
|
1030
|
+
**PraxisState** represents the current facts and context:
|
|
1031
|
+
|
|
1032
|
+
```typescript
|
|
1033
|
+
interface PraxisState {
|
|
1034
|
+
facts: Record<string, unknown>;
|
|
1035
|
+
metadata?: {
|
|
1036
|
+
version?: number;
|
|
1037
|
+
lastUpdated?: number;
|
|
1038
|
+
[key: string]: unknown;
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
**PraxisEvent** represents things that have happened:
|
|
1044
|
+
|
|
1045
|
+
```typescript
|
|
1046
|
+
interface PraxisEvent {
|
|
1047
|
+
type: string;
|
|
1048
|
+
timestamp: number;
|
|
1049
|
+
data?: Record<string, unknown>;
|
|
1050
|
+
metadata?: {
|
|
1051
|
+
correlationId?: string;
|
|
1052
|
+
source?: string;
|
|
1053
|
+
[key: string]: unknown;
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
### Rules
|
|
1059
|
+
|
|
1060
|
+
Rules are condition-action pairs that fire when conditions are met:
|
|
1061
|
+
|
|
1062
|
+
```typescript
|
|
1063
|
+
const myRule = rule<MyState, MyEvent>()
|
|
1064
|
+
.id('my-rule')
|
|
1065
|
+
.describe('What this rule does')
|
|
1066
|
+
.priority(10) // Higher priority rules execute first
|
|
1067
|
+
.on('EVENT_TYPE') // Optional: only check for specific event types
|
|
1068
|
+
.when((state, event) => {
|
|
1069
|
+
// Condition: return true to fire the rule
|
|
1070
|
+
return state.facts.someValue > 10;
|
|
1071
|
+
})
|
|
1072
|
+
.then((state, event) => {
|
|
1073
|
+
// Action: return effects to execute
|
|
1074
|
+
return [
|
|
1075
|
+
{ type: 'SEND_EMAIL', payload: { to: 'user@example.com' } },
|
|
1076
|
+
{ type: 'LOG', payload: { level: 'info', message: 'Rule fired' } },
|
|
1077
|
+
];
|
|
1078
|
+
})
|
|
1079
|
+
.build();
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
### Constraints
|
|
1083
|
+
|
|
1084
|
+
Constraints are invariants that must hold true:
|
|
1085
|
+
|
|
1086
|
+
```typescript
|
|
1087
|
+
const myConstraint = constraint<MyState>()
|
|
1088
|
+
.id('my-constraint')
|
|
1089
|
+
.describe('What this constraint ensures')
|
|
1090
|
+
.check((state) => {
|
|
1091
|
+
// Return true if constraint is satisfied
|
|
1092
|
+
return state.facts.balance >= 0;
|
|
1093
|
+
})
|
|
1094
|
+
.message('Balance cannot be negative')
|
|
1095
|
+
.build();
|
|
1096
|
+
```
|
|
1097
|
+
|
|
1098
|
+
### Registry
|
|
1099
|
+
|
|
1100
|
+
The registry manages rules and constraints:
|
|
1101
|
+
|
|
1102
|
+
```typescript
|
|
1103
|
+
const registry = createRegistry<MyState, MyEvent>();
|
|
1104
|
+
|
|
1105
|
+
// Register rules and constraints
|
|
1106
|
+
registry.registerRule(myRule);
|
|
1107
|
+
registry.registerConstraint(myConstraint);
|
|
1108
|
+
|
|
1109
|
+
// Evaluate rules for a state transition
|
|
1110
|
+
const effects = registry.evaluateRules(state, event);
|
|
1111
|
+
|
|
1112
|
+
// Check constraints
|
|
1113
|
+
const violations = registry.checkConstraints(state);
|
|
1114
|
+
|
|
1115
|
+
// Get statistics
|
|
1116
|
+
const stats = registry.getStats();
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
### Step Functions
|
|
1120
|
+
|
|
1121
|
+
Step functions are pure functions that transition state:
|
|
1122
|
+
|
|
1123
|
+
```typescript
|
|
1124
|
+
// With registry integration
|
|
1125
|
+
const step = createStepFunction({
|
|
1126
|
+
registry,
|
|
1127
|
+
checkConstraints: true,
|
|
1128
|
+
reducer: (state, event) => {
|
|
1129
|
+
// Your state transition logic
|
|
1130
|
+
return newState;
|
|
1131
|
+
},
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
// Simple step without registry
|
|
1135
|
+
const simpleStep = step((state, event) => {
|
|
1136
|
+
// Direct state transformation
|
|
1137
|
+
return { ...state, facts: { ...state.facts, updated: true } };
|
|
1138
|
+
});
|
|
1139
|
+
|
|
1140
|
+
// Compose multiple step functions
|
|
1141
|
+
const composedStep = compose(step1, step2, step3);
|
|
1142
|
+
```
|
|
1143
|
+
|
|
1144
|
+
### Actors
|
|
1145
|
+
|
|
1146
|
+
Actors maintain their own state and respond to events:
|
|
1147
|
+
|
|
1148
|
+
```typescript
|
|
1149
|
+
import { createActor, createActorSystem } from '@plures/praxis';
|
|
1150
|
+
|
|
1151
|
+
// Create an actor
|
|
1152
|
+
const myActor = createActor(
|
|
1153
|
+
'actor-1',
|
|
1154
|
+
initialState,
|
|
1155
|
+
stepFunction,
|
|
1156
|
+
'counter-actor'
|
|
1157
|
+
);
|
|
1158
|
+
|
|
1159
|
+
// Create an actor system
|
|
1160
|
+
const system = createActorSystem();
|
|
1161
|
+
system.register(myActor);
|
|
1162
|
+
|
|
1163
|
+
// Send events to actors
|
|
1164
|
+
const result = system.send('actor-1', event);
|
|
1165
|
+
|
|
1166
|
+
// Broadcast to all actors
|
|
1167
|
+
const results = system.broadcast(event);
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
### Flows
|
|
1171
|
+
|
|
1172
|
+
Flows represent sequences of events:
|
|
1173
|
+
|
|
1174
|
+
```typescript
|
|
1175
|
+
import { createFlow, advanceFlow } from '@plures/praxis';
|
|
1176
|
+
|
|
1177
|
+
// Define a flow
|
|
1178
|
+
const flow = createFlow('onboarding-flow', [
|
|
1179
|
+
{ id: 'step1', expectedEventType: 'USER_REGISTERED' },
|
|
1180
|
+
{ id: 'step2', expectedEventType: 'EMAIL_VERIFIED' },
|
|
1181
|
+
{ id: 'step3', expectedEventType: 'PROFILE_COMPLETED' },
|
|
1182
|
+
]);
|
|
1183
|
+
|
|
1184
|
+
// Advance the flow with events
|
|
1185
|
+
const { flow: updatedFlow, accepted } = advanceFlow(flow, event);
|
|
1186
|
+
|
|
1187
|
+
if (updatedFlow.complete) {
|
|
1188
|
+
console.log('Flow completed!');
|
|
1189
|
+
}
|
|
1190
|
+
```
|
|
1191
|
+
|
|
1192
|
+
## Architecture Principles
|
|
1193
|
+
|
|
1194
|
+
1. **Pure Functions**: State transitions are pure, predictable, and testable
|
|
1195
|
+
2. **JSON-Friendly**: All data structures serialize to JSON for interoperability
|
|
1196
|
+
3. **Logic-First**: Focus on business logic, not implementation details
|
|
1197
|
+
4. **Composable**: Build complex behavior from simple, reusable pieces
|
|
1198
|
+
5. **Type-Safe**: Leverage TypeScript for compile-time guarantees
|
|
1199
|
+
|
|
1200
|
+
## Advanced Usage
|
|
1201
|
+
|
|
1202
|
+
### Custom Event Types
|
|
1203
|
+
|
|
1204
|
+
```typescript
|
|
1205
|
+
interface UserEvent extends PraxisEvent {
|
|
1206
|
+
type: 'USER_LOGIN' | 'USER_LOGOUT';
|
|
1207
|
+
data: {
|
|
1208
|
+
userId: string;
|
|
1209
|
+
sessionId: string;
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
const registry = createRegistry<AppState, UserEvent>();
|
|
1214
|
+
```
|
|
1215
|
+
|
|
1216
|
+
### Effect Handlers
|
|
1217
|
+
|
|
1218
|
+
Effects are side-effect descriptions that can be executed outside the pure core:
|
|
1219
|
+
|
|
1220
|
+
```typescript
|
|
1221
|
+
async function executeEffects(effects: Effect[]) {
|
|
1222
|
+
for (const effect of effects) {
|
|
1223
|
+
switch (effect.type) {
|
|
1224
|
+
case 'SEND_EMAIL':
|
|
1225
|
+
await emailService.send(effect.payload);
|
|
1226
|
+
break;
|
|
1227
|
+
case 'LOG':
|
|
1228
|
+
console.log(effect.payload);
|
|
1229
|
+
break;
|
|
1230
|
+
// Add more effect handlers as needed
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
const result = step(state, event);
|
|
1236
|
+
if (result.effects) {
|
|
1237
|
+
await executeEffects(result.effects);
|
|
1238
|
+
}
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
## Future Roadmap
|
|
1242
|
+
|
|
1243
|
+
- 🌐 **Svelte v5 Integration**: First-class support for Svelte 5 runes
|
|
1244
|
+
- 🗄️ **pluresdb/unum Integration**: Persistent state management
|
|
1245
|
+
- 🔄 **C# Port**: Cross-platform compatibility
|
|
1246
|
+
- ⚡ **PowerShell Module**: Scripting and automation support
|
|
1247
|
+
- 🎭 **Advanced FSM Tools**: Internal state machine utilities
|
|
1248
|
+
- 📊 **Visualization**: Flow and state visualization tools
|
|
1249
|
+
|
|
1250
|
+
## Development
|
|
1251
|
+
|
|
1252
|
+
```bash
|
|
1253
|
+
# Install dependencies
|
|
1254
|
+
npm install
|
|
1255
|
+
|
|
1256
|
+
# Build
|
|
1257
|
+
npm run build
|
|
1258
|
+
|
|
1259
|
+
# Run tests
|
|
1260
|
+
npm test
|
|
1261
|
+
|
|
1262
|
+
# Type check
|
|
1263
|
+
npm run typecheck
|
|
1264
|
+
```
|
|
1265
|
+
|
|
1266
|
+
### Deno Development
|
|
1267
|
+
|
|
1268
|
+
```bash
|
|
1269
|
+
# Run with Deno
|
|
1270
|
+
deno task dev
|
|
1271
|
+
|
|
1272
|
+
# Run tests
|
|
1273
|
+
deno task test
|
|
1274
|
+
|
|
1275
|
+
# Lint and format
|
|
1276
|
+
deno task lint
|
|
1277
|
+
deno task fmt
|
|
1278
|
+
```
|
|
1279
|
+
|
|
1280
|
+
For more detailed development information, see [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
1281
|
+
|
|
1282
|
+
## License
|
|
1283
|
+
|
|
1284
|
+
MIT License - see [LICENSE](./LICENSE) for details.
|
|
1285
|
+
|
|
1286
|
+
## Contributing
|
|
1287
|
+
|
|
1288
|
+
Contributions are welcome! Please read our [Contributing Guide](./CONTRIBUTING.md) to get started.
|
|
1289
|
+
|
|
1290
|
+
- 🐛 [Report a bug](https://github.com/plures/praxis/issues/new?template=bug_report.yml)
|
|
1291
|
+
- 💡 [Request a feature](https://github.com/plures/praxis/issues/new?template=enhancement.yml)
|
|
1292
|
+
- 📖 [Improve documentation](https://github.com/plures/praxis/issues/new?template=bug_report.yml)
|
|
1293
|
+
- 🔒 [Report a security issue](./SECURITY.md)
|
|
1294
|
+
|
|
1295
|
+
Please review our [Code of Conduct](./CODE_OF_CONDUCT.md) before participating.
|
|
1296
|
+
|
|
1297
|
+
## Support
|
|
1298
|
+
|
|
1299
|
+
- 📚 [Documentation](./docs/)
|
|
1300
|
+
- 💬 [GitHub Discussions](https://github.com/plures/praxis/discussions)
|
|
1301
|
+
- 🐛 [Issue Tracker](https://github.com/plures/praxis/issues)
|
|
1302
|
+
- 🌐 [Plures Organization](https://github.com/plures)
|
|
1303
|
+
|
|
1304
|
+
---
|
|
1305
|
+
|
|
1306
|
+
**Praxis** – Because application logic should be practical, provable, and portable.
|
|
1307
|
+
|
|
1308
|
+
---
|
|
1309
|
+
|
|
1310
|
+
Built with ❤️ by the plures team
|