@xmachines/play-tanstack-react-router 1.0.0-beta.1

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 (203) hide show
  1. package/.oxfmtrc.json +3 -0
  2. package/.oxlintrc.json +3 -0
  3. package/README.md +177 -0
  4. package/dist/extract-params.d.ts +45 -0
  5. package/dist/extract-params.d.ts.map +1 -0
  6. package/dist/extract-params.js +70 -0
  7. package/dist/extract-params.js.map +1 -0
  8. package/dist/index.d.ts +18 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +17 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/play-router-provider.d.ts +33 -0
  13. package/dist/play-router-provider.d.ts.map +1 -0
  14. package/dist/play-router-provider.js +31 -0
  15. package/dist/play-router-provider.js.map +1 -0
  16. package/dist/route-map.d.ts +101 -0
  17. package/dist/route-map.d.ts.map +1 -0
  18. package/dist/route-map.js +139 -0
  19. package/dist/route-map.js.map +1 -0
  20. package/dist/tanstack-router-bridge.d.ts +115 -0
  21. package/dist/tanstack-router-bridge.d.ts.map +1 -0
  22. package/dist/tanstack-router-bridge.js +112 -0
  23. package/dist/tanstack-router-bridge.js.map +1 -0
  24. package/dist/types.d.ts +26 -0
  25. package/dist/types.d.ts.map +1 -0
  26. package/dist/types.js +7 -0
  27. package/dist/types.js.map +1 -0
  28. package/dist/utils.d.ts +9 -0
  29. package/dist/utils.d.ts.map +1 -0
  30. package/dist/utils.js +10 -0
  31. package/dist/utils.js.map +1 -0
  32. package/examples/demo/README.md +100 -0
  33. package/examples/demo/docs/ARCHITECTURE.md +643 -0
  34. package/examples/demo/docs/INVARIANTS.md +461 -0
  35. package/examples/demo/docs/SWAP-REACT.md +635 -0
  36. package/examples/demo/index.html +16 -0
  37. package/examples/demo/package.json +39 -0
  38. package/examples/demo/src/App.tsx +148 -0
  39. package/examples/demo/src/components/About.tsx +49 -0
  40. package/examples/demo/src/components/Contact.tsx +43 -0
  41. package/examples/demo/src/components/Dashboard.tsx +46 -0
  42. package/examples/demo/src/components/DebugPanel.tsx +68 -0
  43. package/examples/demo/src/components/HeaderNav.tsx +103 -0
  44. package/examples/demo/src/components/Home.tsx +41 -0
  45. package/examples/demo/src/components/Login.tsx +82 -0
  46. package/examples/demo/src/components/Navigation.tsx +262 -0
  47. package/examples/demo/src/components/Profile.tsx +46 -0
  48. package/examples/demo/src/components/Register.tsx +109 -0
  49. package/examples/demo/src/components/Settings.tsx +92 -0
  50. package/examples/demo/src/components/index.ts +16 -0
  51. package/examples/demo/src/main.tsx +20 -0
  52. package/examples/demo/test/actor-authority.test.ts +50 -0
  53. package/examples/demo/test/browser/__screenshots__/back-button-duplicate.browser.test.tsx/Browser-back-button-navigates-through-unique-history--no-duplicates--1.png +0 -0
  54. package/examples/demo/test/browser/__screenshots__/back-button-duplicate.browser.test.tsx/GAP-12--navigation-via-goto---events-creates-single-history-entries-1.png +0 -0
  55. package/examples/demo/test/browser/__screenshots__/back-button-duplicate.browser.test.tsx/GAP-12--navigation-via-goto---events-creates-single-history-entries-2.png +0 -0
  56. package/examples/demo/test/browser/__screenshots__/back-forward-sync.browser.test.tsx/Back-Forward--After-authentication-flow-1.png +0 -0
  57. package/examples/demo/test/browser/__screenshots__/back-forward-sync.browser.test.tsx/Back-Forward--Multiple-rapid-navigations-1.png +0 -0
  58. package/examples/demo/test/browser/__screenshots__/back-forward-sync.browser.test.tsx/Back-Forward--Multiple-rapid-navigations-2.png +0 -0
  59. package/examples/demo/test/browser/__screenshots__/back-forward-sync.browser.test.tsx/Back-Forward--URL-stays-in-sync-with-actor-state-1.png +0 -0
  60. package/examples/demo/test/browser/__screenshots__/back-forward-sync.browser.test.tsx/Back-Forward--URL-stays-in-sync-with-actor-state-2.png +0 -0
  61. package/examples/demo/test/browser/__screenshots__/back-forward-sync.browser.test.tsx/Back-Forward--Works-correctly-1.png +0 -0
  62. package/examples/demo/test/browser/__screenshots__/back-forward-sync.browser.test.tsx/Back-Forward--Works-correctly-2.png +0 -0
  63. package/examples/demo/test/browser/__screenshots__/direct-navigation.browser.test.ts/Direct-navigation-to--about-loads-about-page-1.png +0 -0
  64. package/examples/demo/test/browser/__screenshots__/direct-navigation.browser.test.ts/Direct-navigation-to--contact-loads-contact-page-1.png +0 -0
  65. package/examples/demo/test/browser/__screenshots__/direct-navigation.browser.test.ts/Direct-navigation-to--home-loads-home-page-1.png +0 -0
  66. package/examples/demo/test/browser/__screenshots__/direct-navigation.browser.test.ts/Direct-navigation-to-protected-route-while-authenticated-loads-dashboard-1.png +0 -0
  67. package/examples/demo/test/browser/__screenshots__/direct-navigation.browser.test.ts/Direct-navigation-to-protected-route-while-unauthenticated-redirects-to-login-1.png +0 -0
  68. package/examples/demo/test/browser/__screenshots__/exact-user-scenario.browser.test.tsx/Debug--Print-history-after-each-navigation-1.png +0 -0
  69. package/examples/demo/test/browser/__screenshots__/exact-user-scenario.browser.test.tsx/Debug--Print-history-after-each-navigation-2.png +0 -0
  70. package/examples/demo/test/browser/__screenshots__/exact-user-scenario.browser.test.tsx/EXACT-USER-SCENARIO--home---about---home---contact---home--then-back-3x-should-land-on-about-1.png +0 -0
  71. package/examples/demo/test/browser/__screenshots__/exact-user-scenario.browser.test.tsx/EXACT-USER-SCENARIO--home---about---home---contact---home--then-back-3x-should-land-on-about-2.png +0 -0
  72. package/examples/demo/test/browser/__screenshots__/guard-rejection.browser.test.tsx/E2E--Actor-Authority---infrastructure-cannot-override-guards-1.png +0 -0
  73. package/examples/demo/test/browser/__screenshots__/guard-rejection.browser.test.tsx/E2E--Actor-Authority---infrastructure-cannot-override-guards-2.png +0 -0
  74. package/examples/demo/test/browser/__screenshots__/guard-rejection.browser.test.tsx/E2E--Guards-reject-invalid-navigation-1.png +0 -0
  75. package/examples/demo/test/browser/__screenshots__/guard-rejection.browser.test.tsx/E2E--Guards-reject-invalid-navigation-2.png +0 -0
  76. package/examples/demo/test/browser/__screenshots__/history-investigation.browser.test.tsx/baseHistory-back---navigation--avoiding-window-history--1.png +0 -0
  77. package/examples/demo/test/browser/__screenshots__/history-investigation.browser.test.tsx/baseHistory-back---navigation--avoiding-window-history--2.png +0 -0
  78. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Back-forward-with-guard-transitions---authenticated-user-1.png +0 -0
  79. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Back-forward-with-guard-transitions---authenticated-user-2.png +0 -0
  80. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Back-forward-with-guard-transitions---unauthenticated-user-1.png +0 -0
  81. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Back-forward-with-guard-transitions---unauthenticated-user-2.png +0 -0
  82. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Back-with-guard---authenticated-user-navigates-back-1.png +0 -0
  83. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Back-with-guard---authenticated-user-navigates-back-2.png +0 -0
  84. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Back-with-guard---unauthenticated-user-stays-on-public-routes-1.png +0 -0
  85. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Back-with-guard---unauthenticated-user-stays-on-public-routes-2.png +0 -0
  86. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Forward-button-after-back---unique-history-1.png +0 -0
  87. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Forward-button-after-back---unique-history-2.png +0 -0
  88. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Forward-button-after-back-1.png +0 -0
  89. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Forward-button-after-back-2.png +0 -0
  90. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Navigate-forward-then-back---unique-history-entries-1.png +0 -0
  91. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Navigate-forward-then-back---unique-history-entries-2.png +0 -0
  92. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Rapid-back-forward-navigation-doesn-t-cause-duplicate-entries-1.png +0 -0
  93. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Rapid-back-forward-navigation-doesn-t-cause-duplicate-entries-2.png +0 -0
  94. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Single-back-navigation---about-to-home-1.png +0 -0
  95. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Single-back-navigation---about-to-home-2.png +0 -0
  96. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Single-back-navigation---contact-to-about-1.png +0 -0
  97. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--Single-back-navigation---contact-to-about-2.png +0 -0
  98. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--View-syncs-with-URL-after-back-forward-1.png +0 -0
  99. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--View-syncs-with-URL-after-back-forward-2.png +0 -0
  100. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--View-syncs-with-URL-after-back-navigation-1.png +0 -0
  101. package/examples/demo/test/browser/__screenshots__/history-navigation.browser.test.ts/GAP-12--View-syncs-with-URL-after-back-navigation-2.png +0 -0
  102. package/examples/demo/test/browser/__screenshots__/login-flow.browser.test.tsx/E2E--User-can-log-in-and-see-dashboard-1.png +0 -0
  103. package/examples/demo/test/browser/__screenshots__/login-flow.browser.test.tsx/E2E--User-can-log-in-and-see-dashboard-2.png +0 -0
  104. package/examples/demo/test/browser/__screenshots__/navigation.browser.test.tsx/E2E--Navigation-reflects-actor-state-transitions-1.png +0 -0
  105. package/examples/demo/test/browser/__screenshots__/navigation.browser.test.tsx/E2E--Navigation-reflects-actor-state-transitions-2.png +0 -0
  106. package/examples/demo/test/browser/__screenshots__/protected-route-navigation.browser.test.tsx/Browser-back-forward-through-multiple-protected-routes-1.png +0 -0
  107. package/examples/demo/test/browser/__screenshots__/protected-route-navigation.browser.test.tsx/Browser-back-forward-through-multiple-protected-routes-2.png +0 -0
  108. package/examples/demo/test/browser/__screenshots__/protected-route-navigation.browser.test.tsx/Browser-back-navigates-from-dashboard-to-settings--protected-route--1.png +0 -0
  109. package/examples/demo/test/browser/__screenshots__/protected-route-navigation.browser.test.tsx/Browser-back-navigates-from-dashboard-to-settings--protected-route--2.png +0 -0
  110. package/examples/demo/test/browser/__screenshots__/protected-route-navigation.browser.test.tsx/RED--Browser-back-forward-through-multiple-protected-routes-1.png +0 -0
  111. package/examples/demo/test/browser/__screenshots__/protected-route-navigation.browser.test.tsx/RED--Browser-back-from-dashboard-to-settings--protected-route--1.png +0 -0
  112. package/examples/demo/test/browser/__screenshots__/protected-route-navigation.browser.test.tsx/RED--Browser-back-navigates-from-dashboard-to-settings--protected-route--1.png +0 -0
  113. package/examples/demo/test/browser/__screenshots__/settings-parameter.browser.test.tsx/Settings-Parameter-Display-should-display--account--section-when-navigating-to--settings-account-1.png +0 -0
  114. package/examples/demo/test/browser/__screenshots__/settings-parameter.browser.test.tsx/Settings-Parameter-Display-should-display--account--section-when-navigating-to--settings-account-2.png +0 -0
  115. package/examples/demo/test/browser/__screenshots__/settings-parameter.browser.test.tsx/Settings-Parameter-Display-should-display--general--section-when-navigating-to--settings--no-parameter--1.png +0 -0
  116. package/examples/demo/test/browser/__screenshots__/settings-parameter.browser.test.tsx/Settings-Parameter-Display-should-display--general--section-when-navigating-to--settings--no-parameter--2.png +0 -0
  117. package/examples/demo/test/browser/__screenshots__/settings-parameter.browser.test.tsx/Settings-Parameter-Display-should-display--profile--section-when-navigating-to--settings-profile-1.png +0 -0
  118. package/examples/demo/test/browser/__screenshots__/settings-parameter.browser.test.tsx/Settings-Parameter-Display-should-display--profile--section-when-navigating-to--settings-profile-2.png +0 -0
  119. package/examples/demo/test/browser/__screenshots__/settings-parameter.browser.test.tsx/Settings-Parameter-Display-should-update-section-display-when-clicking-section-navigation-buttons-1.png +0 -0
  120. package/examples/demo/test/browser/__screenshots__/settings-parameter.browser.test.tsx/Settings-Parameter-Display-should-update-section-display-when-clicking-section-navigation-buttons-2.png +0 -0
  121. package/examples/demo/test/browser/__screenshots__/settings-query-freeze.browser.test.ts/Settings-with-query-parameters-works-correctly-1.png +0 -0
  122. package/examples/demo/test/browser/__screenshots__/settings-query-freeze.browser.test.ts/Settings-with-section-parameter-works-correctly-1.png +0 -0
  123. package/examples/demo/test/browser/__screenshots__/state-driven.browser.test.ts/DEMO-04--State-Driven-Reset---Browser-back-sends-event-to-actor-1.png +0 -0
  124. package/examples/demo/test/browser/__screenshots__/state-driven.browser.test.ts/DEMO-04--State-Driven-Reset---Browser-back-sends-event-to-actor-2.png +0 -0
  125. package/examples/demo/test/browser/__screenshots__/state-driven.browser.test.ts/DEMO-04b--Browser-navigation-with-SignalSyncedHistory-integration-1.png +0 -0
  126. package/examples/demo/test/browser/__screenshots__/state-driven.browser.test.ts/DEMO-04b--Browser-navigation-with-SignalSyncedHistory-integration-2.png +0 -0
  127. package/examples/demo/test/browser/__screenshots__/tanstack-integration.browser.test.tsx/TanStack-Router-Integration-renders-with-RouterProvider-context-1.png +0 -0
  128. package/examples/demo/test/browser/__screenshots__/tanstack-integration.browser.test.tsx/TanStack-Router-Integration-renders-with-RouterProvider-context-2.png +0 -0
  129. package/examples/demo/test/browser/__screenshots__/test-multiple-back.browser.test.tsx/Multiple-back--Navigate-forward-3x-then-back-3x-1.png +0 -0
  130. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-1--Opening-with--someinvalidstate-stays-at-current-state-1.png +0 -0
  131. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-2--Opening-with--about-renders-About-component--not-Login-1.png +0 -0
  132. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-2b--Opening-with--home-renders-Home-component--not-Login-1.png +0 -0
  133. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-2c--Opening-with--contact-renders-Contact-component--not-Login-1.png +0 -0
  134. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-3--Back-forward-navigation---rendering-syncs-with-URL-1.png +0 -0
  135. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-3--Back-forward-navigation---rendering-syncs-with-URL-2.png +0 -0
  136. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-4--Auth-state-preserved-when-navigating-between-authenticated-anonymous-states-1.png +0 -0
  137. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-4--Auth-state-preserved-when-navigating-between-authenticated-anonymous-states-2.png +0 -0
  138. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-4b--Browser-back-forward-preserves-auth-state-1.png +0 -0
  139. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-4b--Browser-back-forward-preserves-auth-state-2.png +0 -0
  140. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-5--Protected-route-with-play-route-respects-authentication-guard-1.png +0 -0
  141. package/examples/demo/test/browser/__screenshots__/uat-xstate-route-regression.browser.test.ts/UAT-5--Protected-route-with-play-route-respects-authentication-guard-2.png +0 -0
  142. package/examples/demo/test/browser/__screenshots__/user-reported-scenario.browser.test.tsx/User-scenario--home---about---home---contact---home--then-back-3x-1.png +0 -0
  143. package/examples/demo/test/browser/__screenshots__/user-reported-scenario.browser.test.tsx/User-scenario--login---home---about---home---contact---home--then-back-3x-1.png +0 -0
  144. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/Browser-back-button-sends-play-route-event-with-correct-state-ID-1.png +0 -0
  145. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/Browser-back-button-sends-play-route-event-with-correct-state-ID-2.png +0 -0
  146. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/Browser-back-button-sends-xstate-route-event-with-correct-state-ID-1.png +0 -0
  147. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/Direct-URL-navigation-sends-play-route-event-1.png +0 -0
  148. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/Direct-URL-navigation-sends-xstate-route-event-1.png +0 -0
  149. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/Forward-button-sends-play-route-event-1.png +0 -0
  150. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/Forward-button-sends-play-route-event-2.png +0 -0
  151. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/Forward-button-sends-xstate-route-event-1.png +0 -0
  152. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/GAP-12-fix-preserved--No-duplicate-history-entries-with-play-route-1.png +0 -0
  153. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/GAP-12-fix-preserved--No-duplicate-history-entries-with-play-route-2.png +0 -0
  154. package/examples/demo/test/browser/__screenshots__/xstate-route-events.browser.test.ts/Protected-route-sends-xstate-route-with-authentication-guard-1.png +0 -0
  155. package/examples/demo/test/browser/back-button-duplicate.browser.test.tsx +148 -0
  156. package/examples/demo/test/browser/back-forward-sync.browser.test.tsx +149 -0
  157. package/examples/demo/test/browser/direct-navigation.browser.test.ts +146 -0
  158. package/examples/demo/test/browser/exact-user-scenario.browser.test.tsx +207 -0
  159. package/examples/demo/test/browser/guard-rejection.browser.test.tsx +52 -0
  160. package/examples/demo/test/browser/history-investigation.browser.test.tsx +82 -0
  161. package/examples/demo/test/browser/history-navigation.browser.test.ts +351 -0
  162. package/examples/demo/test/browser/login-flow.browser.test.tsx +34 -0
  163. package/examples/demo/test/browser/navigation.browser.test.tsx +34 -0
  164. package/examples/demo/test/browser/protected-route-navigation.browser.test.tsx +161 -0
  165. package/examples/demo/test/browser/redirect-url-update.browser.test.tsx +140 -0
  166. package/examples/demo/test/browser/settings-parameter.browser.test.tsx +164 -0
  167. package/examples/demo/test/browser/settings-query-freeze.browser.test.ts +141 -0
  168. package/examples/demo/test/browser/state-driven.browser.test.ts +112 -0
  169. package/examples/demo/test/browser/tanstack-integration.browser.test.tsx +61 -0
  170. package/examples/demo/test/browser/uat-xstate-route-regression.browser.test.ts +58 -0
  171. package/examples/demo/test/browser/xstate-route-events.browser.test.ts +293 -0
  172. package/examples/demo/test/browser-back-view-rendering.test.ts +104 -0
  173. package/examples/demo/test/browser-e2e/auth-flow.browser.test.tsx +49 -0
  174. package/examples/demo/test/invalid-route-redirect.test.ts +40 -0
  175. package/examples/demo/test/passive-infra.test.ts +35 -0
  176. package/examples/demo/test/route-parameters.test.ts +539 -0
  177. package/examples/demo/test/signal-only.test.ts +54 -0
  178. package/examples/demo/test/strict-separation.test.ts +37 -0
  179. package/examples/demo/test/test-utils.ts +49 -0
  180. package/examples/demo/tsconfig.json +21 -0
  181. package/examples/demo/tsconfig.tsbuildinfo +1 -0
  182. package/examples/demo/vite.config.ts +13 -0
  183. package/examples/demo/vitest.browser.config.ts +72 -0
  184. package/examples/demo/vitest.config.e2e.browser.ts +28 -0
  185. package/examples/demo/vitest.config.ts +35 -0
  186. package/package.json +51 -0
  187. package/src/extract-params.ts +75 -0
  188. package/src/index.ts +31 -0
  189. package/src/play-router-provider.tsx +46 -0
  190. package/src/route-map.ts +158 -0
  191. package/src/tanstack-router-bridge.ts +135 -0
  192. package/src/types.ts +26 -0
  193. package/src/utils.ts +12 -0
  194. package/test/browser/__screenshots__/signal-synced-history.browser.test.ts/Browser-back-button-sends-route-navigate-event-to-actor-1.png +0 -0
  195. package/test/browser/__screenshots__/signal-synced-history.browser.test.ts/SignalSyncedHistory-prevents-circular-updates-1.png +0 -0
  196. package/test/browser/__screenshots__/signal-synced-history.browser.test.ts/SignalSyncedHistory-syncs-actor-route-to-browser-URL-1.png +0 -0
  197. package/test/browser/signal-synced-history.browser.test.ts +95 -0
  198. package/test/route-map.test.ts +107 -0
  199. package/test/tanstack-router-bridge.test.ts +318 -0
  200. package/test/urlpattern-integration.test.ts +145 -0
  201. package/tsconfig.json +16 -0
  202. package/tsconfig.tsbuildinfo +1 -0
  203. package/vitest.config.ts +35 -0
