@plures/praxis 0.2.1 → 1.0.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 (486) hide show
  1. package/README.md +188 -61
  2. package/core/codegen/docs-generator.ts +808 -0
  3. package/core/codegen/index.ts +27 -0
  4. package/core/codegen/ts-generator.ts +15 -0
  5. package/core/db-adapter/index.ts +52 -0
  6. package/core/db-adapter/sync-engine.ts +450 -0
  7. package/core/logic-engine/engine.ts +12 -0
  8. package/core/logic-engine/index.ts +16 -0
  9. package/core/logic-engine/protocol.ts +16 -0
  10. package/core/logic-engine/psf-adapter.ts +269 -0
  11. package/core/logic-engine/rules.ts +16 -0
  12. package/core/schema-engine/compiler.ts +431 -0
  13. package/core/schema-engine/generator.ts +635 -0
  14. package/core/schema-engine/index.ts +18 -0
  15. package/core/schema-engine/psf.ts +664 -0
  16. package/core/schema-engine/types.ts +63 -0
  17. package/core/schema-engine/validator.ts +541 -0
  18. package/dist/core/codegen/docs-generator.d.ts +123 -0
  19. package/dist/core/codegen/docs-generator.d.ts.map +1 -0
  20. package/dist/core/codegen/docs-generator.js +674 -0
  21. package/dist/core/codegen/docs-generator.js.map +1 -0
  22. package/dist/core/codegen/index.d.ts +11 -0
  23. package/dist/core/codegen/index.d.ts.map +1 -0
  24. package/dist/core/codegen/index.js +13 -0
  25. package/dist/core/codegen/index.js.map +1 -0
  26. package/dist/core/codegen/ts-generator.d.ts +8 -0
  27. package/dist/core/codegen/ts-generator.d.ts.map +1 -0
  28. package/dist/core/codegen/ts-generator.js +8 -0
  29. package/dist/core/codegen/ts-generator.js.map +1 -0
  30. package/dist/core/db-adapter/index.d.ts +18 -0
  31. package/dist/core/db-adapter/index.d.ts.map +1 -0
  32. package/dist/core/db-adapter/index.js +23 -0
  33. package/dist/core/db-adapter/index.js.map +1 -0
  34. package/dist/core/db-adapter/sync-engine.d.ts +180 -0
  35. package/dist/core/db-adapter/sync-engine.d.ts.map +1 -0
  36. package/dist/core/db-adapter/sync-engine.js +342 -0
  37. package/dist/core/db-adapter/sync-engine.js.map +1 -0
  38. package/dist/core/logic-engine/engine.d.ts +8 -0
  39. package/dist/core/logic-engine/engine.d.ts.map +1 -0
  40. package/dist/core/logic-engine/engine.js +8 -0
  41. package/dist/core/logic-engine/engine.js.map +1 -0
  42. package/dist/core/logic-engine/index.d.ts +16 -0
  43. package/dist/core/logic-engine/index.d.ts.map +1 -0
  44. package/dist/core/logic-engine/index.js +16 -0
  45. package/dist/core/logic-engine/index.js.map +1 -0
  46. package/dist/core/logic-engine/protocol.d.ts +7 -0
  47. package/dist/core/logic-engine/protocol.d.ts.map +1 -0
  48. package/dist/core/logic-engine/protocol.js +7 -0
  49. package/dist/core/logic-engine/protocol.js.map +1 -0
  50. package/dist/core/logic-engine/psf-adapter.d.ts +88 -0
  51. package/dist/core/logic-engine/psf-adapter.d.ts.map +1 -0
  52. package/dist/core/logic-engine/psf-adapter.js +207 -0
  53. package/dist/core/logic-engine/psf-adapter.js.map +1 -0
  54. package/dist/core/logic-engine/rules.d.ts +7 -0
  55. package/dist/core/logic-engine/rules.d.ts.map +1 -0
  56. package/dist/core/logic-engine/rules.js +7 -0
  57. package/dist/core/logic-engine/rules.js.map +1 -0
  58. package/dist/core/schema-engine/compiler.d.ts +198 -0
  59. package/dist/core/schema-engine/compiler.d.ts.map +1 -0
  60. package/dist/core/schema-engine/compiler.js +262 -0
  61. package/dist/core/schema-engine/compiler.js.map +1 -0
  62. package/dist/core/schema-engine/generator.d.ts +115 -0
  63. package/dist/core/schema-engine/generator.d.ts.map +1 -0
  64. package/dist/core/schema-engine/generator.js +506 -0
  65. package/dist/core/schema-engine/generator.js.map +1 -0
  66. package/dist/core/schema-engine/index.d.ts +18 -0
  67. package/dist/core/schema-engine/index.d.ts.map +1 -0
  68. package/dist/core/schema-engine/index.js +18 -0
  69. package/dist/core/schema-engine/index.js.map +1 -0
  70. package/dist/core/schema-engine/psf.d.ts +612 -0
  71. package/dist/core/schema-engine/psf.d.ts.map +1 -0
  72. package/dist/core/schema-engine/psf.js +45 -0
  73. package/dist/core/schema-engine/psf.js.map +1 -0
  74. package/dist/core/schema-engine/types.d.ts +10 -0
  75. package/dist/core/schema-engine/types.d.ts.map +1 -0
  76. package/dist/core/schema-engine/types.js +7 -0
  77. package/dist/core/schema-engine/types.js.map +1 -0
  78. package/dist/core/schema-engine/validator.d.ts +140 -0
  79. package/dist/core/schema-engine/validator.d.ts.map +1 -0
  80. package/dist/core/schema-engine/validator.js +407 -0
  81. package/dist/core/schema-engine/validator.js.map +1 -0
  82. package/dist/src/adapters/cli.d.ts.map +1 -0
  83. package/dist/src/adapters/cli.js.map +1 -0
  84. package/dist/src/cli/commands/auth.d.ts.map +1 -0
  85. package/dist/src/cli/commands/auth.js.map +1 -0
  86. package/dist/src/cli/commands/build.d.ts +23 -0
  87. package/dist/src/cli/commands/build.d.ts.map +1 -0
  88. package/dist/src/cli/commands/build.js +162 -0
  89. package/dist/src/cli/commands/build.js.map +1 -0
  90. package/dist/src/cli/commands/canvas.d.ts +23 -0
  91. package/dist/src/cli/commands/canvas.d.ts.map +1 -0
  92. package/dist/src/cli/commands/canvas.js +215 -0
  93. package/dist/src/cli/commands/canvas.js.map +1 -0
  94. package/dist/src/cli/commands/cloud.d.ts.map +1 -0
  95. package/dist/src/cli/commands/cloud.js.map +1 -0
  96. package/dist/src/cli/commands/create.d.ts +21 -0
  97. package/dist/src/cli/commands/create.d.ts.map +1 -0
  98. package/dist/src/cli/commands/create.js +621 -0
  99. package/dist/src/cli/commands/create.js.map +1 -0
  100. package/dist/src/cli/commands/dev.d.ts +21 -0
  101. package/dist/src/cli/commands/dev.d.ts.map +1 -0
  102. package/dist/src/cli/commands/dev.js +71 -0
  103. package/dist/src/cli/commands/dev.js.map +1 -0
  104. package/dist/src/cli/commands/generate.d.ts.map +1 -0
  105. package/dist/src/cli/commands/generate.js.map +1 -0
  106. package/dist/src/cli/commands/orchestrate.d.ts +44 -0
  107. package/dist/src/cli/commands/orchestrate.d.ts.map +1 -0
  108. package/dist/src/cli/commands/orchestrate.js +150 -0
  109. package/dist/src/cli/commands/orchestrate.js.map +1 -0
  110. package/dist/{cli → src/cli}/index.d.ts.map +1 -1
  111. package/dist/{cli → src/cli}/index.js +53 -21
  112. package/dist/src/cli/index.js.map +1 -0
  113. package/dist/src/cloud/auth.d.ts.map +1 -0
  114. package/dist/src/cloud/auth.js.map +1 -0
  115. package/dist/src/cloud/billing.d.ts.map +1 -0
  116. package/dist/src/cloud/billing.js.map +1 -0
  117. package/dist/src/cloud/client.d.ts.map +1 -0
  118. package/dist/src/cloud/client.js.map +1 -0
  119. package/dist/src/cloud/index.d.ts.map +1 -0
  120. package/dist/src/cloud/index.js.map +1 -0
  121. package/dist/src/cloud/marketplace.d.ts.map +1 -0
  122. package/dist/src/cloud/marketplace.js.map +1 -0
  123. package/dist/src/cloud/provisioning.d.ts.map +1 -0
  124. package/dist/src/cloud/provisioning.js.map +1 -0
  125. package/dist/src/cloud/relay/endpoints.d.ts.map +1 -0
  126. package/dist/src/cloud/relay/endpoints.js.map +1 -0
  127. package/dist/src/cloud/relay/health/index.d.ts.map +1 -0
  128. package/dist/src/cloud/relay/health/index.js.map +1 -0
  129. package/dist/src/cloud/relay/stats/index.d.ts.map +1 -0
  130. package/dist/src/cloud/relay/stats/index.js.map +1 -0
  131. package/dist/src/cloud/relay/sync/index.d.ts.map +1 -0
  132. package/dist/src/cloud/relay/sync/index.js.map +1 -0
  133. package/dist/src/cloud/relay/usage/index.d.ts.map +1 -0
  134. package/dist/src/cloud/relay/usage/index.js.map +1 -0
  135. package/dist/src/cloud/sponsors.d.ts.map +1 -0
  136. package/dist/src/cloud/sponsors.js.map +1 -0
  137. package/dist/src/cloud/types.d.ts.map +1 -0
  138. package/dist/src/cloud/types.js.map +1 -0
  139. package/dist/src/components/index.d.ts.map +1 -0
  140. package/dist/src/components/index.js.map +1 -0
  141. package/dist/src/core/actors.d.ts.map +1 -0
  142. package/dist/src/core/actors.js.map +1 -0
  143. package/dist/src/core/component/generator.d.ts.map +1 -0
  144. package/dist/{core → src/core}/component/generator.js +45 -3
  145. package/dist/src/core/component/generator.js.map +1 -0
  146. package/dist/src/core/engine.d.ts.map +1 -0
  147. package/dist/src/core/engine.js.map +1 -0
  148. package/dist/src/core/introspection.d.ts.map +1 -0
  149. package/dist/src/core/introspection.js.map +1 -0
  150. package/dist/src/core/logic/generator.d.ts.map +1 -0
  151. package/dist/{core → src/core}/logic/generator.js +35 -4
  152. package/dist/src/core/logic/generator.js.map +1 -0
  153. package/dist/src/core/pluresdb/adapter.d.ts +72 -0
  154. package/dist/src/core/pluresdb/adapter.d.ts.map +1 -0
  155. package/dist/src/core/pluresdb/adapter.js +73 -0
  156. package/dist/src/core/pluresdb/adapter.js.map +1 -0
  157. package/dist/src/core/pluresdb/generator.d.ts.map +1 -0
  158. package/dist/{core → src/core}/pluresdb/generator.js +33 -4
  159. package/dist/src/core/pluresdb/generator.js.map +1 -0
  160. package/dist/src/core/pluresdb/index.d.ts +15 -0
  161. package/dist/src/core/pluresdb/index.d.ts.map +1 -0
  162. package/dist/src/core/pluresdb/index.js +11 -0
  163. package/dist/src/core/pluresdb/index.js.map +1 -0
  164. package/dist/src/core/pluresdb/schema-registry.d.ts +104 -0
  165. package/dist/src/core/pluresdb/schema-registry.d.ts.map +1 -0
  166. package/dist/src/core/pluresdb/schema-registry.js +130 -0
  167. package/dist/src/core/pluresdb/schema-registry.js.map +1 -0
  168. package/dist/src/core/pluresdb/store.d.ts +199 -0
  169. package/dist/src/core/pluresdb/store.d.ts.map +1 -0
  170. package/dist/src/core/pluresdb/store.js +344 -0
  171. package/dist/src/core/pluresdb/store.js.map +1 -0
  172. package/dist/src/core/protocol.d.ts.map +1 -0
  173. package/dist/src/core/protocol.js.map +1 -0
  174. package/dist/src/core/rules.d.ts.map +1 -0
  175. package/dist/src/core/rules.js.map +1 -0
  176. package/dist/src/core/schema/loader.d.ts.map +1 -0
  177. package/dist/src/core/schema/loader.js.map +1 -0
  178. package/dist/src/core/schema/normalize.d.ts.map +1 -0
  179. package/dist/src/core/schema/normalize.js.map +1 -0
  180. package/dist/src/core/schema/types.d.ts.map +1 -0
  181. package/dist/src/core/schema/types.js.map +1 -0
  182. package/dist/src/dsl/index.d.ts.map +1 -0
  183. package/dist/src/dsl/index.js.map +1 -0
  184. package/dist/src/dsl.d.ts.map +1 -0
  185. package/dist/src/dsl.js.map +1 -0
  186. package/dist/src/examples/advanced-todo/index.d.ts.map +1 -0
  187. package/dist/src/examples/advanced-todo/index.js.map +1 -0
  188. package/dist/src/examples/auth-basic/index.d.ts.map +1 -0
  189. package/dist/src/examples/auth-basic/index.js.map +1 -0
  190. package/dist/src/examples/cart/index.d.ts.map +1 -0
  191. package/dist/src/examples/cart/index.js.map +1 -0
  192. package/dist/src/examples/hero-ecommerce/index.d.ts.map +1 -0
  193. package/dist/src/examples/hero-ecommerce/index.js.map +1 -0
  194. package/dist/src/examples/svelte-counter/index.d.ts.map +1 -0
  195. package/dist/src/examples/svelte-counter/index.js.map +1 -0
  196. package/dist/src/flows.d.ts.map +1 -0
  197. package/dist/src/flows.js.map +1 -0
  198. package/dist/{index.d.ts → src/index.d.ts} +12 -2
  199. package/dist/src/index.d.ts.map +1 -0
  200. package/dist/{index.js → src/index.js} +6 -1
  201. package/dist/src/index.js.map +1 -0
  202. package/dist/src/integrations/code-canvas.d.ts +265 -0
  203. package/dist/src/integrations/code-canvas.d.ts.map +1 -0
  204. package/dist/src/integrations/code-canvas.js +451 -0
  205. package/dist/src/integrations/code-canvas.js.map +1 -0
  206. package/dist/src/integrations/pluresdb.d.ts +117 -0
  207. package/dist/src/integrations/pluresdb.d.ts.map +1 -0
  208. package/dist/src/integrations/pluresdb.js +117 -0
  209. package/dist/src/integrations/pluresdb.js.map +1 -0
  210. package/dist/src/integrations/state-docs.d.ts +191 -0
  211. package/dist/src/integrations/state-docs.d.ts.map +1 -0
  212. package/dist/src/integrations/state-docs.js +515 -0
  213. package/dist/src/integrations/state-docs.js.map +1 -0
  214. package/dist/src/integrations/svelte.d.ts.map +1 -0
  215. package/dist/src/integrations/svelte.js.map +1 -0
  216. package/dist/src/integrations/tauri.d.ts +360 -0
  217. package/dist/src/integrations/tauri.d.ts.map +1 -0
  218. package/dist/src/integrations/tauri.js +278 -0
  219. package/dist/src/integrations/tauri.js.map +1 -0
  220. package/dist/src/integrations/unum.d.ts +159 -0
  221. package/dist/src/integrations/unum.d.ts.map +1 -0
  222. package/dist/src/integrations/unum.js +240 -0
  223. package/dist/src/integrations/unum.js.map +1 -0
  224. package/dist/src/registry.d.ts.map +1 -0
  225. package/dist/src/registry.js.map +1 -0
  226. package/dist/{runtime → src/runtime}/terminal-adapter.d.ts +58 -7
  227. package/dist/src/runtime/terminal-adapter.d.ts.map +1 -0
  228. package/dist/src/runtime/terminal-adapter.js +237 -0
  229. package/dist/src/runtime/terminal-adapter.js.map +1 -0
  230. package/dist/src/step.d.ts.map +1 -0
  231. package/dist/src/step.js.map +1 -0
  232. package/dist/src/types.d.ts.map +1 -0
  233. package/dist/{cloud → src}/types.js.map +1 -1
  234. package/dist/tools/cli/commands/index.d.ts +7 -0
  235. package/dist/tools/cli/commands/index.d.ts.map +1 -0
  236. package/dist/tools/cli/commands/index.js +7 -0
  237. package/dist/tools/cli/commands/index.js.map +1 -0
  238. package/dist/tools/cli/index.d.ts +8 -0
  239. package/dist/tools/cli/index.d.ts.map +1 -0
  240. package/dist/tools/cli/index.js +9 -0
  241. package/dist/tools/cli/index.js.map +1 -0
  242. package/dist/tools/watcher/index.d.ts +105 -0
  243. package/dist/tools/watcher/index.d.ts.map +1 -0
  244. package/dist/tools/watcher/index.js +213 -0
  245. package/dist/tools/watcher/index.js.map +1 -0
  246. package/dist/ui/canvas/canvas-projection.d.ts +78 -0
  247. package/dist/ui/canvas/canvas-projection.d.ts.map +1 -0
  248. package/dist/ui/canvas/canvas-projection.js +416 -0
  249. package/dist/ui/canvas/canvas-projection.js.map +1 -0
  250. package/dist/ui/canvas/canvas-state.d.ts +200 -0
  251. package/dist/ui/canvas/canvas-state.d.ts.map +1 -0
  252. package/dist/ui/canvas/canvas-state.js +464 -0
  253. package/dist/ui/canvas/canvas-state.js.map +1 -0
  254. package/dist/ui/canvas/components/index.d.ts +95 -0
  255. package/dist/ui/canvas/components/index.d.ts.map +1 -0
  256. package/dist/ui/canvas/components/index.js +19 -0
  257. package/dist/ui/canvas/components/index.js.map +1 -0
  258. package/dist/ui/canvas/index.d.ts +32 -0
  259. package/dist/ui/canvas/index.d.ts.map +1 -0
  260. package/dist/ui/canvas/index.js +32 -0
  261. package/dist/ui/canvas/index.js.map +1 -0
  262. package/dist/ui/svelte-generator/index.d.ts +9 -0
  263. package/dist/ui/svelte-generator/index.d.ts.map +1 -0
  264. package/dist/ui/svelte-generator/index.js +11 -0
  265. package/dist/ui/svelte-generator/index.js.map +1 -0
  266. package/dist/ui/svelte-generator/psf-generator.d.ts +128 -0
  267. package/dist/ui/svelte-generator/psf-generator.d.ts.map +1 -0
  268. package/dist/ui/svelte-generator/psf-generator.js +506 -0
  269. package/dist/ui/svelte-generator/psf-generator.js.map +1 -0
  270. package/docs/README.md +155 -0
  271. package/docs/core/building-extensions.md +553 -0
  272. package/docs/core/cli-usage.md +498 -0
  273. package/docs/core/code-canvas-sync.md +468 -0
  274. package/docs/core/logic-engine.md +566 -0
  275. package/docs/core/pluresdb-integration.md +646 -0
  276. package/docs/core/schema-model.md +414 -0
  277. package/docs/core/ui-generation.md +580 -0
  278. package/docs/core/what-is-praxis.md +240 -0
  279. package/docs/tutorials/README.md +84 -0
  280. package/docs/tutorials/ecommerce-cart.md +631 -0
  281. package/docs/tutorials/first-app.md +529 -0
  282. package/docs/tutorials/form-builder.md +620 -0
  283. package/docs/tutorials/todo-pluresdb.md +589 -0
  284. package/package.json +1 -1
  285. package/src/__tests__/canvas-components.test.ts +450 -0
  286. package/src/__tests__/cli-create.test.ts +178 -0
  287. package/src/__tests__/code-canvas-integration.test.ts +277 -0
  288. package/src/__tests__/docs-generator.test.ts +181 -0
  289. package/src/__tests__/generators.test.ts +3 -2
  290. package/src/__tests__/pluresdb.test.ts +457 -0
  291. package/src/__tests__/psf-schema-engine.test.ts +450 -0
  292. package/src/__tests__/state-docs-integration.test.ts +297 -0
  293. package/src/__tests__/tauri-integration.test.ts +298 -0
  294. package/src/__tests__/terminal-node.test.ts +1 -1
  295. package/src/__tests__/unum-integration.test.ts +142 -0
  296. package/src/cli/commands/build.ts +203 -0
  297. package/src/cli/commands/canvas.ts +246 -0
  298. package/src/cli/commands/create.ts +666 -0
  299. package/src/cli/commands/dev.ts +95 -0
  300. package/src/cli/commands/orchestrate.ts +212 -0
  301. package/src/cli/index.ts +48 -21
  302. package/src/core/component/generator.ts +45 -3
  303. package/src/core/logic/generator.ts +39 -4
  304. package/src/core/pluresdb/adapter.ts +117 -0
  305. package/src/core/pluresdb/generator.ts +33 -4
  306. package/src/core/pluresdb/index.ts +37 -0
  307. package/src/core/pluresdb/schema-registry.ts +162 -0
  308. package/src/core/pluresdb/store.ts +443 -0
  309. package/src/index.ts +109 -0
  310. package/src/integrations/code-canvas.ts +717 -0
  311. package/src/integrations/pluresdb.ts +140 -29
  312. package/src/integrations/state-docs.ts +710 -0
  313. package/src/integrations/tauri.ts +638 -0
  314. package/src/integrations/unum.ts +395 -0
  315. package/src/runtime/terminal-adapter.ts +178 -23
  316. package/dist/adapters/cli.d.ts.map +0 -1
  317. package/dist/adapters/cli.js.map +0 -1
  318. package/dist/cli/commands/auth.d.ts.map +0 -1
  319. package/dist/cli/commands/auth.js.map +0 -1
  320. package/dist/cli/commands/cloud.d.ts.map +0 -1
  321. package/dist/cli/commands/cloud.js.map +0 -1
  322. package/dist/cli/commands/generate.d.ts.map +0 -1
  323. package/dist/cli/commands/generate.js.map +0 -1
  324. package/dist/cli/index.js.map +0 -1
  325. package/dist/cloud/auth.d.ts.map +0 -1
  326. package/dist/cloud/auth.js.map +0 -1
  327. package/dist/cloud/billing.d.ts.map +0 -1
  328. package/dist/cloud/billing.js.map +0 -1
  329. package/dist/cloud/client.d.ts.map +0 -1
  330. package/dist/cloud/client.js.map +0 -1
  331. package/dist/cloud/index.d.ts.map +0 -1
  332. package/dist/cloud/index.js.map +0 -1
  333. package/dist/cloud/marketplace.d.ts.map +0 -1
  334. package/dist/cloud/marketplace.js.map +0 -1
  335. package/dist/cloud/provisioning.d.ts.map +0 -1
  336. package/dist/cloud/provisioning.js.map +0 -1
  337. package/dist/cloud/relay/endpoints.d.ts.map +0 -1
  338. package/dist/cloud/relay/endpoints.js.map +0 -1
  339. package/dist/cloud/relay/health/index.d.ts.map +0 -1
  340. package/dist/cloud/relay/health/index.js.map +0 -1
  341. package/dist/cloud/relay/stats/index.d.ts.map +0 -1
  342. package/dist/cloud/relay/stats/index.js.map +0 -1
  343. package/dist/cloud/relay/sync/index.d.ts.map +0 -1
  344. package/dist/cloud/relay/sync/index.js.map +0 -1
  345. package/dist/cloud/relay/usage/index.d.ts.map +0 -1
  346. package/dist/cloud/relay/usage/index.js.map +0 -1
  347. package/dist/cloud/sponsors.d.ts.map +0 -1
  348. package/dist/cloud/sponsors.js.map +0 -1
  349. package/dist/cloud/types.d.ts.map +0 -1
  350. package/dist/components/index.d.ts.map +0 -1
  351. package/dist/components/index.js.map +0 -1
  352. package/dist/core/actors.d.ts.map +0 -1
  353. package/dist/core/actors.js.map +0 -1
  354. package/dist/core/component/generator.d.ts.map +0 -1
  355. package/dist/core/component/generator.js.map +0 -1
  356. package/dist/core/engine.d.ts.map +0 -1
  357. package/dist/core/engine.js.map +0 -1
  358. package/dist/core/introspection.d.ts.map +0 -1
  359. package/dist/core/introspection.js.map +0 -1
  360. package/dist/core/logic/generator.d.ts.map +0 -1
  361. package/dist/core/logic/generator.js.map +0 -1
  362. package/dist/core/pluresdb/generator.d.ts.map +0 -1
  363. package/dist/core/pluresdb/generator.js.map +0 -1
  364. package/dist/core/protocol.d.ts.map +0 -1
  365. package/dist/core/protocol.js.map +0 -1
  366. package/dist/core/rules.d.ts.map +0 -1
  367. package/dist/core/rules.js.map +0 -1
  368. package/dist/core/schema/loader.d.ts.map +0 -1
  369. package/dist/core/schema/loader.js.map +0 -1
  370. package/dist/core/schema/normalize.d.ts.map +0 -1
  371. package/dist/core/schema/normalize.js.map +0 -1
  372. package/dist/core/schema/types.d.ts.map +0 -1
  373. package/dist/core/schema/types.js.map +0 -1
  374. package/dist/dsl/index.d.ts.map +0 -1
  375. package/dist/dsl/index.js.map +0 -1
  376. package/dist/dsl.d.ts.map +0 -1
  377. package/dist/dsl.js.map +0 -1
  378. package/dist/examples/advanced-todo/index.d.ts.map +0 -1
  379. package/dist/examples/advanced-todo/index.js.map +0 -1
  380. package/dist/examples/auth-basic/index.d.ts.map +0 -1
  381. package/dist/examples/auth-basic/index.js.map +0 -1
  382. package/dist/examples/cart/index.d.ts.map +0 -1
  383. package/dist/examples/cart/index.js.map +0 -1
  384. package/dist/examples/hero-ecommerce/index.d.ts.map +0 -1
  385. package/dist/examples/hero-ecommerce/index.js.map +0 -1
  386. package/dist/examples/svelte-counter/index.d.ts.map +0 -1
  387. package/dist/examples/svelte-counter/index.js.map +0 -1
  388. package/dist/flows.d.ts.map +0 -1
  389. package/dist/flows.js.map +0 -1
  390. package/dist/index.d.ts.map +0 -1
  391. package/dist/index.js.map +0 -1
  392. package/dist/integrations/pluresdb.d.ts +0 -56
  393. package/dist/integrations/pluresdb.d.ts.map +0 -1
  394. package/dist/integrations/pluresdb.js +0 -46
  395. package/dist/integrations/pluresdb.js.map +0 -1
  396. package/dist/integrations/svelte.d.ts.map +0 -1
  397. package/dist/integrations/svelte.js.map +0 -1
  398. package/dist/registry.d.ts.map +0 -1
  399. package/dist/registry.js.map +0 -1
  400. package/dist/runtime/terminal-adapter.d.ts.map +0 -1
  401. package/dist/runtime/terminal-adapter.js +0 -113
  402. package/dist/runtime/terminal-adapter.js.map +0 -1
  403. package/dist/step.d.ts.map +0 -1
  404. package/dist/step.js.map +0 -1
  405. package/dist/types.d.ts.map +0 -1
  406. package/dist/types.js.map +0 -1
  407. /package/dist/{adapters → src/adapters}/cli.d.ts +0 -0
  408. /package/dist/{adapters → src/adapters}/cli.js +0 -0
  409. /package/dist/{cli → src/cli}/commands/auth.d.ts +0 -0
  410. /package/dist/{cli → src/cli}/commands/auth.js +0 -0
  411. /package/dist/{cli → src/cli}/commands/cloud.d.ts +0 -0
  412. /package/dist/{cli → src/cli}/commands/cloud.js +0 -0
  413. /package/dist/{cli → src/cli}/commands/generate.d.ts +0 -0
  414. /package/dist/{cli → src/cli}/commands/generate.js +0 -0
  415. /package/dist/{cli → src/cli}/index.d.ts +0 -0
  416. /package/dist/{cloud → src/cloud}/auth.d.ts +0 -0
  417. /package/dist/{cloud → src/cloud}/auth.js +0 -0
  418. /package/dist/{cloud → src/cloud}/billing.d.ts +0 -0
  419. /package/dist/{cloud → src/cloud}/billing.js +0 -0
  420. /package/dist/{cloud → src/cloud}/client.d.ts +0 -0
  421. /package/dist/{cloud → src/cloud}/client.js +0 -0
  422. /package/dist/{cloud → src/cloud}/index.d.ts +0 -0
  423. /package/dist/{cloud → src/cloud}/index.js +0 -0
  424. /package/dist/{cloud → src/cloud}/marketplace.d.ts +0 -0
  425. /package/dist/{cloud → src/cloud}/marketplace.js +0 -0
  426. /package/dist/{cloud → src/cloud}/provisioning.d.ts +0 -0
  427. /package/dist/{cloud → src/cloud}/provisioning.js +0 -0
  428. /package/dist/{cloud → src/cloud}/relay/endpoints.d.ts +0 -0
  429. /package/dist/{cloud → src/cloud}/relay/endpoints.js +0 -0
  430. /package/dist/{cloud → src/cloud}/relay/health/index.d.ts +0 -0
  431. /package/dist/{cloud → src/cloud}/relay/health/index.js +0 -0
  432. /package/dist/{cloud → src/cloud}/relay/stats/index.d.ts +0 -0
  433. /package/dist/{cloud → src/cloud}/relay/stats/index.js +0 -0
  434. /package/dist/{cloud → src/cloud}/relay/sync/index.d.ts +0 -0
  435. /package/dist/{cloud → src/cloud}/relay/sync/index.js +0 -0
  436. /package/dist/{cloud → src/cloud}/relay/usage/index.d.ts +0 -0
  437. /package/dist/{cloud → src/cloud}/relay/usage/index.js +0 -0
  438. /package/dist/{cloud → src/cloud}/sponsors.d.ts +0 -0
  439. /package/dist/{cloud → src/cloud}/sponsors.js +0 -0
  440. /package/dist/{cloud → src/cloud}/types.d.ts +0 -0
  441. /package/dist/{cloud → src/cloud}/types.js +0 -0
  442. /package/dist/{components → src/components}/index.d.ts +0 -0
  443. /package/dist/{components → src/components}/index.js +0 -0
  444. /package/dist/{core → src/core}/actors.d.ts +0 -0
  445. /package/dist/{core → src/core}/actors.js +0 -0
  446. /package/dist/{core → src/core}/component/generator.d.ts +0 -0
  447. /package/dist/{core → src/core}/engine.d.ts +0 -0
  448. /package/dist/{core → src/core}/engine.js +0 -0
  449. /package/dist/{core → src/core}/introspection.d.ts +0 -0
  450. /package/dist/{core → src/core}/introspection.js +0 -0
  451. /package/dist/{core → src/core}/logic/generator.d.ts +0 -0
  452. /package/dist/{core → src/core}/pluresdb/generator.d.ts +0 -0
  453. /package/dist/{core → src/core}/protocol.d.ts +0 -0
  454. /package/dist/{core → src/core}/protocol.js +0 -0
  455. /package/dist/{core → src/core}/rules.d.ts +0 -0
  456. /package/dist/{core → src/core}/rules.js +0 -0
  457. /package/dist/{core → src/core}/schema/loader.d.ts +0 -0
  458. /package/dist/{core → src/core}/schema/loader.js +0 -0
  459. /package/dist/{core → src/core}/schema/normalize.d.ts +0 -0
  460. /package/dist/{core → src/core}/schema/normalize.js +0 -0
  461. /package/dist/{core → src/core}/schema/types.d.ts +0 -0
  462. /package/dist/{core → src/core}/schema/types.js +0 -0
  463. /package/dist/{dsl → src/dsl}/index.d.ts +0 -0
  464. /package/dist/{dsl → src/dsl}/index.js +0 -0
  465. /package/dist/{dsl.d.ts → src/dsl.d.ts} +0 -0
  466. /package/dist/{dsl.js → src/dsl.js} +0 -0
  467. /package/dist/{examples → src/examples}/advanced-todo/index.d.ts +0 -0
  468. /package/dist/{examples → src/examples}/advanced-todo/index.js +0 -0
  469. /package/dist/{examples → src/examples}/auth-basic/index.d.ts +0 -0
  470. /package/dist/{examples → src/examples}/auth-basic/index.js +0 -0
  471. /package/dist/{examples → src/examples}/cart/index.d.ts +0 -0
  472. /package/dist/{examples → src/examples}/cart/index.js +0 -0
  473. /package/dist/{examples → src/examples}/hero-ecommerce/index.d.ts +0 -0
  474. /package/dist/{examples → src/examples}/hero-ecommerce/index.js +0 -0
  475. /package/dist/{examples → src/examples}/svelte-counter/index.d.ts +0 -0
  476. /package/dist/{examples → src/examples}/svelte-counter/index.js +0 -0
  477. /package/dist/{flows.d.ts → src/flows.d.ts} +0 -0
  478. /package/dist/{flows.js → src/flows.js} +0 -0
  479. /package/dist/{integrations → src/integrations}/svelte.d.ts +0 -0
  480. /package/dist/{integrations → src/integrations}/svelte.js +0 -0
  481. /package/dist/{registry.d.ts → src/registry.d.ts} +0 -0
  482. /package/dist/{registry.js → src/registry.js} +0 -0
  483. /package/dist/{step.d.ts → src/step.d.ts} +0 -0
  484. /package/dist/{step.js → src/step.js} +0 -0
  485. /package/dist/{types.d.ts → src/types.d.ts} +0 -0
  486. /package/dist/{types.js → src/types.js} +0 -0
