hbengine 0.2.3

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 (561) hide show
  1. package/README.md +20 -0
  2. package/engine-cli/connect.mjs +73 -0
  3. package/engine-cli/hbengine.mjs +565 -0
  4. package/engine-cli/package.json +1 -0
  5. package/engine-cli/templates.mjs +14 -0
  6. package/engine-conformance/analyse-worker.mjs +12 -0
  7. package/engine-conformance/analyse.mjs +4458 -0
  8. package/engine-conformance/bundle.mjs +208 -0
  9. package/engine-conformance/clock.mjs +294 -0
  10. package/engine-conformance/csp.go +56 -0
  11. package/engine-conformance/csp.json +6 -0
  12. package/engine-conformance/csp.mjs +20 -0
  13. package/engine-conformance/gzip-sizes.mjs +9 -0
  14. package/engine-conformance/package.json +1 -0
  15. package/engine-conformance/picture.mjs +55 -0
  16. package/engine-conformance/report.go +349 -0
  17. package/engine-conformance/run.mjs +1217 -0
  18. package/engine-conformance/scan.mjs +476 -0
  19. package/engine-conformance/testdata/clock-overlay/bundle/assets.json +1 -0
  20. package/engine-conformance/testdata/clock-overlay/bundle/game.css +17 -0
  21. package/engine-conformance/testdata/clock-overlay/bundle/game.js +83 -0
  22. package/engine-conformance/testdata/clock-overlay/bundle/hbtest.json +4 -0
  23. package/engine-conformance/testdata/clock-overlay/bundle/index.html +34 -0
  24. package/engine-conformance/testdata/clock-probe/bundle/assets.json +1 -0
  25. package/engine-conformance/testdata/clock-probe/bundle/game.css +17 -0
  26. package/engine-conformance/testdata/clock-probe/bundle/game.js +65 -0
  27. package/engine-conformance/testdata/clock-probe/bundle/hbtest.json +4 -0
  28. package/engine-conformance/testdata/clock-probe/bundle/index.html +35 -0
  29. package/engine-conformance/testdata/clock-probe/bundle/probe-worker.js +46 -0
  30. package/engine-conformance/testdata/clock-probe/bundle/probe.js +210 -0
  31. package/engine-conformance/testdata/clock-probe/math/dice.tsv +100 -0
  32. package/engine-conformance/testdata/clock-probe/math/manifest.json +2925 -0
  33. package/engine-conformance/testdata/clock-worker/bundle/assets.json +1 -0
  34. package/engine-conformance/testdata/clock-worker/bundle/clock-worker.js +14 -0
  35. package/engine-conformance/testdata/clock-worker/bundle/game.css +17 -0
  36. package/engine-conformance/testdata/clock-worker/bundle/game.js +61 -0
  37. package/engine-conformance/testdata/clock-worker/bundle/hbtest.json +4 -0
  38. package/engine-conformance/testdata/clock-worker/bundle/index.html +35 -0
  39. package/engine-conformance/testdata/clock-worker/math/dice.tsv +100 -0
  40. package/engine-conformance/testdata/clock-worker/math/manifest.json +2925 -0
  41. package/engine-conformance/travel.mjs +1209 -0
  42. package/engine-conformance/vendor/acorn/LICENSE +21 -0
  43. package/engine-conformance/vendor/acorn/acorn.mjs +6266 -0
  44. package/engine-conformance/wasm-releases.json +168 -0
  45. package/engine-examples/README.md +23 -0
  46. package/engine-examples/coin/AGENTS.md +3 -0
  47. package/engine-examples/coin/README.md +7 -0
  48. package/engine-examples/coin/bundle/assets.json +1 -0
  49. package/engine-examples/coin/bundle/game.css +5 -0
  50. package/engine-examples/coin/bundle/game.js +19 -0
  51. package/engine-examples/coin/bundle/hbtest.json +5 -0
  52. package/engine-examples/coin/bundle/index.html +16 -0
  53. package/engine-examples/coin/math/coin.tsv +2 -0
  54. package/engine-examples/coin/math/manifest.json +17 -0
  55. package/engine-examples/crash/AGENTS.md +3 -0
  56. package/engine-examples/crash/README.md +14 -0
  57. package/engine-examples/crash/bundle/assets.json +1 -0
  58. package/engine-examples/crash/bundle/game.css +8 -0
  59. package/engine-examples/crash/bundle/game.js +90 -0
  60. package/engine-examples/crash/bundle/hbtest.json +5 -0
  61. package/engine-examples/crash/bundle/index.html +20 -0
  62. package/engine-examples/crash/math/crash-01.tsv +2 -0
  63. package/engine-examples/crash/math/crash-02.tsv +2 -0
  64. package/engine-examples/crash/math/crash-03.tsv +2 -0
  65. package/engine-examples/crash/math/crash-04.tsv +2 -0
  66. package/engine-examples/crash/math/crash-05.tsv +2 -0
  67. package/engine-examples/crash/math/crash-06.tsv +2 -0
  68. package/engine-examples/crash/math/crash-07.tsv +2 -0
  69. package/engine-examples/crash/math/crash-08.tsv +2 -0
  70. package/engine-examples/crash/math/crash-09.tsv +2 -0
  71. package/engine-examples/crash/math/crash-10.tsv +2 -0
  72. package/engine-examples/crash/math/crash-11.tsv +2 -0
  73. package/engine-examples/crash/math/crash-12.tsv +2 -0
  74. package/engine-examples/crash/math/crash-13.tsv +2 -0
  75. package/engine-examples/crash/math/crash-14.tsv +2 -0
  76. package/engine-examples/crash/math/crash-15.tsv +2 -0
  77. package/engine-examples/crash/math/crash-16.tsv +2 -0
  78. package/engine-examples/crash/math/crash-17.tsv +2 -0
  79. package/engine-examples/crash/math/crash-18.tsv +2 -0
  80. package/engine-examples/crash/math/crash-19.tsv +2 -0
  81. package/engine-examples/crash/math/crash-20.tsv +2 -0
  82. package/engine-examples/crash/math/crash-21.tsv +2 -0
  83. package/engine-examples/crash/math/crash-22.tsv +2 -0
  84. package/engine-examples/crash/math/crash-23.tsv +2 -0
  85. package/engine-examples/crash/math/crash-24.tsv +2 -0
  86. package/engine-examples/crash/math/crash-25.tsv +2 -0
  87. package/engine-examples/crash/math/crash-26.tsv +2 -0
  88. package/engine-examples/crash/math/crash-27.tsv +2 -0
  89. package/engine-examples/crash/math/crash-28.tsv +2 -0
  90. package/engine-examples/crash/math/crash-29.tsv +2 -0
  91. package/engine-examples/crash/math/crash-30.tsv +2 -0
  92. package/engine-examples/crash/math/crash-31.tsv +2 -0
  93. package/engine-examples/crash/math/crash-32.tsv +2 -0
  94. package/engine-examples/crash/math/crash-33.tsv +2 -0
  95. package/engine-examples/crash/math/crash-34.tsv +2 -0
  96. package/engine-examples/crash/math/crash-35.tsv +2 -0
  97. package/engine-examples/crash/math/crash-36.tsv +2 -0
  98. package/engine-examples/crash/math/crash-37.tsv +2 -0
  99. package/engine-examples/crash/math/crash-38.tsv +2 -0
  100. package/engine-examples/crash/math/crash-39.tsv +2 -0
  101. package/engine-examples/crash/math/crash-40.tsv +2 -0
  102. package/engine-examples/crash/math/crash-41.tsv +2 -0
  103. package/engine-examples/crash/math/crash-42.tsv +2 -0
  104. package/engine-examples/crash/math/crash-43.tsv +2 -0
  105. package/engine-examples/crash/math/crash-44.tsv +2 -0
  106. package/engine-examples/crash/math/crash-45.tsv +2 -0
  107. package/engine-examples/crash/math/crash-46.tsv +2 -0
  108. package/engine-examples/crash/math/crash-47.tsv +2 -0
  109. package/engine-examples/crash/math/crash-48.tsv +2 -0
  110. package/engine-examples/crash/math/crash-49.tsv +2 -0
  111. package/engine-examples/crash/math/crash-50.tsv +2 -0
  112. package/engine-examples/crash/math/crash-51.tsv +2 -0
  113. package/engine-examples/crash/math/crash-52.tsv +2 -0
  114. package/engine-examples/crash/math/crash-53.tsv +2 -0
  115. package/engine-examples/crash/math/crash-54.tsv +2 -0
  116. package/engine-examples/crash/math/crash-55.tsv +2 -0
  117. package/engine-examples/crash/math/crash-56.tsv +2 -0
  118. package/engine-examples/crash/math/crash-57.tsv +2 -0
  119. package/engine-examples/crash/math/crash-58.tsv +2 -0
  120. package/engine-examples/crash/math/crash-59.tsv +2 -0
  121. package/engine-examples/crash/math/crash-60.tsv +2 -0
  122. package/engine-examples/crash/math/crash-61.tsv +2 -0
  123. package/engine-examples/crash/math/crash-62.tsv +2 -0
  124. package/engine-examples/crash/math/crash-63.tsv +2 -0
  125. package/engine-examples/crash/math/crash-64.tsv +2 -0
  126. package/engine-examples/crash/math/gen.mjs +31 -0
  127. package/engine-examples/crash/math/manifest.json +1 -0
  128. package/engine-examples/dice/AGENTS.md +3 -0
  129. package/engine-examples/dice/README.md +25 -0
  130. package/engine-examples/dice/bundle/assets.json +1 -0
  131. package/engine-examples/dice/bundle/game.css +17 -0
  132. package/engine-examples/dice/bundle/game.js +61 -0
  133. package/engine-examples/dice/bundle/hbtest.json +4 -0
  134. package/engine-examples/dice/bundle/index.html +34 -0
  135. package/engine-examples/dice/math/dice.tsv +100 -0
  136. package/engine-examples/dice/math/manifest.json +2925 -0
  137. package/engine-examples/keno/AGENTS.md +3 -0
  138. package/engine-examples/keno/README.md +11 -0
  139. package/engine-examples/keno/bundle/assets.json +1 -0
  140. package/engine-examples/keno/bundle/game.css +14 -0
  141. package/engine-examples/keno/bundle/game.js +86 -0
  142. package/engine-examples/keno/bundle/hbtest.json +4 -0
  143. package/engine-examples/keno/bundle/i18n.json +342 -0
  144. package/engine-examples/keno/bundle/index.html +20 -0
  145. package/engine-examples/keno/bundle/model.json +1 -0
  146. package/engine-examples/keno/math/gen.mjs +35 -0
  147. package/engine-examples/keno/math/keno-picks-1.tsv +2 -0
  148. package/engine-examples/keno/math/keno-picks-10.tsv +11 -0
  149. package/engine-examples/keno/math/keno-picks-2.tsv +3 -0
  150. package/engine-examples/keno/math/keno-picks-3.tsv +4 -0
  151. package/engine-examples/keno/math/keno-picks-4.tsv +5 -0
  152. package/engine-examples/keno/math/keno-picks-5.tsv +6 -0
  153. package/engine-examples/keno/math/keno-picks-6.tsv +7 -0
  154. package/engine-examples/keno/math/keno-picks-7.tsv +8 -0
  155. package/engine-examples/keno/math/keno-picks-8.tsv +9 -0
  156. package/engine-examples/keno/math/keno-picks-9.tsv +10 -0
  157. package/engine-examples/keno/math/manifest.json +1 -0
  158. package/engine-examples/keno/math-kit/pack.mjs +165 -0
  159. package/engine-examples/keno/math-kit/package.json +8 -0
  160. package/engine-examples/keno/math-kit/slot.mjs +94 -0
  161. package/engine-examples/keno/math-kit/tumble.mjs +94 -0
  162. package/engine-examples/lines/AGENTS.md +3 -0
  163. package/engine-examples/lines/README.md +20 -0
  164. package/engine-examples/lines/bundle/assets.json +1 -0
  165. package/engine-examples/lines/bundle/game.css +16 -0
  166. package/engine-examples/lines/bundle/game.js +125 -0
  167. package/engine-examples/lines/bundle/hbtest.json +4 -0
  168. package/engine-examples/lines/bundle/i18n.json +242 -0
  169. package/engine-examples/lines/bundle/index.html +23 -0
  170. package/engine-examples/lines/bundle/model.json +1 -0
  171. package/engine-examples/lines/math/gen.mjs +54 -0
  172. package/engine-examples/lines/math-kit/pack.mjs +165 -0
  173. package/engine-examples/lines/math-kit/package.json +8 -0
  174. package/engine-examples/lines/math-kit/slot.mjs +94 -0
  175. package/engine-examples/lines/math-kit/tumble.mjs +94 -0
  176. package/engine-examples/mines/AGENTS.md +3 -0
  177. package/engine-examples/mines/README.md +13 -0
  178. package/engine-examples/mines/bundle/assets.json +1 -0
  179. package/engine-examples/mines/bundle/game.css +12 -0
  180. package/engine-examples/mines/bundle/game.js +58 -0
  181. package/engine-examples/mines/bundle/hbtest.json +8 -0
  182. package/engine-examples/mines/bundle/index.html +16 -0
  183. package/engine-examples/mines/math/gen.mjs +40 -0
  184. package/engine-examples/mines/math/manifest.json +1 -0
  185. package/engine-examples/mines/math/mines-1-1.tsv +2 -0
  186. package/engine-examples/mines/math/mines-1-2.tsv +2 -0
  187. package/engine-examples/mines/math/mines-1-22.tsv +2 -0
  188. package/engine-examples/mines/math/mines-1-23.tsv +2 -0
  189. package/engine-examples/mines/math/mines-1-24.tsv +2 -0
  190. package/engine-examples/mines/math/mines-1-3.tsv +2 -0
  191. package/engine-examples/mines/math/mines-10-1.tsv +2 -0
  192. package/engine-examples/mines/math/mines-10-10.tsv +2 -0
  193. package/engine-examples/mines/math/mines-10-11.tsv +2 -0
  194. package/engine-examples/mines/math/mines-10-12.tsv +2 -0
  195. package/engine-examples/mines/math/mines-10-13.tsv +2 -0
  196. package/engine-examples/mines/math/mines-10-14.tsv +2 -0
  197. package/engine-examples/mines/math/mines-10-15.tsv +2 -0
  198. package/engine-examples/mines/math/mines-10-2.tsv +2 -0
  199. package/engine-examples/mines/math/mines-10-3.tsv +2 -0
  200. package/engine-examples/mines/math/mines-10-4.tsv +2 -0
  201. package/engine-examples/mines/math/mines-10-5.tsv +2 -0
  202. package/engine-examples/mines/math/mines-10-6.tsv +2 -0
  203. package/engine-examples/mines/math/mines-10-7.tsv +2 -0
  204. package/engine-examples/mines/math/mines-10-8.tsv +2 -0
  205. package/engine-examples/mines/math/mines-10-9.tsv +2 -0
  206. package/engine-examples/mines/math/mines-11-1.tsv +2 -0
  207. package/engine-examples/mines/math/mines-11-10.tsv +2 -0
  208. package/engine-examples/mines/math/mines-11-11.tsv +2 -0
  209. package/engine-examples/mines/math/mines-11-12.tsv +2 -0
  210. package/engine-examples/mines/math/mines-11-13.tsv +2 -0
  211. package/engine-examples/mines/math/mines-11-14.tsv +2 -0
  212. package/engine-examples/mines/math/mines-11-2.tsv +2 -0
  213. package/engine-examples/mines/math/mines-11-3.tsv +2 -0
  214. package/engine-examples/mines/math/mines-11-4.tsv +2 -0
  215. package/engine-examples/mines/math/mines-11-5.tsv +2 -0
  216. package/engine-examples/mines/math/mines-11-6.tsv +2 -0
  217. package/engine-examples/mines/math/mines-11-7.tsv +2 -0
  218. package/engine-examples/mines/math/mines-11-8.tsv +2 -0
  219. package/engine-examples/mines/math/mines-11-9.tsv +2 -0
  220. package/engine-examples/mines/math/mines-12-1.tsv +2 -0
  221. package/engine-examples/mines/math/mines-12-10.tsv +2 -0
  222. package/engine-examples/mines/math/mines-12-11.tsv +2 -0
  223. package/engine-examples/mines/math/mines-12-12.tsv +2 -0
  224. package/engine-examples/mines/math/mines-12-13.tsv +2 -0
  225. package/engine-examples/mines/math/mines-12-2.tsv +2 -0
  226. package/engine-examples/mines/math/mines-12-3.tsv +2 -0
  227. package/engine-examples/mines/math/mines-12-4.tsv +2 -0
  228. package/engine-examples/mines/math/mines-12-5.tsv +2 -0
  229. package/engine-examples/mines/math/mines-12-6.tsv +2 -0
  230. package/engine-examples/mines/math/mines-12-7.tsv +2 -0
  231. package/engine-examples/mines/math/mines-12-8.tsv +2 -0
  232. package/engine-examples/mines/math/mines-12-9.tsv +2 -0
  233. package/engine-examples/mines/math/mines-13-1.tsv +2 -0
  234. package/engine-examples/mines/math/mines-13-10.tsv +2 -0
  235. package/engine-examples/mines/math/mines-13-11.tsv +2 -0
  236. package/engine-examples/mines/math/mines-13-12.tsv +2 -0
  237. package/engine-examples/mines/math/mines-13-2.tsv +2 -0
  238. package/engine-examples/mines/math/mines-13-3.tsv +2 -0
  239. package/engine-examples/mines/math/mines-13-4.tsv +2 -0
  240. package/engine-examples/mines/math/mines-13-5.tsv +2 -0
  241. package/engine-examples/mines/math/mines-13-6.tsv +2 -0
  242. package/engine-examples/mines/math/mines-13-7.tsv +2 -0
  243. package/engine-examples/mines/math/mines-13-8.tsv +2 -0
  244. package/engine-examples/mines/math/mines-13-9.tsv +2 -0
  245. package/engine-examples/mines/math/mines-14-1.tsv +2 -0
  246. package/engine-examples/mines/math/mines-14-10.tsv +2 -0
  247. package/engine-examples/mines/math/mines-14-11.tsv +2 -0
  248. package/engine-examples/mines/math/mines-14-2.tsv +2 -0
  249. package/engine-examples/mines/math/mines-14-3.tsv +2 -0
  250. package/engine-examples/mines/math/mines-14-4.tsv +2 -0
  251. package/engine-examples/mines/math/mines-14-5.tsv +2 -0
  252. package/engine-examples/mines/math/mines-14-6.tsv +2 -0
  253. package/engine-examples/mines/math/mines-14-7.tsv +2 -0
  254. package/engine-examples/mines/math/mines-14-8.tsv +2 -0
  255. package/engine-examples/mines/math/mines-14-9.tsv +2 -0
  256. package/engine-examples/mines/math/mines-15-1.tsv +2 -0
  257. package/engine-examples/mines/math/mines-15-10.tsv +2 -0
  258. package/engine-examples/mines/math/mines-15-2.tsv +2 -0
  259. package/engine-examples/mines/math/mines-15-3.tsv +2 -0
  260. package/engine-examples/mines/math/mines-15-4.tsv +2 -0
  261. package/engine-examples/mines/math/mines-15-5.tsv +2 -0
  262. package/engine-examples/mines/math/mines-15-6.tsv +2 -0
  263. package/engine-examples/mines/math/mines-15-7.tsv +2 -0
  264. package/engine-examples/mines/math/mines-15-8.tsv +2 -0
  265. package/engine-examples/mines/math/mines-15-9.tsv +2 -0
  266. package/engine-examples/mines/math/mines-16-1.tsv +2 -0
  267. package/engine-examples/mines/math/mines-16-2.tsv +2 -0
  268. package/engine-examples/mines/math/mines-16-3.tsv +2 -0
  269. package/engine-examples/mines/math/mines-16-4.tsv +2 -0
  270. package/engine-examples/mines/math/mines-16-5.tsv +2 -0
  271. package/engine-examples/mines/math/mines-16-6.tsv +2 -0
  272. package/engine-examples/mines/math/mines-16-7.tsv +2 -0
  273. package/engine-examples/mines/math/mines-16-8.tsv +2 -0
  274. package/engine-examples/mines/math/mines-16-9.tsv +2 -0
  275. package/engine-examples/mines/math/mines-17-1.tsv +2 -0
  276. package/engine-examples/mines/math/mines-17-2.tsv +2 -0
  277. package/engine-examples/mines/math/mines-17-3.tsv +2 -0
  278. package/engine-examples/mines/math/mines-17-4.tsv +2 -0
  279. package/engine-examples/mines/math/mines-17-5.tsv +2 -0
  280. package/engine-examples/mines/math/mines-17-6.tsv +2 -0
  281. package/engine-examples/mines/math/mines-17-7.tsv +2 -0
  282. package/engine-examples/mines/math/mines-17-8.tsv +2 -0
  283. package/engine-examples/mines/math/mines-18-1.tsv +2 -0
  284. package/engine-examples/mines/math/mines-18-2.tsv +2 -0
  285. package/engine-examples/mines/math/mines-18-3.tsv +2 -0
  286. package/engine-examples/mines/math/mines-18-4.tsv +2 -0
  287. package/engine-examples/mines/math/mines-18-5.tsv +2 -0
  288. package/engine-examples/mines/math/mines-18-6.tsv +2 -0
  289. package/engine-examples/mines/math/mines-18-7.tsv +2 -0
  290. package/engine-examples/mines/math/mines-19-1.tsv +2 -0
  291. package/engine-examples/mines/math/mines-19-2.tsv +2 -0
  292. package/engine-examples/mines/math/mines-19-3.tsv +2 -0
  293. package/engine-examples/mines/math/mines-19-4.tsv +2 -0
  294. package/engine-examples/mines/math/mines-19-5.tsv +2 -0
  295. package/engine-examples/mines/math/mines-19-6.tsv +2 -0
  296. package/engine-examples/mines/math/mines-2-1.tsv +2 -0
  297. package/engine-examples/mines/math/mines-2-19.tsv +2 -0
  298. package/engine-examples/mines/math/mines-2-2.tsv +2 -0
  299. package/engine-examples/mines/math/mines-2-20.tsv +2 -0
  300. package/engine-examples/mines/math/mines-2-21.tsv +2 -0
  301. package/engine-examples/mines/math/mines-2-22.tsv +2 -0
  302. package/engine-examples/mines/math/mines-2-23.tsv +2 -0
  303. package/engine-examples/mines/math/mines-2-3.tsv +2 -0
  304. package/engine-examples/mines/math/mines-2-4.tsv +2 -0
  305. package/engine-examples/mines/math/mines-2-5.tsv +2 -0
  306. package/engine-examples/mines/math/mines-20-1.tsv +2 -0
  307. package/engine-examples/mines/math/mines-20-2.tsv +2 -0
  308. package/engine-examples/mines/math/mines-20-3.tsv +2 -0
  309. package/engine-examples/mines/math/mines-20-4.tsv +2 -0
  310. package/engine-examples/mines/math/mines-20-5.tsv +2 -0
  311. package/engine-examples/mines/math/mines-21-1.tsv +2 -0
  312. package/engine-examples/mines/math/mines-21-2.tsv +2 -0
  313. package/engine-examples/mines/math/mines-21-3.tsv +2 -0
  314. package/engine-examples/mines/math/mines-21-4.tsv +2 -0
  315. package/engine-examples/mines/math/mines-22-1.tsv +2 -0
  316. package/engine-examples/mines/math/mines-22-2.tsv +2 -0
  317. package/engine-examples/mines/math/mines-22-3.tsv +2 -0
  318. package/engine-examples/mines/math/mines-23-1.tsv +2 -0
  319. package/engine-examples/mines/math/mines-23-2.tsv +2 -0
  320. package/engine-examples/mines/math/mines-24-1.tsv +2 -0
  321. package/engine-examples/mines/math/mines-3-1.tsv +2 -0
  322. package/engine-examples/mines/math/mines-3-17.tsv +2 -0
  323. package/engine-examples/mines/math/mines-3-18.tsv +2 -0
  324. package/engine-examples/mines/math/mines-3-19.tsv +2 -0
  325. package/engine-examples/mines/math/mines-3-2.tsv +2 -0
  326. package/engine-examples/mines/math/mines-3-20.tsv +2 -0
  327. package/engine-examples/mines/math/mines-3-21.tsv +2 -0
  328. package/engine-examples/mines/math/mines-3-22.tsv +2 -0
  329. package/engine-examples/mines/math/mines-3-3.tsv +2 -0
  330. package/engine-examples/mines/math/mines-3-4.tsv +2 -0
  331. package/engine-examples/mines/math/mines-3-5.tsv +2 -0
  332. package/engine-examples/mines/math/mines-3-6.tsv +2 -0
  333. package/engine-examples/mines/math/mines-4-1.tsv +2 -0
  334. package/engine-examples/mines/math/mines-4-13.tsv +2 -0
  335. package/engine-examples/mines/math/mines-4-14.tsv +2 -0
  336. package/engine-examples/mines/math/mines-4-15.tsv +2 -0
  337. package/engine-examples/mines/math/mines-4-16.tsv +2 -0
  338. package/engine-examples/mines/math/mines-4-17.tsv +2 -0
  339. package/engine-examples/mines/math/mines-4-18.tsv +2 -0
  340. package/engine-examples/mines/math/mines-4-19.tsv +2 -0
  341. package/engine-examples/mines/math/mines-4-2.tsv +2 -0
  342. package/engine-examples/mines/math/mines-4-20.tsv +2 -0
  343. package/engine-examples/mines/math/mines-4-21.tsv +2 -0
  344. package/engine-examples/mines/math/mines-4-3.tsv +2 -0
  345. package/engine-examples/mines/math/mines-4-4.tsv +2 -0
  346. package/engine-examples/mines/math/mines-4-5.tsv +2 -0
  347. package/engine-examples/mines/math/mines-4-6.tsv +2 -0
  348. package/engine-examples/mines/math/mines-4-7.tsv +2 -0
  349. package/engine-examples/mines/math/mines-4-8.tsv +2 -0
  350. package/engine-examples/mines/math/mines-4-9.tsv +2 -0
  351. package/engine-examples/mines/math/mines-5-1.tsv +2 -0
  352. package/engine-examples/mines/math/mines-5-10.tsv +2 -0
  353. package/engine-examples/mines/math/mines-5-11.tsv +2 -0
  354. package/engine-examples/mines/math/mines-5-12.tsv +2 -0
  355. package/engine-examples/mines/math/mines-5-13.tsv +2 -0
  356. package/engine-examples/mines/math/mines-5-14.tsv +2 -0
  357. package/engine-examples/mines/math/mines-5-15.tsv +2 -0
  358. package/engine-examples/mines/math/mines-5-16.tsv +2 -0
  359. package/engine-examples/mines/math/mines-5-17.tsv +2 -0
  360. package/engine-examples/mines/math/mines-5-18.tsv +2 -0
  361. package/engine-examples/mines/math/mines-5-19.tsv +2 -0
  362. package/engine-examples/mines/math/mines-5-2.tsv +2 -0
  363. package/engine-examples/mines/math/mines-5-20.tsv +2 -0
  364. package/engine-examples/mines/math/mines-5-3.tsv +2 -0
  365. package/engine-examples/mines/math/mines-5-4.tsv +2 -0
  366. package/engine-examples/mines/math/mines-5-5.tsv +2 -0
  367. package/engine-examples/mines/math/mines-5-6.tsv +2 -0
  368. package/engine-examples/mines/math/mines-5-7.tsv +2 -0
  369. package/engine-examples/mines/math/mines-5-8.tsv +2 -0
  370. package/engine-examples/mines/math/mines-5-9.tsv +2 -0
  371. package/engine-examples/mines/math/mines-6-1.tsv +2 -0
  372. package/engine-examples/mines/math/mines-6-10.tsv +2 -0
  373. package/engine-examples/mines/math/mines-6-11.tsv +2 -0
  374. package/engine-examples/mines/math/mines-6-12.tsv +2 -0
  375. package/engine-examples/mines/math/mines-6-13.tsv +2 -0
  376. package/engine-examples/mines/math/mines-6-14.tsv +2 -0
  377. package/engine-examples/mines/math/mines-6-15.tsv +2 -0
  378. package/engine-examples/mines/math/mines-6-16.tsv +2 -0
  379. package/engine-examples/mines/math/mines-6-17.tsv +2 -0
  380. package/engine-examples/mines/math/mines-6-18.tsv +2 -0
  381. package/engine-examples/mines/math/mines-6-19.tsv +2 -0
  382. package/engine-examples/mines/math/mines-6-2.tsv +2 -0
  383. package/engine-examples/mines/math/mines-6-3.tsv +2 -0
  384. package/engine-examples/mines/math/mines-6-4.tsv +2 -0
  385. package/engine-examples/mines/math/mines-6-5.tsv +2 -0
  386. package/engine-examples/mines/math/mines-6-6.tsv +2 -0
  387. package/engine-examples/mines/math/mines-6-7.tsv +2 -0
  388. package/engine-examples/mines/math/mines-6-8.tsv +2 -0
  389. package/engine-examples/mines/math/mines-6-9.tsv +2 -0
  390. package/engine-examples/mines/math/mines-7-1.tsv +2 -0
  391. package/engine-examples/mines/math/mines-7-10.tsv +2 -0
  392. package/engine-examples/mines/math/mines-7-11.tsv +2 -0
  393. package/engine-examples/mines/math/mines-7-12.tsv +2 -0
  394. package/engine-examples/mines/math/mines-7-13.tsv +2 -0
  395. package/engine-examples/mines/math/mines-7-14.tsv +2 -0
  396. package/engine-examples/mines/math/mines-7-15.tsv +2 -0
  397. package/engine-examples/mines/math/mines-7-16.tsv +2 -0
  398. package/engine-examples/mines/math/mines-7-17.tsv +2 -0
  399. package/engine-examples/mines/math/mines-7-18.tsv +2 -0
  400. package/engine-examples/mines/math/mines-7-2.tsv +2 -0
  401. package/engine-examples/mines/math/mines-7-3.tsv +2 -0
  402. package/engine-examples/mines/math/mines-7-4.tsv +2 -0
  403. package/engine-examples/mines/math/mines-7-5.tsv +2 -0
  404. package/engine-examples/mines/math/mines-7-6.tsv +2 -0
  405. package/engine-examples/mines/math/mines-7-7.tsv +2 -0
  406. package/engine-examples/mines/math/mines-7-8.tsv +2 -0
  407. package/engine-examples/mines/math/mines-7-9.tsv +2 -0
  408. package/engine-examples/mines/math/mines-8-1.tsv +2 -0
  409. package/engine-examples/mines/math/mines-8-10.tsv +2 -0
  410. package/engine-examples/mines/math/mines-8-11.tsv +2 -0
  411. package/engine-examples/mines/math/mines-8-12.tsv +2 -0
  412. package/engine-examples/mines/math/mines-8-13.tsv +2 -0
  413. package/engine-examples/mines/math/mines-8-14.tsv +2 -0
  414. package/engine-examples/mines/math/mines-8-15.tsv +2 -0
  415. package/engine-examples/mines/math/mines-8-16.tsv +2 -0
  416. package/engine-examples/mines/math/mines-8-17.tsv +2 -0
  417. package/engine-examples/mines/math/mines-8-2.tsv +2 -0
  418. package/engine-examples/mines/math/mines-8-3.tsv +2 -0
  419. package/engine-examples/mines/math/mines-8-4.tsv +2 -0
  420. package/engine-examples/mines/math/mines-8-5.tsv +2 -0
  421. package/engine-examples/mines/math/mines-8-6.tsv +2 -0
  422. package/engine-examples/mines/math/mines-8-7.tsv +2 -0
  423. package/engine-examples/mines/math/mines-8-8.tsv +2 -0
  424. package/engine-examples/mines/math/mines-8-9.tsv +2 -0
  425. package/engine-examples/mines/math/mines-9-1.tsv +2 -0
  426. package/engine-examples/mines/math/mines-9-10.tsv +2 -0
  427. package/engine-examples/mines/math/mines-9-11.tsv +2 -0
  428. package/engine-examples/mines/math/mines-9-12.tsv +2 -0
  429. package/engine-examples/mines/math/mines-9-13.tsv +2 -0
  430. package/engine-examples/mines/math/mines-9-14.tsv +2 -0
  431. package/engine-examples/mines/math/mines-9-15.tsv +2 -0
  432. package/engine-examples/mines/math/mines-9-16.tsv +2 -0
  433. package/engine-examples/mines/math/mines-9-2.tsv +2 -0
  434. package/engine-examples/mines/math/mines-9-3.tsv +2 -0
  435. package/engine-examples/mines/math/mines-9-4.tsv +2 -0
  436. package/engine-examples/mines/math/mines-9-5.tsv +2 -0
  437. package/engine-examples/mines/math/mines-9-6.tsv +2 -0
  438. package/engine-examples/mines/math/mines-9-7.tsv +2 -0
  439. package/engine-examples/mines/math/mines-9-8.tsv +2 -0
  440. package/engine-examples/mines/math/mines-9-9.tsv +2 -0
  441. package/engine-examples/plinko/AGENTS.md +3 -0
  442. package/engine-examples/plinko/README.md +9 -0
  443. package/engine-examples/plinko/bundle/assets.json +1 -0
  444. package/engine-examples/plinko/bundle/game.css +5 -0
  445. package/engine-examples/plinko/bundle/game.js +92 -0
  446. package/engine-examples/plinko/bundle/hbtest.json +4 -0
  447. package/engine-examples/plinko/bundle/index.html +16 -0
  448. package/engine-examples/plinko/bundle/model.json +1 -0
  449. package/engine-examples/plinko/math/gen.mjs +40 -0
  450. package/engine-examples/plinko/math/manifest.json +1 -0
  451. package/engine-examples/plinko/math/plinko-12-high.tsv +13 -0
  452. package/engine-examples/plinko/math/plinko-12-low.tsv +13 -0
  453. package/engine-examples/plinko/math/plinko-12-medium.tsv +13 -0
  454. package/engine-examples/plinko/math/plinko-16-high.tsv +17 -0
  455. package/engine-examples/plinko/math/plinko-16-low.tsv +17 -0
  456. package/engine-examples/plinko/math/plinko-16-medium.tsv +17 -0
  457. package/engine-examples/plinko/math/plinko-8-high.tsv +9 -0
  458. package/engine-examples/plinko/math/plinko-8-low.tsv +9 -0
  459. package/engine-examples/plinko/math/plinko-8-medium.tsv +9 -0
  460. package/engine-examples/plinko/math-kit/pack.mjs +165 -0
  461. package/engine-examples/plinko/math-kit/package.json +8 -0
  462. package/engine-examples/plinko/math-kit/slot.mjs +94 -0
  463. package/engine-examples/plinko/math-kit/tumble.mjs +94 -0
  464. package/engine-examples/slot/AGENTS.md +3 -0
  465. package/engine-examples/slot/README.md +26 -0
  466. package/engine-examples/slot/bundle/assets.json +1 -0
  467. package/engine-examples/slot/bundle/game.css +19 -0
  468. package/engine-examples/slot/bundle/game.js +42 -0
  469. package/engine-examples/slot/bundle/hbtest.json +4 -0
  470. package/engine-examples/slot/bundle/index.html +23 -0
  471. package/engine-examples/slot/math/gen.mjs +79 -0
  472. package/engine-examples/slot/math/manifest.json +1 -0
  473. package/engine-examples/slot/math/slot.tsv +110592 -0
  474. package/engine-examples/tower/AGENTS.md +3 -0
  475. package/engine-examples/tower/README.md +21 -0
  476. package/engine-examples/tower/bundle/assets.json +1 -0
  477. package/engine-examples/tower/bundle/game.css +8 -0
  478. package/engine-examples/tower/bundle/game.js +37 -0
  479. package/engine-examples/tower/bundle/hbtest.json +5 -0
  480. package/engine-examples/tower/bundle/index.html +16 -0
  481. package/engine-examples/tower/math/floor.tsv +4 -0
  482. package/engine-examples/tower/math/manifest.json +61 -0
  483. package/engine-examples/tumble/AGENTS.md +3 -0
  484. package/engine-examples/tumble/README.md +18 -0
  485. package/engine-examples/tumble/bundle/assets.json +1 -0
  486. package/engine-examples/tumble/bundle/game.css +13 -0
  487. package/engine-examples/tumble/bundle/game.js +119 -0
  488. package/engine-examples/tumble/bundle/hbtest.json +4 -0
  489. package/engine-examples/tumble/bundle/i18n.json +122 -0
  490. package/engine-examples/tumble/bundle/index.html +20 -0
  491. package/engine-examples/tumble/bundle/model.json +1 -0
  492. package/engine-examples/tumble/math/gen.mjs +38 -0
  493. package/engine-examples/tumble/math-kit/pack.mjs +165 -0
  494. package/engine-examples/tumble/math-kit/package.json +8 -0
  495. package/engine-examples/tumble/math-kit/slot.mjs +94 -0
  496. package/engine-examples/tumble/math-kit/tumble.mjs +94 -0
  497. package/engine-examples/wheel/README.md +14 -0
  498. package/engine-examples/wheel/bundle/assets.json +1 -0
  499. package/engine-examples/wheel/bundle/game.css +7 -0
  500. package/engine-examples/wheel/bundle/game.js +51 -0
  501. package/engine-examples/wheel/bundle/hbtest.json +4 -0
  502. package/engine-examples/wheel/bundle/index.html +19 -0
  503. package/engine-examples/wheel/math/high.tsv +24 -0
  504. package/engine-examples/wheel/math/low.tsv +24 -0
  505. package/engine-examples/wheel/math/manifest.json +48 -0
  506. package/engine-examples/wheel/math/medium.tsv +24 -0
  507. package/engine-math/pack.mjs +165 -0
  508. package/engine-math/package.json +1 -0
  509. package/engine-math/slot.mjs +94 -0
  510. package/engine-math/tumble.mjs +94 -0
  511. package/engine-mcp/package.json +1 -0
  512. package/engine-mcp/server.mjs +151 -0
  513. package/engine-sdk/GUIDE.md +855 -0
  514. package/engine-sdk/assets.js +92 -0
  515. package/engine-sdk/autoplay.js +82 -0
  516. package/engine-sdk/bet-field.js +391 -0
  517. package/engine-sdk/kit/fiat-coins.js +51 -0
  518. package/engine-sdk/kit/numeric-input.js +116 -0
  519. package/engine-sdk/kit/wallet-format.js +423 -0
  520. package/engine-sdk/marks.js +22 -0
  521. package/engine-sdk/messages.js +289 -0
  522. package/engine-sdk/money.js +89 -0
  523. package/engine-sdk/package.json +1 -0
  524. package/engine-sdk/protocol.js +263 -0
  525. package/engine-sdk/sdk.d.ts +138 -0
  526. package/engine-sdk/sdk.js +330 -0
  527. package/engine-sdk/stake.js +68 -0
  528. package/engine-sdk/ui.d.ts +36 -0
  529. package/engine-sdk/ui.js +340 -0
  530. package/engine-shell/core/faults.js +127 -0
  531. package/engine-shell/core/rgs.js +193 -0
  532. package/engine-shell/core/router.js +917 -0
  533. package/engine-shell/host/boot.js +408 -0
  534. package/engine-shell/host/engine-v1.js +438 -0
  535. package/engine-shell/host/fair.js +285 -0
  536. package/engine-shell/host/fonts/SOURCE.json +11 -0
  537. package/engine-shell/host/fonts/figtree-400.woff2 +0 -0
  538. package/engine-shell/host/fonts/figtree-500.woff2 +0 -0
  539. package/engine-shell/host/fonts/figtree-600.woff2 +0 -0
  540. package/engine-shell/host/fonts/red-hat-display-700.woff2 +0 -0
  541. package/engine-shell/host/index.html +230 -0
  542. package/engine-shell/host/page.js +809 -0
  543. package/engine-shell/host/sandbox-panel.js +681 -0
  544. package/engine-shell/host/sandbox-scenarios.js +554 -0
  545. package/engine-shell/host/site-bridge.js +87 -0
  546. package/engine-shell/host/strings.js +916 -0
  547. package/engine-shell/package.json +1 -0
  548. package/engine-shell/verifiers/badcat/coin.tsv +2 -0
  549. package/engine-shell/verifiers/badcat/dice-2.tsv +11 -0
  550. package/engine-shell/verifiers/badcat/dice-5.tsv +26 -0
  551. package/engine-shell/verifiers/badcat/dice-9.tsv +46 -0
  552. package/engine-shell/verifiers/badcat/manifest.json +3344 -0
  553. package/engine-shell/verifiers/badcat/rps.tsv +3 -0
  554. package/engine-shell/verifiers/badcat/triple.tsv +66 -0
  555. package/engine-shell/verifiers/engine-verify.js +358 -0
  556. package/engine-shell/verifiers/package.json +5 -0
  557. package/engine-shell/verifiers/parity/manifest.json +27 -0
  558. package/engine-shell/verifiers/parity/wide.tsv +5 -0
  559. package/engine-shell/verifiers/parity-vectors.json +244 -0
  560. package/engine-shell/verifiers/vectors.json +100 -0
  561. package/package.json +10 -0