@@ -0,0 +1,635 @@
1
+ # Swapping React for Vue or Svelte
2
+
3
+ **Proof of DEMO-06:** This guide demonstrates that swapping React for Vue or Svelte requires **zero changes to business logic** - only the view renderer and component implementations change.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [What Needs to Change](#what-needs-to-change)
10
+ 2. [What Stays the Same](#what-stays-the-same)
11
+ 3. [Vue Example](#vue-example)
12
+ 4. [Svelte Example](#svelte-example)
13
+ 5. [Why This Works](#why-this-works)
14
+
15
+ ---
16
+
17
+ ## What Needs to Change
18
+
19
+ | Layer | React | Vue | Svelte |
20
+ | ----------------------------- | ----------------------- | ------------------------------ | --------------------------------- |
21
+ | **Business Logic** | ✅ No changes | ✅ No changes | ✅ No changes |
22
+ | **State Machine** | ✅ No changes | ✅ No changes | ✅ No changes |
23
+ | **Component Catalog** | ✅ No changes | ✅ No changes | ✅ No changes |
24
+ | **Router Integration** | ✅ No changes | ✅ No changes | ✅ No changes |
25
+ | **View Renderer** | `@xmachines/play-react` | `@xmachines/play-vue` (future) | `@xmachines/play-svelte` (future) |
26
+ | **Component Implementations** | `.tsx` files | `.vue` files | `.svelte` files |
27
+
28
+ **Key Insight:** Only the view layer changes. Business logic, state machine, catalog, and router integration are framework-agnostic.
29
+
30
+ ---
31
+
32
+ ## What Stays the Same
33
+
34
+ ### 1. State Machine (100% Unchanged)
35
+
36
+ ```typescript
37
+ // src/machines/auth-machine.ts - IDENTICAL for React, Vue, Svelte
38
+ import { createMachine, assign } from "xstate";
39
+
40
+ export const authMachine = createMachine({
41
+ id: "auth",
42
+ initial: "loggedOut",
43
+ context: {
44
+ isAuthenticated: false,
45
+ username: null,
46
+ routeParams: {},
47
+ queryParams: {},
48
+ },
49
+ states: {
50
+ loggedOut: {
51
+ meta: {
52
+ route: "/",
53
+ view: {
54
+ component: "LoginForm", // String reference, not framework-specific
55
+ props: { title: "Please Log In" },
56
+ },
57
+ },
58
+ on: {
59
+ "auth.login": {
60
+ target: "loggedIn",
61
+ actions: assign({
62
+ isAuthenticated: true,
63
+ username: ({ event }) => event.username,
64
+ }),
65
+ },
66
+ },
67
+ },
68
+ loggedIn: {
69
+ meta: {
70
+ route: "/dashboard",
71
+ view: {
72
+ component: "Dashboard",
73
+ props: { welcome: true },
74
+ },
75
+ },
76
+ // Always-guard validates state entry
77
+ always: [
78
+ {
79
+ target: "loggedOut",
80
+ guard: ({ context }) => !context.isAuthenticated,
81
+ },
82
+ ],
83
+ on: {
84
+ "auth.logout": {
85
+ target: "loggedOut",
86
+ actions: assign({
87
+ isAuthenticated: false,
88
+ username: null,
89
+ }),
90
+ },
91
+ },
92
+ },
93
+ },
94
+ });
95
+ ```
96
+
97
+ **Why It's Unchanged:**
98
+
99
+ - No React imports - machine is pure XState
100
+ - View structure in `meta.view` is plain data
101
+ - Component names are strings, not JSX imports
102
+ - Guards, actions, context are framework-agnostic
103
+
104
+ ---
105
+
106
+ ### 2. Component Catalog (100% Unchanged)
107
+
108
+ ```typescript
109
+ // src/machines/catalog.ts - IDENTICAL for React, Vue, Svelte
110
+ import { z } from "zod";
111
+ import { defineCatalog } from "@xmachines/play-catalog";
112
+
113
+ export const catalog = defineCatalog({
114
+ LoginForm: z.object({
115
+ title: z.string(),
116
+ }),
117
+ Dashboard: z.object({
118
+ welcome: z.boolean(),
119
+ }),
120
+ });
121
+ ```
122
+
123
+ **Why It's Unchanged:**
124
+
125
+ - No React imports - catalog uses Zod schemas
126
+ - Props are plain data structures
127
+ - Zod validation is framework-agnostic
128
+
129
+ ---
130
+
131
+ ### 3. Router Integration (100% Unchanged)
132
+
133
+ ```typescript
134
+ // Integration code - IDENTICAL for React, Vue, Svelte
135
+ import { definePlayer } from "@xmachines/play-xstate";
136
+ import { createPlayRouter } from "@xmachines/play-tanstack-react-router";
137
+
138
+ const createPlayer = definePlayer({
139
+ machine: authMachine,
140
+ catalog,
141
+ });
142
+
143
+ const actor = createPlayer();
144
+ actor.start();
145
+
146
+ const router = createPlayRouter({ actor });
147
+ ```
148
+
149
+ **Why It's Unchanged:**
150
+
151
+ - `definePlayer` is framework-agnostic
152
+ - `createPlayRouter` observes actor signals, doesn't care about view framework
153
+ - Router sync happens via signals, not React-specific hooks
154
+
155
+ ---
156
+
157
+ ## Vue Example
158
+
159
+ ### Installing Vue Renderer (Future)
160
+
161
+ ```bash
162
+ npm install @xmachines/play-vue vue
163
+ ```
164
+
165
+ ### Vue LoginForm Component
166
+
167
+ ```vue
168
+ <!-- src/components/LoginForm.vue -->
169
+ <script setup lang="ts">
170
+ import { ref } from "vue";
171
+
172
+ // Props from catalog
173
+ interface Props {
174
+ send: (event: any) => void;
175
+ title: string;
176
+ }
177
+
178
+ const props = defineProps<Props>();
179
+
180
+ // Local UI state ONLY (not business logic)
181
+ const username = ref("");
182
+ const password = ref("");
183
+
184
+ const handleSubmit = () => {
185
+ // Passive Infrastructure: Forward event to actor
186
+ props.send({
187
+ type: "auth.login",
188
+ username: username.value,
189
+ password: password.value,
190
+ });
191
+ };
192
+ </script>
193
+
194
+ <template>
195
+ <div style="max-width: 400px; margin: 50px auto; padding: 20px">
196
+ <h1>{{ title }}</h1>
197
+ <form @submit.prevent="handleSubmit">
198
+ <div style="margin-bottom: 15px">
199
+ <label for="username" style="display: block; margin-bottom: 5px"> Username </label>
200
+ <input
201
+ type="text"
202
+ id="username"
203
+ v-model="username"
204
+ style="width: 100%; padding: 8px; font-size: 16px"
205
+ required
206
+ />
207
+ </div>
208
+ <div style="margin-bottom: 15px">
209
+ <label for="password" style="display: block; margin-bottom: 5px"> Password </label>
210
+ <input
211
+ type="password"
212
+ id="password"
213
+ v-model="password"
214
+ style="width: 100%; padding: 8px; font-size: 16px"
215
+ required
216
+ />
217
+ </div>
218
+ <button
219
+ type="submit"
220
+ style="
221
+ width: 100%;
222
+ padding: 10px;
223
+ font-size: 16px;
224
+ background-color: #007bff;
225
+ color: white;
226
+ border: none;
227
+ border-radius: 4px;
228
+ cursor: pointer;
229
+ "
230
+ >
231
+ Log In
232
+ </button>
233
+ </form>
234
+ <p style="margin-top: 15px; font-size: 14px; color: #666">
235
+ Demo credentials: any username/password
236
+ </p>
237
+ </div>
238
+ </template>
239
+ ```
240
+
241
+ **Key Similarities to React:**
242
+
243
+ - Component receives `send` function via props (same interface)
244
+ - Component forwards `auth.login` event (same event structure)
245
+ - Local form state managed by Vue (`ref` instead of `useState`)
246
+ - Business logic remains in actor - component just forwards events
247
+
248
+ ---
249
+
250
+ ### Vue Dashboard Component
251
+
252
+ ```vue
253
+ <!-- src/components/Dashboard.vue -->
254
+ <script setup lang="ts">
255
+ interface Props {
256
+ send: (event: any) => void;
257
+ welcome: boolean;
258
+ }
259
+
260
+ const props = defineProps<Props>();
261
+
262
+ const handleLogout = () => {
263
+ // Passive Infrastructure: Forward event to actor
264
+ props.send({ type: "auth.logout" });
265
+ };
266
+ </script>
267
+
268
+ <template>
269
+ <div style="max-width: 800px; margin: 50px auto; padding: 20px">
270
+ <h1 v-if="welcome" style="margin-bottom: 20px">Welcome to the Dashboard!</h1>
271
+ <div style="margin-bottom: 20px">
272
+ <p style="font-size: 16px; line-height: 1.6">
273
+ This is a protected route - you can only see this because you're logged in.
274
+ </p>
275
+ <p style="font-size: 16px; line-height: 1.6; margin-top: 10px">
276
+ The authentication machine's guard protects this route from logged-out users,
277
+ demonstrating the <strong>Actor Authority</strong> invariant.
278
+ </p>
279
+ </div>
280
+ <button
281
+ @click="handleLogout"
282
+ style="
283
+ padding: 10px 20px;
284
+ font-size: 16px;
285
+ background-color: #dc3545;
286
+ color: white;
287
+ border: none;
288
+ border-radius: 4px;
289
+ cursor: pointer;
290
+ "
291
+ >
292
+ Logout
293
+ </button>
294
+ </div>
295
+ </template>
296
+ ```
297
+
298
+ ---
299
+
300
+ ### Vue App Integration
301
+
302
+ ```typescript
303
+ // src/App.vue
304
+ <script setup lang="ts">
305
+ import { definePlayer } from "@xmachines/play-xstate";
306
+ import { createPlayRouter } from "@xmachines/play-tanstack-react-router";
307
+ import { PlayRenderer } from "@xmachines/play-vue"; // Vue renderer
308
+ import { defineComponents } from "@xmachines/play-catalog";
309
+ import { authMachine } from "./machines/auth-machine";
310
+ import { catalog } from "./machines/catalog";
311
+ import LoginForm from "./components/LoginForm.vue";
312
+ import Dashboard from "./components/Dashboard.vue";
313
+
314
+ // Define component implementations
315
+ const components = defineComponents(catalog, {
316
+ LoginForm,
317
+ Dashboard,
318
+ });
319
+
320
+ // Create player factory
321
+ const createPlayer = definePlayer({
322
+ machine: authMachine,
323
+ catalog,
324
+ });
325
+
326
+ // Create actor instance
327
+ const actor = createPlayer();
328
+ actor.start();
329
+
330
+ // Create router
331
+ const router = createPlayRouter({ actor });
332
+ </script>
333
+
334
+ <template>
335
+ <!-- PlayRenderer uses Vue's reactivity system to observe actor signals -->
336
+ <PlayRenderer :actor="actor" :components="components" />
337
+ </template>
338
+ ```
339
+
340
+ **Key Changes from React:**
341
+
342
+ - Import `@xmachines/play-vue` instead of `@xmachines/play-react`
343
+ - Component files are `.vue` instead of `.tsx`
344
+ - Vue template syntax (`v-model`, `@click`) instead of JSX
345
+
346
+ **What Stayed the Same:**
347
+
348
+ - `definePlayer({ machine, catalog })` - identical
349
+ - `createPlayRouter({ actor })` - identical
350
+ - Business logic in `authMachine` - unchanged
351
+ - Component prop interface (`send`, `title`, `welcome`) - identical
352
+
353
+ ---
354
+
355
+ ## Svelte Example
356
+
357
+ ### Installing Svelte Renderer (Future)
358
+
359
+ ```bash
360
+ npm install @xmachines/play-svelte svelte
361
+ ```
362
+
363
+ ### Svelte LoginForm Component
364
+
365
+ ```svelte
366
+ <!-- src/components/LoginForm.svelte -->
367
+ <script lang="ts">
368
+ // Props from catalog
369
+ export let send: (event: any) => void;
370
+ export let title: string;
371
+
372
+ // Local UI state ONLY (not business logic)
373
+ let username = "";
374
+ let password = "";
375
+
376
+ const handleSubmit = (e: Event) => {
377
+ e.preventDefault();
378
+
379
+ // Passive Infrastructure: Forward event to actor
380
+ send({
381
+ type: "auth.login",
382
+ username,
383
+ password,
384
+ });
385
+ };
386
+ </script>
387
+
388
+ <div style="max-width: 400px; margin: 50px auto; padding: 20px">
389
+ <h1>{title}</h1>
390
+ <form on:submit={handleSubmit}>
391
+ <div style="margin-bottom: 15px">
392
+ <label for="username" style="display: block; margin-bottom: 5px">
393
+ Username
394
+ </label>
395
+ <input
396
+ type="text"
397
+ id="username"
398
+ bind:value={username}
399
+ style="width: 100%; padding: 8px; font-size: 16px"
400
+ required
401
+ />
402
+ </div>
403
+ <div style="margin-bottom: 15px">
404
+ <label for="password" style="display: block; margin-bottom: 5px">
405
+ Password
406
+ </label>
407
+ <input
408
+ type="password"
409
+ id="password"
410
+ bind:value={password}
411
+ style="width: 100%; padding: 8px; font-size: 16px"
412
+ required
413
+ />
414
+ </div>
415
+ <button
416
+ type="submit"
417
+ style="width: 100%; padding: 10px; font-size: 16px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer;"
418
+ >
419
+ Log In
420
+ </button>
421
+ </form>
422
+ <p style="margin-top: 15px; font-size: 14px; color: #666">
423
+ Demo credentials: any username/password
424
+ </p>
425
+ </div>
426
+ ```
427
+
428
+ **Key Similarities to React/Vue:**
429
+
430
+ - Component receives `send` function via props (same interface)
431
+ - Component forwards `auth.login` event (same event structure)
432
+ - Local form state managed by Svelte (`let` instead of `useState`/`ref`)
433
+ - Business logic remains in actor - component just forwards events
434
+
435
+ ---
436
+
437
+ ### Svelte Dashboard Component
438
+
439
+ ```svelte
440
+ <!-- src/components/Dashboard.svelte -->
441
+ <script lang="ts">
442
+ export let send: (event: any) => void;
443
+ export let welcome: boolean;
444
+
445
+ const handleLogout = () => {
446
+ // Passive Infrastructure: Forward event to actor
447
+ send({ type: "auth.logout" });
448
+ };
449
+ </script>
450
+
451
+ <div style="max-width: 800px; margin: 50px auto; padding: 20px">
452
+ {#if welcome}
453
+ <h1 style="margin-bottom: 20px">Welcome to the Dashboard!</h1>
454
+ {/if}
455
+ <div style="margin-bottom: 20px">
456
+ <p style="font-size: 16px; line-height: 1.6">
457
+ This is a protected route - you can only see this because you're logged
458
+ in.
459
+ </p>
460
+ <p style="font-size: 16px; line-height: 1.6; margin-top: 10px">
461
+ The authentication machine's guard protects this route from logged-out
462
+ users, demonstrating the <strong>Actor Authority</strong> invariant.
463
+ </p>
464
+ </div>
465
+ <button
466
+ on:click={handleLogout}
467
+ style="padding: 10px 20px; font-size: 16px; background-color: #dc3545; color: white; border: none; border-radius: 4px; cursor: pointer;"
468
+ >
469
+ Logout
470
+ </button>
471
+ </div>
472
+ ```
473
+
474
+ ---
475
+
476
+ ### Svelte App Integration
477
+
478
+ ```svelte
479
+ <!-- src/App.svelte -->
480
+ <script lang="ts">
481
+ import { definePlayer } from "@xmachines/play-xstate";
482
+ import { createPlayRouter } from "@xmachines/play-tanstack-react-router";
483
+ import { PlayRenderer } from "@xmachines/play-svelte"; // Svelte renderer
484
+ import { defineComponents } from "@xmachines/play-catalog";
485
+ import { authMachine } from "./machines/auth-machine";
486
+ import { catalog } from "./machines/catalog";
487
+ import LoginForm from "./components/LoginForm.svelte";
488
+ import Dashboard from "./components/Dashboard.svelte";
489
+
490
+ // Define component implementations
491
+ const components = defineComponents(catalog, {
492
+ LoginForm,
493
+ Dashboard,
494
+ });
495
+
496
+ // Create player factory
497
+ const createPlayer = definePlayer({
498
+ machine: authMachine,
499
+ catalog,
500
+ });
501
+
502
+ // Create actor instance
503
+ const actor = createPlayer();
504
+ actor.start();
505
+
506
+ // Create router
507
+ const router = createPlayRouter({ actor });
508
+ </script>
509
+
510
+ <!-- PlayRenderer uses Svelte stores to observe actor signals -->
511
+ <PlayRenderer {actor} {components} />
512
+ ```
513
+
514
+ **Key Changes from React/Vue:**
515
+
516
+ - Import `@xmachines/play-svelte` instead of `@xmachines/play-react`
517
+ - Component files are `.svelte` instead of `.tsx`/`.vue`
518
+ - Svelte template syntax (`bind:value`, `on:click`) instead of JSX/Vue
519
+
520
+ **What Stayed the Same:**
521
+
522
+ - `definePlayer({ machine, catalog })` - identical
523
+ - `createPlayRouter({ actor })` - identical
524
+ - Business logic in `authMachine` - unchanged
525
+ - Component prop interface (`send`, `title`, `welcome`) - identical
526
+
527
+ ---
528
+
529
+ ## Why This Works
530
+
531
+ ### 1. Strict Separation Invariant
532
+
533
+ **Business logic has zero framework imports.**
534
+
535
+ `auth-machine.ts` and `catalog.ts` have no React, Vue, or Svelte imports. They use XState and Zod - both framework-agnostic libraries.
536
+
537
+ **Verification:**
538
+
539
+ ```bash
540
+ grep -rn "from ['\"']react\|from ['\"']vue\|from ['\"']svelte" src/machines/
541
+ # Expected: no output (zero framework imports)
542
+ ```
543
+
544
+ ---
545
+
546
+ ### 2. Signal-Only Reactivity Invariant
547
+
548
+ **Business state lives in actor signals, not framework-specific state.**
549
+
550
+ - React: `useSignalEffect` observes `actor.state` signal
551
+ - Vue: Vue's reactivity system observes `actor.state` signal via `watchEffect`
552
+ - Svelte: Svelte stores observe `actor.state` signal via `derived`
553
+
554
+ All three frameworks observe the **same signal** - the actor's state signal. Framework-specific reactivity is only for rendering, not business logic.
555
+
556
+ ---
557
+
558
+ ### 3. Passive Infrastructure Invariant
559
+
560
+ **Components forward events via `send()`, don't control navigation.**
561
+
562
+ All three implementations:
563
+
564
+ ```typescript
565
+ // React
566
+ send({ type: "auth.login", username, password });
567
+
568
+ // Vue
569
+ props.send({ type: "auth.login", username: username.value, password: password.value });
570
+
571
+ // Svelte
572
+ send({ type: "auth.login", username, password });
573
+ ```
574
+
575
+ Same event structure. Same `send` function interface. Actor processes event identically regardless of framework.
576
+
577
+ ---
578
+
579
+ ### 4. meta.view Pattern
580
+
581
+ **View structure defined in metadata, not framework-specific code.**
582
+
583
+ ```typescript
584
+ meta: {
585
+ view: {
586
+ component: "LoginForm", // String reference
587
+ props: { title: "Please Log In" },
588
+ },
589
+ }
590
+ ```
591
+
592
+ - React renderer resolves `"LoginForm"` → `LoginForm.tsx`
593
+ - Vue renderer resolves `"LoginForm"` → `LoginForm.vue`
594
+ - Svelte renderer resolves `"LoginForm"` → `LoginForm.svelte`
595
+
596
+ Same metadata structure. Framework-specific resolution happens at runtime by renderer.
597
+
598
+ ---
599
+
600
+ ## Summary
601
+
602
+ ### What Changes
603
+
604
+ | Item | React | Vue | Svelte |
605
+ | ---------------- | ----------------------- | --------------------- | ------------------------ |
606
+ | Renderer package | `@xmachines/play-react` | `@xmachines/play-vue` | `@xmachines/play-svelte` |
607
+ | Component files | `.tsx` | `.vue` | `.svelte` |
608
+ | Template syntax | JSX | Vue templates | Svelte templates |
609
+ | Local state | `useState` | `ref` | `let` |
610
+
611
+ ### What Stays the Same (100% Unchanged)
612
+
613
+ - ✅ State machine definition (`auth-machine.ts`)
614
+ - ✅ Component catalog (`catalog.ts`)
615
+ - ✅ Guards, actions, context
616
+ - ✅ Event types (`auth.login`, `auth.logout`, `play.route`)
617
+ - ✅ Component prop interface (`send`, `title`, `welcome`)
618
+ - ✅ Router integration (`createPlayRouter`)
619
+ - ✅ Business logic, validation, authentication flow
620
+
621
+ ---
622
+
623
+ ## Try It Yourself
624
+
625
+ 1. **Clone this demo** and verify React works
626
+ 2. **Implement Vue components** following patterns above
627
+ 3. **Swap renderer** in `App.vue`
628
+ 4. **Run `npm run dev`** - everything works!
629
+ 5. **Verify tests still pass** - invariants proven
630
+
631
+ **Result:** Business logic unchanged. Framework swap complete.
632
+
633
+ ---
634
+
635
+ **Questions?** Read [ARCHITECTURE.md](./ARCHITECTURE.md) for line-by-line code walkthrough or the RFC specification for invariant explanations.
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>XMachines Play - React Demo</title>
7
+ <meta
8
+ name="description"
9
+ content="Universal Player Architecture demonstration with authentication flow"
10
+ />
11
+ </head>
12
+ <body>
13
+ <div id="root"></div>
14
+ <script type="module" src="/src/main.tsx"></script>
15
+ </body>
16
+ </html>
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@xmachines/play-tanstack-react-router-demo",
3
+ "version": "1.0.0-beta.1",
4
+ "private": true,
5
+ "description": "Universal Player Architecture demonstration with authentication flow",
6
+ "type": "module",
7
+ "scripts": {
8
+ "dev": "vite",
9
+ "build": "vite build",
10
+ "preview": "vite preview",
11
+ "test": "vitest run",
12
+ "test:vitest": "vitest run",
13
+ "test:browser": "NODE_OPTIONS='--max-old-space-size=8192' vitest run --config vitest.config.e2e.browser.ts",
14
+ "test:browser:full": "NODE_OPTIONS='--max-old-space-size=8192' vitest run --config vitest.browser.config.ts",
15
+ "test:e2e": "npm run test:browser"
16
+ },
17
+ "dependencies": {
18
+ "@tanstack/react-router": "^1.166.7",
19
+ "@xmachines/play": "1.0.0-beta.1",
20
+ "@xmachines/play-catalog": "1.0.0-beta.1",
21
+ "@xmachines/play-react": "1.0.0-beta.1",
22
+ "@xmachines/play-router": "1.0.0-beta.1",
23
+ "@xmachines/play-router-shared": "1.0.0-beta.1",
24
+ "@xmachines/play-tanstack-react-router": "1.0.0-beta.1",
25
+ "@xmachines/play-xstate": "1.0.0-beta.1",
26
+ "react": "^19.0.0",
27
+ "react-dom": "^19.0.0",
28
+ "xstate": "^5.28.0",
29
+ "zod": "^4.3.6"
30
+ },
31
+ "devDependencies": {
32
+ "@types/react": "^19.0.0",
33
+ "@types/react-dom": "^19.0.0",
34
+ "@vitejs/plugin-react": "^5.1.4",
35
+ "jsdom": "^28.1.0",
36
+ "typescript": "^5.7.0",
37
+ "vite": "^7.3.1"
38
+ }
39
+ }