@@ -0,0 +1,631 @@
1
+ # E-commerce Cart Tutorial
2
+
3
+ This tutorial walks you through building a shopping cart with a multi-step checkout flow. You'll learn about flows, complex state management, and constraint validation.
4
+
5
+ **Time:** 45-60 minutes
6
+ **Level:** Intermediate to Advanced
7
+ **Prerequisites:** Completed [Form Builder Tutorial](./form-builder.md)
8
+
9
+ ## What You'll Build
10
+
11
+ An e-commerce cart that:
12
+ - Manages a product catalog
13
+ - Handles cart operations (add, remove, update quantity)
14
+ - Implements a multi-step checkout flow
15
+ - Validates cart constraints (max items, stock)
16
+ - Processes orders
17
+
18
+ ## Step 1: Define the Models
19
+
20
+ Create the PSF schema for the e-commerce domain:
21
+
22
+ ```json
23
+ {
24
+ "$version": "1.0.0",
25
+ "id": "ecommerce-cart",
26
+ "name": "E-commerce Cart",
27
+
28
+ "models": [
29
+ {
30
+ "name": "Product",
31
+ "fields": [
32
+ { "name": "id", "type": "uuid" },
33
+ { "name": "name", "type": "string" },
34
+ { "name": "description", "type": "string" },
35
+ { "name": "price", "type": "number" },
36
+ { "name": "stock", "type": "number" },
37
+ { "name": "imageUrl", "type": "string" }
38
+ ]
39
+ },
40
+ {
41
+ "name": "CartItem",
42
+ "fields": [
43
+ { "name": "productId", "type": "string" },
44
+ { "name": "quantity", "type": "number" },
45
+ { "name": "priceAtAdd", "type": "number" }
46
+ ]
47
+ },
48
+ {
49
+ "name": "Order",
50
+ "fields": [
51
+ { "name": "id", "type": "uuid" },
52
+ { "name": "items", "type": { "array": { "reference": "CartItem" } } },
53
+ { "name": "total", "type": "number" },
54
+ { "name": "status", "type": { "enum": ["pending", "processing", "shipped", "delivered"] } },
55
+ { "name": "shippingAddress", "type": "object" },
56
+ { "name": "createdAt", "type": "datetime" }
57
+ ]
58
+ }
59
+ ]
60
+ }
61
+ ```
62
+
63
+ ## Step 2: Create the Engine
64
+
65
+ Create `src/engine.ts`:
66
+
67
+ ```typescript
68
+ import {
69
+ createPraxisEngine,
70
+ PraxisRegistry,
71
+ defineFact,
72
+ defineEvent,
73
+ defineRule,
74
+ defineConstraint,
75
+ } from '@plures/praxis';
76
+
77
+ // Types
78
+ interface Product {
79
+ id: string;
80
+ name: string;
81
+ description: string;
82
+ price: number;
83
+ stock: number;
84
+ imageUrl: string;
85
+ }
86
+
87
+ interface CartItem {
88
+ productId: string;
89
+ quantity: number;
90
+ priceAtAdd: number;
91
+ }
92
+
93
+ interface ShippingAddress {
94
+ name: string;
95
+ street: string;
96
+ city: string;
97
+ state: string;
98
+ zip: string;
99
+ country: string;
100
+ }
101
+
102
+ interface Order {
103
+ id: string;
104
+ items: CartItem[];
105
+ total: number;
106
+ status: 'pending' | 'processing' | 'shipped' | 'delivered';
107
+ shippingAddress: ShippingAddress;
108
+ createdAt: Date;
109
+ }
110
+
111
+ type CheckoutStep = 'cart' | 'shipping' | 'payment' | 'confirmation';
112
+
113
+ interface CartContext {
114
+ products: Product[];
115
+ cart: CartItem[];
116
+ orders: Order[];
117
+ checkoutStep: CheckoutStep;
118
+ shippingAddress: ShippingAddress | null;
119
+ paymentMethod: string | null;
120
+ lastError: string | null;
121
+ }
122
+
123
+ // Facts
124
+ export const ItemAddedToCart = defineFact<'ItemAddedToCart', { productId: string; quantity: number }>('ItemAddedToCart');
125
+ export const ItemRemovedFromCart = defineFact<'ItemRemovedFromCart', { productId: string }>('ItemRemovedFromCart');
126
+ export const QuantityUpdated = defineFact<'QuantityUpdated', { productId: string; newQuantity: number }>('QuantityUpdated');
127
+ export const CheckoutStarted = defineFact<'CheckoutStarted', {}>('CheckoutStarted');
128
+ export const ShippingEntered = defineFact<'ShippingEntered', { address: ShippingAddress }>('ShippingEntered');
129
+ export const PaymentProcessed = defineFact<'PaymentProcessed', { success: boolean }>('PaymentProcessed');
130
+ export const OrderPlaced = defineFact<'OrderPlaced', { orderId: string; total: number }>('OrderPlaced');
131
+ export const CartCleared = defineFact<'CartCleared', {}>('CartCleared');
132
+
133
+ // Events
134
+ export const ADD_TO_CART = defineEvent<'ADD_TO_CART', { productId: string; quantity: number }>('ADD_TO_CART');
135
+ export const REMOVE_FROM_CART = defineEvent<'REMOVE_FROM_CART', { productId: string }>('REMOVE_FROM_CART');
136
+ export const UPDATE_QUANTITY = defineEvent<'UPDATE_QUANTITY', { productId: string; quantity: number }>('UPDATE_QUANTITY');
137
+ export const START_CHECKOUT = defineEvent<'START_CHECKOUT', {}>('START_CHECKOUT');
138
+ export const ENTER_SHIPPING = defineEvent<'ENTER_SHIPPING', { address: ShippingAddress }>('ENTER_SHIPPING');
139
+ export const ENTER_PAYMENT = defineEvent<'ENTER_PAYMENT', { method: string }>('ENTER_PAYMENT');
140
+ export const CONFIRM_ORDER = defineEvent<'CONFIRM_ORDER', {}>('CONFIRM_ORDER');
141
+ export const GO_BACK = defineEvent<'GO_BACK', {}>('GO_BACK');
142
+ export const CLEAR_CART = defineEvent<'CLEAR_CART', {}>('CLEAR_CART');
143
+
144
+ // Rules
145
+ const addToCartRule = defineRule<CartContext>({
146
+ id: 'cart.addItem',
147
+ description: 'Add item to cart',
148
+ impl: (state, events) => {
149
+ const event = events.find(ADD_TO_CART.is);
150
+ if (!event) return [];
151
+
152
+ const product = state.context.products.find(p => p.id === event.payload.productId);
153
+ if (!product) {
154
+ state.context.lastError = 'Product not found';
155
+ return [];
156
+ }
157
+
158
+ if (product.stock < event.payload.quantity) {
159
+ state.context.lastError = 'Not enough stock';
160
+ return [];
161
+ }
162
+
163
+ // Check if already in cart
164
+ const existingItem = state.context.cart.find(i => i.productId === event.payload.productId);
165
+ if (existingItem) {
166
+ existingItem.quantity += event.payload.quantity;
167
+ } else {
168
+ state.context.cart.push({
169
+ productId: event.payload.productId,
170
+ quantity: event.payload.quantity,
171
+ priceAtAdd: product.price,
172
+ });
173
+ }
174
+
175
+ state.context.lastError = null;
176
+ return [ItemAddedToCart.create({ productId: event.payload.productId, quantity: event.payload.quantity })];
177
+ },
178
+ });
179
+
180
+ const removeFromCartRule = defineRule<CartContext>({
181
+ id: 'cart.removeItem',
182
+ description: 'Remove item from cart',
183
+ impl: (state, events) => {
184
+ const event = events.find(REMOVE_FROM_CART.is);
185
+ if (!event) return [];
186
+
187
+ state.context.cart = state.context.cart.filter(i => i.productId !== event.payload.productId);
188
+ state.context.lastError = null;
189
+
190
+ return [ItemRemovedFromCart.create({ productId: event.payload.productId })];
191
+ },
192
+ });
193
+
194
+ const updateQuantityRule = defineRule<CartContext>({
195
+ id: 'cart.updateQuantity',
196
+ description: 'Update item quantity',
197
+ impl: (state, events) => {
198
+ const event = events.find(UPDATE_QUANTITY.is);
199
+ if (!event) return [];
200
+
201
+ const item = state.context.cart.find(i => i.productId === event.payload.productId);
202
+ if (!item) return [];
203
+
204
+ const product = state.context.products.find(p => p.id === event.payload.productId);
205
+ if (product && event.payload.quantity > product.stock) {
206
+ state.context.lastError = 'Not enough stock';
207
+ return [];
208
+ }
209
+
210
+ if (event.payload.quantity <= 0) {
211
+ state.context.cart = state.context.cart.filter(i => i.productId !== event.payload.productId);
212
+ } else {
213
+ item.quantity = event.payload.quantity;
214
+ }
215
+
216
+ state.context.lastError = null;
217
+ return [QuantityUpdated.create({ productId: event.payload.productId, newQuantity: event.payload.quantity })];
218
+ },
219
+ });
220
+
221
+ const startCheckoutRule = defineRule<CartContext>({
222
+ id: 'checkout.start',
223
+ description: 'Start the checkout process',
224
+ impl: (state, events) => {
225
+ const event = events.find(START_CHECKOUT.is);
226
+ if (!event) return [];
227
+
228
+ if (state.context.cart.length === 0) {
229
+ state.context.lastError = 'Cart is empty';
230
+ return [];
231
+ }
232
+
233
+ state.context.checkoutStep = 'shipping';
234
+ state.context.lastError = null;
235
+
236
+ return [CheckoutStarted.create({})];
237
+ },
238
+ });
239
+
240
+ const enterShippingRule = defineRule<CartContext>({
241
+ id: 'checkout.shipping',
242
+ description: 'Enter shipping information',
243
+ impl: (state, events) => {
244
+ const event = events.find(ENTER_SHIPPING.is);
245
+ if (!event) return [];
246
+
247
+ state.context.shippingAddress = event.payload.address;
248
+ state.context.checkoutStep = 'payment';
249
+ state.context.lastError = null;
250
+
251
+ return [ShippingEntered.create({ address: event.payload.address })];
252
+ },
253
+ });
254
+
255
+ const enterPaymentRule = defineRule<CartContext>({
256
+ id: 'checkout.payment',
257
+ description: 'Enter payment method',
258
+ impl: (state, events) => {
259
+ const event = events.find(ENTER_PAYMENT.is);
260
+ if (!event) return [];
261
+
262
+ state.context.paymentMethod = event.payload.method;
263
+ state.context.checkoutStep = 'confirmation';
264
+ state.context.lastError = null;
265
+
266
+ return [];
267
+ },
268
+ });
269
+
270
+ const confirmOrderRule = defineRule<CartContext>({
271
+ id: 'checkout.confirm',
272
+ description: 'Confirm and place order',
273
+ impl: (state, events) => {
274
+ const event = events.find(CONFIRM_ORDER.is);
275
+ if (!event) return [];
276
+
277
+ if (!state.context.shippingAddress || !state.context.paymentMethod) {
278
+ state.context.lastError = 'Missing checkout information';
279
+ return [];
280
+ }
281
+
282
+ // Calculate total
283
+ const total = state.context.cart.reduce((sum, item) => {
284
+ return sum + (item.priceAtAdd * item.quantity);
285
+ }, 0);
286
+
287
+ // Create order
288
+ const orderId = `order_${Date.now().toString(36)}`;
289
+ const order: Order = {
290
+ id: orderId,
291
+ items: [...state.context.cart],
292
+ total,
293
+ status: 'pending',
294
+ shippingAddress: state.context.shippingAddress,
295
+ createdAt: new Date(),
296
+ };
297
+
298
+ state.context.orders.push(order);
299
+
300
+ // Update stock
301
+ for (const item of state.context.cart) {
302
+ const product = state.context.products.find(p => p.id === item.productId);
303
+ if (product) {
304
+ product.stock -= item.quantity;
305
+ }
306
+ }
307
+
308
+ // Clear cart and reset checkout
309
+ state.context.cart = [];
310
+ state.context.checkoutStep = 'cart';
311
+ state.context.shippingAddress = null;
312
+ state.context.paymentMethod = null;
313
+ state.context.lastError = null;
314
+
315
+ return [
316
+ PaymentProcessed.create({ success: true }),
317
+ OrderPlaced.create({ orderId, total }),
318
+ CartCleared.create({}),
319
+ ];
320
+ },
321
+ });
322
+
323
+ const goBackRule = defineRule<CartContext>({
324
+ id: 'checkout.back',
325
+ description: 'Go back in checkout flow',
326
+ impl: (state, events) => {
327
+ const event = events.find(GO_BACK.is);
328
+ if (!event) return [];
329
+
330
+ const stepOrder: CheckoutStep[] = ['cart', 'shipping', 'payment', 'confirmation'];
331
+ const currentIndex = stepOrder.indexOf(state.context.checkoutStep);
332
+
333
+ if (currentIndex > 0) {
334
+ state.context.checkoutStep = stepOrder[currentIndex - 1];
335
+ }
336
+
337
+ return [];
338
+ },
339
+ });
340
+
341
+ const clearCartRule = defineRule<CartContext>({
342
+ id: 'cart.clear',
343
+ description: 'Clear all items from cart',
344
+ impl: (state, events) => {
345
+ const event = events.find(CLEAR_CART.is);
346
+ if (!event) return [];
347
+
348
+ state.context.cart = [];
349
+ state.context.checkoutStep = 'cart';
350
+ state.context.shippingAddress = null;
351
+ state.context.paymentMethod = null;
352
+
353
+ return [CartCleared.create({})];
354
+ },
355
+ });
356
+
357
+ // Constraints
358
+ const maxCartItemsConstraint = defineConstraint<CartContext>({
359
+ id: 'cart.maxItems',
360
+ description: 'Cart cannot have more than 20 unique items',
361
+ check: (state) => state.context.cart.length <= 20,
362
+ errorMessage: 'Cart cannot have more than 20 different items',
363
+ severity: 'error',
364
+ });
365
+
366
+ const maxQuantityConstraint = defineConstraint<CartContext>({
367
+ id: 'cart.maxQuantity',
368
+ description: 'Cannot order more than 10 of each item',
369
+ check: (state) => state.context.cart.every(item => item.quantity <= 10),
370
+ errorMessage: 'Cannot order more than 10 of each item',
371
+ severity: 'error',
372
+ });
373
+
374
+ const stockConstraint = defineConstraint<CartContext>({
375
+ id: 'cart.inStock',
376
+ description: 'Cart items must be in stock',
377
+ check: (state) => {
378
+ for (const item of state.context.cart) {
379
+ const product = state.context.products.find(p => p.id === item.productId);
380
+ if (!product || product.stock < item.quantity) {
381
+ return false;
382
+ }
383
+ }
384
+ return true;
385
+ },
386
+ errorMessage: 'Some items are out of stock',
387
+ severity: 'error',
388
+ });
389
+
390
+ // Registry
391
+ const registry = new PraxisRegistry<CartContext>();
392
+ registry.registerRule(addToCartRule);
393
+ registry.registerRule(removeFromCartRule);
394
+ registry.registerRule(updateQuantityRule);
395
+ registry.registerRule(startCheckoutRule);
396
+ registry.registerRule(enterShippingRule);
397
+ registry.registerRule(enterPaymentRule);
398
+ registry.registerRule(confirmOrderRule);
399
+ registry.registerRule(goBackRule);
400
+ registry.registerRule(clearCartRule);
401
+ registry.registerConstraint(maxCartItemsConstraint);
402
+ registry.registerConstraint(maxQuantityConstraint);
403
+ registry.registerConstraint(stockConstraint);
404
+
405
+ // Sample products
406
+ const sampleProducts: Product[] = [
407
+ { id: 'p1', name: 'Laptop', description: 'High-performance laptop', price: 999.99, stock: 10, imageUrl: '' },
408
+ { id: 'p2', name: 'Headphones', description: 'Wireless headphones', price: 149.99, stock: 25, imageUrl: '' },
409
+ { id: 'p3', name: 'Keyboard', description: 'Mechanical keyboard', price: 79.99, stock: 50, imageUrl: '' },
410
+ { id: 'p4', name: 'Mouse', description: 'Wireless mouse', price: 49.99, stock: 100, imageUrl: '' },
411
+ { id: 'p5', name: 'Monitor', description: '27" 4K monitor', price: 399.99, stock: 5, imageUrl: '' },
412
+ ];
413
+
414
+ // Engine factory
415
+ export function createCartEngine() {
416
+ return createPraxisEngine({
417
+ initialContext: {
418
+ products: sampleProducts,
419
+ cart: [],
420
+ orders: [],
421
+ checkoutStep: 'cart' as CheckoutStep,
422
+ shippingAddress: null,
423
+ paymentMethod: null,
424
+ lastError: null,
425
+ },
426
+ registry,
427
+ enableHistory: true,
428
+ });
429
+ }
430
+
431
+ // Helper functions
432
+ export function getCartTotal(context: CartContext): number {
433
+ return context.cart.reduce((sum, item) => sum + (item.priceAtAdd * item.quantity), 0);
434
+ }
435
+
436
+ export function getCartItemCount(context: CartContext): number {
437
+ return context.cart.reduce((sum, item) => sum + item.quantity, 0);
438
+ }
439
+
440
+ export function getCheckoutStepNumber(step: CheckoutStep): number {
441
+ const steps: CheckoutStep[] = ['cart', 'shipping', 'payment', 'confirmation'];
442
+ return steps.indexOf(step) + 1;
443
+ }
444
+ ```
445
+
446
+ ## Step 3: Demonstrate the Flow
447
+
448
+ Create `src/main.ts`:
449
+
450
+ ```typescript
451
+ import {
452
+ createCartEngine,
453
+ ADD_TO_CART,
454
+ UPDATE_QUANTITY,
455
+ START_CHECKOUT,
456
+ ENTER_SHIPPING,
457
+ ENTER_PAYMENT,
458
+ CONFIRM_ORDER,
459
+ getCartTotal,
460
+ getCartItemCount,
461
+ getCheckoutStepNumber,
462
+ } from './engine';
463
+
464
+ async function main() {
465
+ console.log('šŸ›’ E-commerce Cart Demo\n');
466
+
467
+ const engine = createCartEngine();
468
+
469
+ // Helper to display cart
470
+ function displayCart() {
471
+ const ctx = engine.getContext();
472
+ console.log('\nšŸ“¦ Cart:');
473
+ console.log('─'.repeat(50));
474
+
475
+ if (ctx.cart.length === 0) {
476
+ console.log(' (empty)');
477
+ } else {
478
+ ctx.cart.forEach((item, i) => {
479
+ const product = ctx.products.find(p => p.id === item.productId)!;
480
+ const subtotal = item.quantity * item.priceAtAdd;
481
+ console.log(` ${i + 1}. ${product.name} x${item.quantity} @ $${item.priceAtAdd.toFixed(2)} = $${subtotal.toFixed(2)}`);
482
+ });
483
+ console.log('─'.repeat(50));
484
+ console.log(` Items: ${getCartItemCount(ctx)}`);
485
+ console.log(` Total: $${getCartTotal(ctx).toFixed(2)}`);
486
+ }
487
+ console.log('');
488
+ }
489
+
490
+ // Display products
491
+ console.log('šŸ“‹ Available Products:');
492
+ engine.getContext().products.forEach((p, i) => {
493
+ console.log(` ${i + 1}. ${p.name} - $${p.price.toFixed(2)} (${p.stock} in stock)`);
494
+ });
495
+
496
+ displayCart();
497
+
498
+ // Add items to cart
499
+ console.log('Adding items to cart...');
500
+ engine.dispatch([ADD_TO_CART.create({ productId: 'p1', quantity: 1 })]); // Laptop
501
+ engine.dispatch([ADD_TO_CART.create({ productId: 'p2', quantity: 2 })]); // Headphones x2
502
+ engine.dispatch([ADD_TO_CART.create({ productId: 'p4', quantity: 1 })]); // Mouse
503
+
504
+ displayCart();
505
+
506
+ // Update quantity
507
+ console.log('Updating headphones quantity to 3...');
508
+ engine.dispatch([UPDATE_QUANTITY.create({ productId: 'p2', quantity: 3 })]);
509
+
510
+ displayCart();
511
+
512
+ // Start checkout
513
+ console.log('Starting checkout...');
514
+ engine.dispatch([START_CHECKOUT.create({})]);
515
+ console.log(`Checkout step: ${engine.getContext().checkoutStep} (${getCheckoutStepNumber(engine.getContext().checkoutStep)}/4)`);
516
+
517
+ // Enter shipping
518
+ console.log('\nEntering shipping information...');
519
+ engine.dispatch([ENTER_SHIPPING.create({
520
+ address: {
521
+ name: 'John Doe',
522
+ street: '123 Main St',
523
+ city: 'San Francisco',
524
+ state: 'CA',
525
+ zip: '94105',
526
+ country: 'USA',
527
+ },
528
+ })]);
529
+ console.log(`Checkout step: ${engine.getContext().checkoutStep} (${getCheckoutStepNumber(engine.getContext().checkoutStep)}/4)`);
530
+
531
+ // Enter payment
532
+ console.log('\nEntering payment method...');
533
+ engine.dispatch([ENTER_PAYMENT.create({ method: 'credit_card' })]);
534
+ console.log(`Checkout step: ${engine.getContext().checkoutStep} (${getCheckoutStepNumber(engine.getContext().checkoutStep)}/4)`);
535
+
536
+ // Confirm order
537
+ console.log('\nConfirming order...');
538
+ const result = engine.step([CONFIRM_ORDER.create({})]);
539
+
540
+ // Check for order confirmation
541
+ const orderPlaced = result.state.facts.find(f => f.tag === 'OrderPlaced');
542
+ if (orderPlaced) {
543
+ console.log('āœ… Order placed successfully!');
544
+ console.log(` Order ID: ${(orderPlaced.payload as any).orderId}`);
545
+ console.log(` Total: $${(orderPlaced.payload as any).total.toFixed(2)}`);
546
+ }
547
+
548
+ // Display orders
549
+ console.log('\nšŸ“‹ Orders:');
550
+ console.log('─'.repeat(50));
551
+ engine.getContext().orders.forEach((order, i) => {
552
+ console.log(` ${i + 1}. ${order.id}`);
553
+ console.log(` Status: ${order.status}`);
554
+ console.log(` Total: $${order.total.toFixed(2)}`);
555
+ console.log(` Items: ${order.items.length}`);
556
+ console.log(` Created: ${order.createdAt.toLocaleString()}`);
557
+ });
558
+
559
+ // Show updated stock
560
+ console.log('\nšŸ“¦ Updated Stock:');
561
+ engine.getContext().products.forEach((p, i) => {
562
+ console.log(` ${i + 1}. ${p.name} - ${p.stock} in stock`);
563
+ });
564
+
565
+ displayCart();
566
+
567
+ console.log('šŸŽ‰ Done!');
568
+ }
569
+
570
+ main().catch(console.error);
571
+ ```
572
+
573
+ ## Key Patterns Learned
574
+
575
+ ### 1. Multi-Step Flows
576
+
577
+ Using state to track flow progress:
578
+
579
+ ```typescript
580
+ type CheckoutStep = 'cart' | 'shipping' | 'payment' | 'confirmation';
581
+
582
+ interface Context {
583
+ checkoutStep: CheckoutStep;
584
+ }
585
+ ```
586
+
587
+ ### 2. Related State Updates
588
+
589
+ Updating multiple pieces of state together:
590
+
591
+ ```typescript
592
+ // Clear cart and reset checkout in one step
593
+ state.context.cart = [];
594
+ state.context.checkoutStep = 'cart';
595
+ state.context.shippingAddress = null;
596
+ ```
597
+
598
+ ### 3. Business Constraints
599
+
600
+ Enforcing business rules:
601
+
602
+ ```typescript
603
+ const stockConstraint = defineConstraint({
604
+ check: (state) => state.context.cart.every(item =>
605
+ products.find(p => p.id === item.productId)?.stock >= item.quantity
606
+ ),
607
+ });
608
+ ```
609
+
610
+ ### 4. Multiple Facts
611
+
612
+ Emitting multiple facts from a single rule:
613
+
614
+ ```typescript
615
+ return [
616
+ PaymentProcessed.create({ success: true }),
617
+ OrderPlaced.create({ orderId, total }),
618
+ CartCleared.create({}),
619
+ ];
620
+ ```
621
+
622
+ ## Next Steps
623
+
624
+ - Add product search and filtering
625
+ - Implement discount codes and promotions
626
+ - Add order history and tracking
627
+ - Integrate with a payment provider
628
+
629
+ ---
630
+
631
+ **Back to:** [Tutorials](./README.md)