@@ -0,0 +1,3 @@
1
+ 1 {"hand":"rock"}
2
+ 1 {"hand":"paper"}
3
+ 1 {"hand":"scissors"}
@@ -0,0 +1,66 @@
1
+ 1 {"coin":0,"hand":"rock","sum":2}
2
+ 1 {"coin":0,"hand":"paper","sum":2}
3
+ 1 {"coin":0,"hand":"scissors","sum":2}
4
+ 2 {"coin":0,"hand":"rock","sum":3}
5
+ 2 {"coin":0,"hand":"paper","sum":3}
6
+ 2 {"coin":0,"hand":"scissors","sum":3}
7
+ 3 {"coin":0,"hand":"rock","sum":4}
8
+ 3 {"coin":0,"hand":"paper","sum":4}
9
+ 3 {"coin":0,"hand":"scissors","sum":4}
10
+ 4 {"coin":0,"hand":"rock","sum":5}
11
+ 4 {"coin":0,"hand":"paper","sum":5}
12
+ 4 {"coin":0,"hand":"scissors","sum":5}
13
+ 5 {"coin":0,"hand":"rock","sum":6}
14
+ 5 {"coin":0,"hand":"paper","sum":6}
15
+ 5 {"coin":0,"hand":"scissors","sum":6}
16
+ 6 {"coin":0,"hand":"rock","sum":7}
17
+ 6 {"coin":0,"hand":"paper","sum":7}
18
+ 6 {"coin":0,"hand":"scissors","sum":7}
19
+ 5 {"coin":0,"hand":"rock","sum":8}
20
+ 5 {"coin":0,"hand":"paper","sum":8}
21
+ 5 {"coin":0,"hand":"scissors","sum":8}
22
+ 4 {"coin":0,"hand":"rock","sum":9}
23
+ 4 {"coin":0,"hand":"paper","sum":9}
24
+ 4 {"coin":0,"hand":"scissors","sum":9}
25
+ 3 {"coin":0,"hand":"rock","sum":10}
26
+ 3 {"coin":0,"hand":"paper","sum":10}
27
+ 3 {"coin":0,"hand":"scissors","sum":10}
28
+ 2 {"coin":0,"hand":"rock","sum":11}
29
+ 2 {"coin":0,"hand":"paper","sum":11}
30
+ 2 {"coin":0,"hand":"scissors","sum":11}
31
+ 1 {"coin":0,"hand":"rock","sum":12}
32
+ 1 {"coin":0,"hand":"paper","sum":12}
33
+ 1 {"coin":0,"hand":"scissors","sum":12}
34
+ 1 {"coin":1,"hand":"rock","sum":2}
35
+ 1 {"coin":1,"hand":"paper","sum":2}
36
+ 1 {"coin":1,"hand":"scissors","sum":2}
37
+ 2 {"coin":1,"hand":"rock","sum":3}
38
+ 2 {"coin":1,"hand":"paper","sum":3}
39
+ 2 {"coin":1,"hand":"scissors","sum":3}
40
+ 3 {"coin":1,"hand":"rock","sum":4}
41
+ 3 {"coin":1,"hand":"paper","sum":4}
42
+ 3 {"coin":1,"hand":"scissors","sum":4}
43
+ 4 {"coin":1,"hand":"rock","sum":5}
44
+ 4 {"coin":1,"hand":"paper","sum":5}
45
+ 4 {"coin":1,"hand":"scissors","sum":5}
46
+ 5 {"coin":1,"hand":"rock","sum":6}
47
+ 5 {"coin":1,"hand":"paper","sum":6}
48
+ 5 {"coin":1,"hand":"scissors","sum":6}
49
+ 6 {"coin":1,"hand":"rock","sum":7}
50
+ 6 {"coin":1,"hand":"paper","sum":7}
51
+ 6 {"coin":1,"hand":"scissors","sum":7}
52
+ 5 {"coin":1,"hand":"rock","sum":8}
53
+ 5 {"coin":1,"hand":"paper","sum":8}
54
+ 5 {"coin":1,"hand":"scissors","sum":8}
55
+ 4 {"coin":1,"hand":"rock","sum":9}
56
+ 4 {"coin":1,"hand":"paper","sum":9}
57
+ 4 {"coin":1,"hand":"scissors","sum":9}
58
+ 3 {"coin":1,"hand":"rock","sum":10}
59
+ 3 {"coin":1,"hand":"paper","sum":10}
60
+ 3 {"coin":1,"hand":"scissors","sum":10}
61
+ 2 {"coin":1,"hand":"rock","sum":11}
62
+ 2 {"coin":1,"hand":"paper","sum":11}
63
+ 2 {"coin":1,"hand":"scissors","sum":11}
64
+ 1 {"coin":1,"hand":"rock","sum":12}
65
+ 1 {"coin":1,"hand":"paper","sum":12}
66
+ 1 {"coin":1,"hand":"scissors","sum":12}
@@ -0,0 +1,358 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // House Engine `engine-v1` verifier (SPEC.md §1–2), independent of the Go
4
+ // server. Node ≥ 18, no dependencies. Reproduces a math pack's hash and
5
+ // re-derives any round from (serverSeed, clientSeed, nonce, mode, bet).
6
+ //
7
+ // node engine-verify.js <packDir> [vectors.json]
8
+ //
9
+ // With vectors.json (the Go package's golden file) it checks every vector
10
+ // and exits non-zero on the first difference. As a module it exports
11
+ // loadPack, mathHash, play and canonicalJSON for the SDK and the public
12
+ // fairness page.
13
+
14
+ const crypto = require('crypto');
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+
18
+ // ---- bytes → text, as the Go reference reads them ----------------------------
19
+ // A pack is UTF-8. The manifest's bytes are the document's — hashed, served
20
+ // and kept as they are — so a manifest that is not well-formed UTF-8 is
21
+ // refused, as the Go gate refuses it (mathpack.Load). A table's bytes are
22
+ // canonicalised on the way in: there Go's decoder turns every byte that does
23
+ // not start a well-formed UTF-8 sequence into U+FFFD, one per byte (a
24
+ // truncated three-byte sequence is two U+FFFD). Node's own decoder folds such
25
+ // a sequence into one, so a table file is walked here and only well-formed
26
+ // runs are handed to it.
27
+
28
+ function readManifestText(file) {
29
+ try {
30
+ return new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(fs.readFileSync(file));
31
+ } catch (e) {
32
+ throw new Error(`${path.basename(file)}: not valid UTF-8`);
33
+ }
34
+ }
35
+
36
+ function readText(file) {
37
+ const b = fs.readFileSync(file);
38
+ const parts = [];
39
+ let start = 0;
40
+ for (let i = 0; i < b.length; ) {
41
+ const n = b[i] < 0x80 ? 1 : utf8Length(b, i);
42
+ if (n > 0) { i += n; continue; }
43
+ parts.push(b.toString('utf8', start, i), '\ufffd');
44
+ i++;
45
+ start = i;
46
+ }
47
+ if (start === 0) return b.toString('utf8');
48
+ parts.push(b.toString('utf8', start));
49
+ return parts.join('');
50
+ }
51
+
52
+ // utf8Length is the length of the well-formed sequence starting at i, or 0
53
+ // (overlong forms, encoded surrogates and code points past U+10FFFF are not
54
+ // well-formed, as for Go's utf8.DecodeRune).
55
+ function utf8Length(b, i) {
56
+ const c = b[i];
57
+ const cont = (k, lo = 0x80, hi = 0xbf) => i + k < b.length && b[i + k] >= lo && b[i + k] <= hi;
58
+ if (c >= 0xc2 && c <= 0xdf) return cont(1) ? 2 : 0;
59
+ if (c === 0xe0) return cont(1, 0xa0) && cont(2) ? 3 : 0;
60
+ if ((c >= 0xe1 && c <= 0xec) || c === 0xee || c === 0xef) return cont(1) && cont(2) ? 3 : 0;
61
+ if (c === 0xed) return cont(1, 0x80, 0x9f) && cont(2) ? 3 : 0;
62
+ if (c === 0xf0) return cont(1, 0x90) && cont(2) && cont(3) ? 4 : 0;
63
+ if (c >= 0xf1 && c <= 0xf3) return cont(1) && cont(2) && cont(3) ? 4 : 0;
64
+ if (c === 0xf4) return cont(1, 0x80, 0x8f) && cont(2) && cont(3) ? 4 : 0;
65
+ return 0;
66
+ }
67
+
68
+ // ---- canonical JSON: keys sorted, no whitespace, numbers as written ---------
69
+ // A tiny parser that keeps each number's source text, so `2.50` stays `2.50`
70
+ // exactly as the Go reference does. Strings are escaped the way Go's
71
+ // encoding/json escapes them: `"` `\` and the short escapes \b \f \n \r \t,
72
+ // every other control character as \u00xx, `<` `>` `&` U+2028 U+2029 as
73
+ // \uXXXX, everything else as itself. An escaped surrogate pair is one code
74
+ // point; a lone surrogate is U+FFFD. Keys sort by code point.
75
+
76
+ function canonicalJSON(text) {
77
+ let i = 0;
78
+ const ws = () => { while (i < text.length && ' \t\r\n'.includes(text[i])) i++; };
79
+ const fail = (m) => { throw new Error(`canonical json: ${m} at ${i}`); };
80
+ function value() {
81
+ ws();
82
+ const c = text[i];
83
+ if (c === '{') return object();
84
+ if (c === '[') return array();
85
+ if (c === '"') return string();
86
+ if (c === 't' && text.startsWith('true', i)) { i += 4; return 'true'; }
87
+ if (c === 'f' && text.startsWith('false', i)) { i += 5; return 'false'; }
88
+ if (c === 'n' && text.startsWith('null', i)) { i += 4; return 'null'; }
89
+ const m = /^-?(0|[1-9]\d*)(\.\d+)?([eE][+-]?\d+)?/.exec(text.slice(i));
90
+ if (!m) fail('unexpected token');
91
+ i += m[0].length;
92
+ return m[0];
93
+ }
94
+ function object() {
95
+ i++; ws();
96
+ const entries = [];
97
+ if (text[i] === '}') { i++; return '{}'; }
98
+ for (;;) {
99
+ ws();
100
+ if (text[i] !== '"') fail('expected key');
101
+ const k = rawString();
102
+ ws();
103
+ if (text[i] !== ':') fail('expected :');
104
+ i++;
105
+ entries.push([k, value()]);
106
+ ws();
107
+ if (text[i] === ',') { i++; continue; }
108
+ if (text[i] === '}') { i++; break; }
109
+ fail('expected , or }');
110
+ }
111
+ if (new Set(entries.map(([k]) => k)).size !== entries.length) fail('duplicate key');
112
+ entries.sort((a, b) => compareCodePoints(a[0], b[0]));
113
+ return '{' + entries.map(([k, v]) => escapeString(k) + ':' + v).join(',') + '}';
114
+ }
115
+ function array() {
116
+ i++; ws();
117
+ const items = [];
118
+ if (text[i] === ']') { i++; return '[]'; }
119
+ for (;;) {
120
+ items.push(value());
121
+ ws();
122
+ if (text[i] === ',') { i++; continue; }
123
+ if (text[i] === ']') { i++; break; }
124
+ fail('expected , or ]');
125
+ }
126
+ return '[' + items.join(',') + ']';
127
+ }
128
+ function rawString() {
129
+ // returns the decoded string
130
+ i++;
131
+ let out = '';
132
+ for (;;) {
133
+ if (i >= text.length) fail('unterminated string');
134
+ const c = text[i++];
135
+ if (c === '"') return out;
136
+ // A raw control character inside a string is not JSON; Go's scanner
137
+ // refuses it, so a verifier that escaped it would hash a pack the
138
+ // gate never takes.
139
+ if (c.charCodeAt(0) < 0x20) fail('control character in string');
140
+ if (c !== '\\') { out += c; continue; }
141
+ const e = text[i++];
142
+ if (e === 'u') { out += String.fromCodePoint(unicodeEscape()); continue; }
143
+ const short = { '"': '"', '\\': '\\', '/': '/', b: '\b', f: '\f', n: '\n', r: '\r', t: '\t' }[e];
144
+ if (short === undefined) fail('bad escape');
145
+ out += short;
146
+ }
147
+ }
148
+ // unicodeEscape reads the XXXX of a \uXXXX (i is just past the u). A high
149
+ // surrogate followed by an escaped low surrogate is one code point. A
150
+ // surrogate on its own is U+FFFD, as Go's decoder has it, and whatever
151
+ // escape follows a lone high surrogate is read on its own.
152
+ function unicodeEscape() {
153
+ const cp = hex4(i);
154
+ i += 4;
155
+ if (cp < 0xd800 || cp > 0xdfff) return cp;
156
+ if (cp <= 0xdbff && text[i] === '\\' && text[i + 1] === 'u') {
157
+ const low = hex4(i + 2);
158
+ if (low >= 0xdc00 && low <= 0xdfff) {
159
+ i += 6;
160
+ return 0x10000 + ((cp - 0xd800) << 10) + (low - 0xdc00);
161
+ }
162
+ }
163
+ return 0xfffd;
164
+ }
165
+ function hex4(at) {
166
+ const h = text.slice(at, at + 4);
167
+ if (!/^[0-9a-fA-F]{4}$/.test(h)) fail('bad \\u escape');
168
+ return parseInt(h, 16);
169
+ }
170
+ function string() { return escapeString(rawString()); }
171
+ const out = value();
172
+ ws();
173
+ if (i !== text.length) fail('trailing data');
174
+ return out;
175
+ }
176
+
177
+ // compareCodePoints orders keys as the Go reference does: by code point,
178
+ // which is UTF-8 byte order. JavaScript's own `<` compares UTF-16 code
179
+ // units, which would put an emoji before U+E000..U+FFFF.
180
+ function compareCodePoints(a, b) {
181
+ let i = 0, j = 0;
182
+ while (i < a.length && j < b.length) {
183
+ const x = a.codePointAt(i), y = b.codePointAt(j);
184
+ if (x !== y) return x - y;
185
+ i += x > 0xffff ? 2 : 1;
186
+ j += y > 0xffff ? 2 : 1;
187
+ }
188
+ return (a.length - i) - (b.length - j);
189
+ }
190
+
191
+ function escapeString(s) {
192
+ let out = '"';
193
+ for (const ch of s) {
194
+ const cp = ch.codePointAt(0);
195
+ if (ch === '"') out += '\\"';
196
+ else if (ch === '\\') out += '\\\\';
197
+ else if (ch === '\b') out += '\\b';
198
+ else if (ch === '\f') out += '\\f';
199
+ else if (ch === '\n') out += '\\n';
200
+ else if (ch === '\r') out += '\\r';
201
+ else if (ch === '\t') out += '\\t';
202
+ else if (cp < 0x20 || ch === '<' || ch === '>' || ch === '&' || cp === 0x2028 || cp === 0x2029) {
203
+ out += '\\u' + cp.toString(16).padStart(4, '0');
204
+ } else out += ch;
205
+ }
206
+ return out + '"';
207
+ }
208
+
209
+ // ---- pack ------------------------------------------------------------------------
210
+
211
+ // A weight is what Go's strconv.ParseUint(s, 10, 64) takes: ASCII digits and
212
+ // nothing else. BigInt() alone would also take `0x10`, `+5` and ` 5`, and a
213
+ // verifier must not hash a table the gate refuses.
214
+ const WEIGHT = /^[0-9]+$/;
215
+
216
+ function parseTable(name, text) {
217
+ const rows = [];
218
+ const lines = text.split('\n');
219
+ if (lines[lines.length - 1] === '') lines.pop();
220
+ for (const line of lines) {
221
+ if (line.startsWith('#') && rows.length === 0) continue;
222
+ const tab = line.indexOf('\t');
223
+ const field = tab < 0 ? line : line.slice(0, tab);
224
+ if (!WEIGHT.test(field)) throw new Error(`${name}: weight ${JSON.stringify(field)} is not a decimal integer`);
225
+ const w = BigInt(field);
226
+ if (w <= 0n) throw new Error(`${name}: weight must be > 0`);
227
+ let data = null;
228
+ if (tab >= 0) {
229
+ // The data column is one JSON value: never empty, never holding a
230
+ // second tab or a carriage return (a CRLF file is refused, as in Go).
231
+ const rest = line.slice(tab + 1);
232
+ if (rest === '' || /[\t\r]/.test(rest)) throw new Error(`${name}: malformed data column`);
233
+ data = canonicalJSON(rest);
234
+ }
235
+ rows.push({ weight: w, data });
236
+ }
237
+ if (rows.length < 2) throw new Error(`${name}: needs at least 2 rows`);
238
+ const cum = [];
239
+ let sum = 0n;
240
+ for (const r of rows) { sum += r.weight; cum.push(sum); }
241
+ if (sum > (1n << 63n)) throw new Error(`${name}: weights sum past 2^63`);
242
+ return { name, rows, cum, sum };
243
+ }
244
+
245
+ function tableBytes(t) {
246
+ return t.rows.map((r) => r.weight.toString() + (r.data === null ? '' : '\t' + r.data) + '\n').join('');
247
+ }
248
+
249
+ function loadPack(dir) {
250
+ const manifestText = readManifestText(path.join(dir, 'manifest.json'));
251
+ const manifest = JSON.parse(manifestText);
252
+ const tables = {};
253
+ for (const m of manifest.modes) {
254
+ const names = m.kind === 'table' ? [m.table] : m.steps.map((s) => s.table);
255
+ for (const n of names) if (!tables[n]) tables[n] = parseTable(n, readText(path.join(dir, n)));
256
+ }
257
+ return { manifest, manifestText, tables };
258
+ }
259
+
260
+ function mathHash(pack) {
261
+ let s = 'house-engine-math/1\n';
262
+ s += 'manifest\n' + canonicalJSON(pack.manifestText) + '\n';
263
+ for (const name of Object.keys(pack.tables).sort()) s += 'table ' + name + '\n' + tableBytes(pack.tables[name]);
264
+ return crypto.createHash('sha256').update(s, 'utf8').digest('hex');
265
+ }
266
+
267
+ // ---- engine-v1 stream and draw ----------------------------------------------------
268
+
269
+ function stream(serverSeed, clientSeed, nonce) {
270
+ let block = 0, buf = Buffer.alloc(0), off = 0;
271
+ const byte = () => {
272
+ if (off >= buf.length) {
273
+ buf = crypto.createHmac('sha256', serverSeed).update(`${clientSeed}:${nonce}:${block}`).digest();
274
+ block++; off = 0;
275
+ }
276
+ return buf[off++];
277
+ };
278
+ return { u64() { let v = 0n; for (let k = 0; k < 8; k++) v = (v << 8n) | BigInt(byte()); return v; } };
279
+ }
280
+
281
+ const TWO64 = 1n << 64n;
282
+
283
+ function pick(table, s) {
284
+ const rem = TWO64 % table.sum;
285
+ const limit = TWO64 - rem;
286
+ let rejected = 0;
287
+ for (;;) {
288
+ const v = s.u64();
289
+ if (v < limit) {
290
+ const r = v % table.sum;
291
+ let lo = 0, hi = table.cum.length - 1;
292
+ while (lo < hi) { const mid = (lo + hi) >> 1; if (table.cum[mid] > r) hi = mid; else lo = mid + 1; }
293
+ return { raw: v, rejected, index: lo };
294
+ }
295
+ rejected++;
296
+ }
297
+ }
298
+
299
+ const inRanges = (rs, i) => rs.some(([lo, hi]) => i >= lo && i <= hi);
300
+
301
+ function play(pack, modeId, betId, serverSeed, clientSeed, nonce) {
302
+ const mode = pack.manifest.modes.find((m) => m.id === modeId);
303
+ if (!mode) throw new Error(`no mode ${modeId}`);
304
+ const bet = mode.bets.find((b) => b.id === betId);
305
+ if (!bet) throw new Error(`no bet ${betId}`);
306
+ const s = stream(serverSeed, clientSeed, nonce);
307
+ if (mode.kind === 'table') {
308
+ const d = pick(pack.tables[mode.table], s);
309
+ const tier = bet.tiers.find((t) => inRanges(t.outcomes, d.index));
310
+ return { mode: modeId, bet: betId, draws: [d], multBp: tier ? tier.multBp : 0 };
311
+ }
312
+ const draws = []; let survived = 0, busted = false;
313
+ for (const step of mode.steps) {
314
+ const d = pick(pack.tables[step.table], s);
315
+ draws.push(d);
316
+ if (!busted && inRanges(bet.survive, d.index)) survived++; else busted = true;
317
+ }
318
+ busted = survived < mode.steps.length;
319
+ const multBp = mode.autoAdvance && !busted ? mode.ladderBp[mode.steps.length - 1] : 0;
320
+ return { mode: modeId, bet: betId, draws, multBp, survived, busted };
321
+ }
322
+
323
+ // ---- CLI -------------------------------------------------------------------------
324
+
325
+ function checkVectors(pack, file) {
326
+ // A vector's raw draw is a decimal string: a u64 does not survive a JSON number.
327
+ const v = JSON.parse(readText(file));
328
+ const hash = mathHash(pack);
329
+ if (hash !== v.mathHash) return `mathHash ${hash} != ${v.mathHash}`;
330
+ for (const vec of v.vectors) {
331
+ const got = play(pack, vec.mode, vec.bet, v.serverSeed, v.clientSeed, vec.nonce);
332
+ const want = vec.draws;
333
+ if (got.draws.length !== want.length) return `${vec.mode}/${vec.bet}: ${got.draws.length} draws, want ${want.length}`;
334
+ for (let k = 0; k < want.length; k++) {
335
+ const g = got.draws[k], w = want[k];
336
+ if (g.raw.toString() !== w.raw || g.index !== w.index || (g.rejected || 0) !== (w.rejected || 0)) {
337
+ return `${vec.mode}/${vec.bet} draw ${k}: ${g.raw}/${g.index}/${g.rejected} want ${w.raw}/${w.index}/${w.rejected || 0}`;
338
+ }
339
+ }
340
+ if (got.multBp !== vec.multBp) return `${vec.mode}/${vec.bet}: multBp ${got.multBp} want ${vec.multBp}`;
341
+ if ((got.survived || 0) !== (vec.survived || 0)) return `${vec.mode}/${vec.bet}: survived ${got.survived} want ${vec.survived}`;
342
+ }
343
+ return null;
344
+ }
345
+
346
+ if (require.main === module) {
347
+ const [dir, vectors] = process.argv.slice(2);
348
+ if (!dir) { console.error('usage: engine-verify.js <packDir> [vectors.json]'); process.exit(2); }
349
+ const pack = loadPack(dir);
350
+ console.log('mathHash ' + mathHash(pack));
351
+ if (vectors) {
352
+ const problem = checkVectors(pack, vectors);
353
+ if (problem) { console.error('MISMATCH ' + problem); process.exit(1); }
354
+ console.log('vectors OK');
355
+ }
356
+ }
357
+
358
+ module.exports = { canonicalJSON, loadPack, mathHash, play, stream, pick, checkVectors };
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "commonjs",
3
+ "private": true,
4
+ "description": "The backend's reference verifier, byte for byte (housegames-backend internal/engine/verifiers/engine-verify.js): CommonJS, so this marker keeps it runnable beside the ESM shell."
5
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "format": "house-engine-math/1",
3
+ "game": "parity",
4
+ "rtpBp": 9900,
5
+ "modes": [
6
+ {
7
+ "id": "pick",
8
+ "label": "Pick \ud83d\udc31",
9
+ "kind": "table",
10
+ "table": "wide.tsv",
11
+ "bets": [
12
+ { "id": "first", "label": "First third", "tiers": [{ "outcomes": [[0, 0]], "multBp": 29700 }] },
13
+ { "id": "either", "tiers": [{ "outcomes": [[0, 1]], "multBp": 14850 }] },
14
+ { "id": "third", "tiers": [{ "outcomes": [[2, 2]], "multBp": 59400 }] },
15
+ { "id": "last", "tiers": [{ "outcomes": [[3, 3]], "multBp": 59400 }] }
16
+ ]
17
+ },
18
+ {
19
+ "id": "climb",
20
+ "kind": "ladder",
21
+ "steps": [{ "table": "wide.tsv" }, { "table": "wide.tsv" }],
22
+ "cashout": true,
23
+ "ladderBp": [14850, 22275],
24
+ "bets": [{ "id": "go", "survive": [[0, 1]] }]
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,5 @@
1
+ # parity: weights sum to 3*2^61, so one draw in four is rejected; row data holds every escape the canonical form has a rule for
2
+ 2305843009213693952 {"z":"tab\tnew\nline","a":"back\bform\f","b":"\u0001\u001f"}
3
+ 2305843009213693952 {"html":"<a href=\"x\">&</a>","sep":"\u2028\u2029","del":"\u007f"}
4
+ 1152921504606846976 {"raw":"🐱","cat":"\ud83d\udc31","lone":"\ud83d x","low":"\udc31","hi":"\ud83d\u0041","pair":"\ud83d\ude00","num":[1,2.50,-0,1E5,10000000000000000000]}
5
+ 1152921504606846976 {"\ud83d\ude00":1,"\ufb01":2,"z":3,"\u00e9":4,"bad":"�� ok"}