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.
- package/README.md +20 -0
- package/engine-cli/connect.mjs +73 -0
- package/engine-cli/hbengine.mjs +565 -0
- package/engine-cli/package.json +1 -0
- package/engine-cli/templates.mjs +14 -0
- package/engine-conformance/analyse-worker.mjs +12 -0
- package/engine-conformance/analyse.mjs +4458 -0
- package/engine-conformance/bundle.mjs +208 -0
- package/engine-conformance/clock.mjs +294 -0
- package/engine-conformance/csp.go +56 -0
- package/engine-conformance/csp.json +6 -0
- package/engine-conformance/csp.mjs +20 -0
- package/engine-conformance/gzip-sizes.mjs +9 -0
- package/engine-conformance/package.json +1 -0
- package/engine-conformance/picture.mjs +55 -0
- package/engine-conformance/report.go +349 -0
- package/engine-conformance/run.mjs +1217 -0
- package/engine-conformance/scan.mjs +476 -0
- package/engine-conformance/testdata/clock-overlay/bundle/assets.json +1 -0
- package/engine-conformance/testdata/clock-overlay/bundle/game.css +17 -0
- package/engine-conformance/testdata/clock-overlay/bundle/game.js +83 -0
- package/engine-conformance/testdata/clock-overlay/bundle/hbtest.json +4 -0
- package/engine-conformance/testdata/clock-overlay/bundle/index.html +34 -0
- package/engine-conformance/testdata/clock-probe/bundle/assets.json +1 -0
- package/engine-conformance/testdata/clock-probe/bundle/game.css +17 -0
- package/engine-conformance/testdata/clock-probe/bundle/game.js +65 -0
- package/engine-conformance/testdata/clock-probe/bundle/hbtest.json +4 -0
- package/engine-conformance/testdata/clock-probe/bundle/index.html +35 -0
- package/engine-conformance/testdata/clock-probe/bundle/probe-worker.js +46 -0
- package/engine-conformance/testdata/clock-probe/bundle/probe.js +210 -0
- package/engine-conformance/testdata/clock-probe/math/dice.tsv +100 -0
- package/engine-conformance/testdata/clock-probe/math/manifest.json +2925 -0
- package/engine-conformance/testdata/clock-worker/bundle/assets.json +1 -0
- package/engine-conformance/testdata/clock-worker/bundle/clock-worker.js +14 -0
- package/engine-conformance/testdata/clock-worker/bundle/game.css +17 -0
- package/engine-conformance/testdata/clock-worker/bundle/game.js +61 -0
- package/engine-conformance/testdata/clock-worker/bundle/hbtest.json +4 -0
- package/engine-conformance/testdata/clock-worker/bundle/index.html +35 -0
- package/engine-conformance/testdata/clock-worker/math/dice.tsv +100 -0
- package/engine-conformance/testdata/clock-worker/math/manifest.json +2925 -0
- package/engine-conformance/travel.mjs +1209 -0
- package/engine-conformance/vendor/acorn/LICENSE +21 -0
- package/engine-conformance/vendor/acorn/acorn.mjs +6266 -0
- package/engine-conformance/wasm-releases.json +168 -0
- package/engine-examples/README.md +23 -0
- package/engine-examples/coin/AGENTS.md +3 -0
- package/engine-examples/coin/README.md +7 -0
- package/engine-examples/coin/bundle/assets.json +1 -0
- package/engine-examples/coin/bundle/game.css +5 -0
- package/engine-examples/coin/bundle/game.js +19 -0
- package/engine-examples/coin/bundle/hbtest.json +5 -0
- package/engine-examples/coin/bundle/index.html +16 -0
- package/engine-examples/coin/math/coin.tsv +2 -0
- package/engine-examples/coin/math/manifest.json +17 -0
- package/engine-examples/crash/AGENTS.md +3 -0
- package/engine-examples/crash/README.md +14 -0
- package/engine-examples/crash/bundle/assets.json +1 -0
- package/engine-examples/crash/bundle/game.css +8 -0
- package/engine-examples/crash/bundle/game.js +90 -0
- package/engine-examples/crash/bundle/hbtest.json +5 -0
- package/engine-examples/crash/bundle/index.html +20 -0
- package/engine-examples/crash/math/crash-01.tsv +2 -0
- package/engine-examples/crash/math/crash-02.tsv +2 -0
- package/engine-examples/crash/math/crash-03.tsv +2 -0
- package/engine-examples/crash/math/crash-04.tsv +2 -0
- package/engine-examples/crash/math/crash-05.tsv +2 -0
- package/engine-examples/crash/math/crash-06.tsv +2 -0
- package/engine-examples/crash/math/crash-07.tsv +2 -0
- package/engine-examples/crash/math/crash-08.tsv +2 -0
- package/engine-examples/crash/math/crash-09.tsv +2 -0
- package/engine-examples/crash/math/crash-10.tsv +2 -0
- package/engine-examples/crash/math/crash-11.tsv +2 -0
- package/engine-examples/crash/math/crash-12.tsv +2 -0
- package/engine-examples/crash/math/crash-13.tsv +2 -0
- package/engine-examples/crash/math/crash-14.tsv +2 -0
- package/engine-examples/crash/math/crash-15.tsv +2 -0
- package/engine-examples/crash/math/crash-16.tsv +2 -0
- package/engine-examples/crash/math/crash-17.tsv +2 -0
- package/engine-examples/crash/math/crash-18.tsv +2 -0
- package/engine-examples/crash/math/crash-19.tsv +2 -0
- package/engine-examples/crash/math/crash-20.tsv +2 -0
- package/engine-examples/crash/math/crash-21.tsv +2 -0
- package/engine-examples/crash/math/crash-22.tsv +2 -0
- package/engine-examples/crash/math/crash-23.tsv +2 -0
- package/engine-examples/crash/math/crash-24.tsv +2 -0
- package/engine-examples/crash/math/crash-25.tsv +2 -0
- package/engine-examples/crash/math/crash-26.tsv +2 -0
- package/engine-examples/crash/math/crash-27.tsv +2 -0
- package/engine-examples/crash/math/crash-28.tsv +2 -0
- package/engine-examples/crash/math/crash-29.tsv +2 -0
- package/engine-examples/crash/math/crash-30.tsv +2 -0
- package/engine-examples/crash/math/crash-31.tsv +2 -0
- package/engine-examples/crash/math/crash-32.tsv +2 -0
- package/engine-examples/crash/math/crash-33.tsv +2 -0
- package/engine-examples/crash/math/crash-34.tsv +2 -0
- package/engine-examples/crash/math/crash-35.tsv +2 -0
- package/engine-examples/crash/math/crash-36.tsv +2 -0
- package/engine-examples/crash/math/crash-37.tsv +2 -0
- package/engine-examples/crash/math/crash-38.tsv +2 -0
- package/engine-examples/crash/math/crash-39.tsv +2 -0
- package/engine-examples/crash/math/crash-40.tsv +2 -0
- package/engine-examples/crash/math/crash-41.tsv +2 -0
- package/engine-examples/crash/math/crash-42.tsv +2 -0
- package/engine-examples/crash/math/crash-43.tsv +2 -0
- package/engine-examples/crash/math/crash-44.tsv +2 -0
- package/engine-examples/crash/math/crash-45.tsv +2 -0
- package/engine-examples/crash/math/crash-46.tsv +2 -0
- package/engine-examples/crash/math/crash-47.tsv +2 -0
- package/engine-examples/crash/math/crash-48.tsv +2 -0
- package/engine-examples/crash/math/crash-49.tsv +2 -0
- package/engine-examples/crash/math/crash-50.tsv +2 -0
- package/engine-examples/crash/math/crash-51.tsv +2 -0
- package/engine-examples/crash/math/crash-52.tsv +2 -0
- package/engine-examples/crash/math/crash-53.tsv +2 -0
- package/engine-examples/crash/math/crash-54.tsv +2 -0
- package/engine-examples/crash/math/crash-55.tsv +2 -0
- package/engine-examples/crash/math/crash-56.tsv +2 -0
- package/engine-examples/crash/math/crash-57.tsv +2 -0
- package/engine-examples/crash/math/crash-58.tsv +2 -0
- package/engine-examples/crash/math/crash-59.tsv +2 -0
- package/engine-examples/crash/math/crash-60.tsv +2 -0
- package/engine-examples/crash/math/crash-61.tsv +2 -0
- package/engine-examples/crash/math/crash-62.tsv +2 -0
- package/engine-examples/crash/math/crash-63.tsv +2 -0
- package/engine-examples/crash/math/crash-64.tsv +2 -0
- package/engine-examples/crash/math/gen.mjs +31 -0
- package/engine-examples/crash/math/manifest.json +1 -0
- package/engine-examples/dice/AGENTS.md +3 -0
- package/engine-examples/dice/README.md +25 -0
- package/engine-examples/dice/bundle/assets.json +1 -0
- package/engine-examples/dice/bundle/game.css +17 -0
- package/engine-examples/dice/bundle/game.js +61 -0
- package/engine-examples/dice/bundle/hbtest.json +4 -0
- package/engine-examples/dice/bundle/index.html +34 -0
- package/engine-examples/dice/math/dice.tsv +100 -0
- package/engine-examples/dice/math/manifest.json +2925 -0
- package/engine-examples/keno/AGENTS.md +3 -0
- package/engine-examples/keno/README.md +11 -0
- package/engine-examples/keno/bundle/assets.json +1 -0
- package/engine-examples/keno/bundle/game.css +14 -0
- package/engine-examples/keno/bundle/game.js +86 -0
- package/engine-examples/keno/bundle/hbtest.json +4 -0
- package/engine-examples/keno/bundle/i18n.json +342 -0
- package/engine-examples/keno/bundle/index.html +20 -0
- package/engine-examples/keno/bundle/model.json +1 -0
- package/engine-examples/keno/math/gen.mjs +35 -0
- package/engine-examples/keno/math/keno-picks-1.tsv +2 -0
- package/engine-examples/keno/math/keno-picks-10.tsv +11 -0
- package/engine-examples/keno/math/keno-picks-2.tsv +3 -0
- package/engine-examples/keno/math/keno-picks-3.tsv +4 -0
- package/engine-examples/keno/math/keno-picks-4.tsv +5 -0
- package/engine-examples/keno/math/keno-picks-5.tsv +6 -0
- package/engine-examples/keno/math/keno-picks-6.tsv +7 -0
- package/engine-examples/keno/math/keno-picks-7.tsv +8 -0
- package/engine-examples/keno/math/keno-picks-8.tsv +9 -0
- package/engine-examples/keno/math/keno-picks-9.tsv +10 -0
- package/engine-examples/keno/math/manifest.json +1 -0
- package/engine-examples/keno/math-kit/pack.mjs +165 -0
- package/engine-examples/keno/math-kit/package.json +8 -0
- package/engine-examples/keno/math-kit/slot.mjs +94 -0
- package/engine-examples/keno/math-kit/tumble.mjs +94 -0
- package/engine-examples/lines/AGENTS.md +3 -0
- package/engine-examples/lines/README.md +20 -0
- package/engine-examples/lines/bundle/assets.json +1 -0
- package/engine-examples/lines/bundle/game.css +16 -0
- package/engine-examples/lines/bundle/game.js +125 -0
- package/engine-examples/lines/bundle/hbtest.json +4 -0
- package/engine-examples/lines/bundle/i18n.json +242 -0
- package/engine-examples/lines/bundle/index.html +23 -0
- package/engine-examples/lines/bundle/model.json +1 -0
- package/engine-examples/lines/math/gen.mjs +54 -0
- package/engine-examples/lines/math-kit/pack.mjs +165 -0
- package/engine-examples/lines/math-kit/package.json +8 -0
- package/engine-examples/lines/math-kit/slot.mjs +94 -0
- package/engine-examples/lines/math-kit/tumble.mjs +94 -0
- package/engine-examples/mines/AGENTS.md +3 -0
- package/engine-examples/mines/README.md +13 -0
- package/engine-examples/mines/bundle/assets.json +1 -0
- package/engine-examples/mines/bundle/game.css +12 -0
- package/engine-examples/mines/bundle/game.js +58 -0
- package/engine-examples/mines/bundle/hbtest.json +8 -0
- package/engine-examples/mines/bundle/index.html +16 -0
- package/engine-examples/mines/math/gen.mjs +40 -0
- package/engine-examples/mines/math/manifest.json +1 -0
- package/engine-examples/mines/math/mines-1-1.tsv +2 -0
- package/engine-examples/mines/math/mines-1-2.tsv +2 -0
- package/engine-examples/mines/math/mines-1-22.tsv +2 -0
- package/engine-examples/mines/math/mines-1-23.tsv +2 -0
- package/engine-examples/mines/math/mines-1-24.tsv +2 -0
- package/engine-examples/mines/math/mines-1-3.tsv +2 -0
- package/engine-examples/mines/math/mines-10-1.tsv +2 -0
- package/engine-examples/mines/math/mines-10-10.tsv +2 -0
- package/engine-examples/mines/math/mines-10-11.tsv +2 -0
- package/engine-examples/mines/math/mines-10-12.tsv +2 -0
- package/engine-examples/mines/math/mines-10-13.tsv +2 -0
- package/engine-examples/mines/math/mines-10-14.tsv +2 -0
- package/engine-examples/mines/math/mines-10-15.tsv +2 -0
- package/engine-examples/mines/math/mines-10-2.tsv +2 -0
- package/engine-examples/mines/math/mines-10-3.tsv +2 -0
- package/engine-examples/mines/math/mines-10-4.tsv +2 -0
- package/engine-examples/mines/math/mines-10-5.tsv +2 -0
- package/engine-examples/mines/math/mines-10-6.tsv +2 -0
- package/engine-examples/mines/math/mines-10-7.tsv +2 -0
- package/engine-examples/mines/math/mines-10-8.tsv +2 -0
- package/engine-examples/mines/math/mines-10-9.tsv +2 -0
- package/engine-examples/mines/math/mines-11-1.tsv +2 -0
- package/engine-examples/mines/math/mines-11-10.tsv +2 -0
- package/engine-examples/mines/math/mines-11-11.tsv +2 -0
- package/engine-examples/mines/math/mines-11-12.tsv +2 -0
- package/engine-examples/mines/math/mines-11-13.tsv +2 -0
- package/engine-examples/mines/math/mines-11-14.tsv +2 -0
- package/engine-examples/mines/math/mines-11-2.tsv +2 -0
- package/engine-examples/mines/math/mines-11-3.tsv +2 -0
- package/engine-examples/mines/math/mines-11-4.tsv +2 -0
- package/engine-examples/mines/math/mines-11-5.tsv +2 -0
- package/engine-examples/mines/math/mines-11-6.tsv +2 -0
- package/engine-examples/mines/math/mines-11-7.tsv +2 -0
- package/engine-examples/mines/math/mines-11-8.tsv +2 -0
- package/engine-examples/mines/math/mines-11-9.tsv +2 -0
- package/engine-examples/mines/math/mines-12-1.tsv +2 -0
- package/engine-examples/mines/math/mines-12-10.tsv +2 -0
- package/engine-examples/mines/math/mines-12-11.tsv +2 -0
- package/engine-examples/mines/math/mines-12-12.tsv +2 -0
- package/engine-examples/mines/math/mines-12-13.tsv +2 -0
- package/engine-examples/mines/math/mines-12-2.tsv +2 -0
- package/engine-examples/mines/math/mines-12-3.tsv +2 -0
- package/engine-examples/mines/math/mines-12-4.tsv +2 -0
- package/engine-examples/mines/math/mines-12-5.tsv +2 -0
- package/engine-examples/mines/math/mines-12-6.tsv +2 -0
- package/engine-examples/mines/math/mines-12-7.tsv +2 -0
- package/engine-examples/mines/math/mines-12-8.tsv +2 -0
- package/engine-examples/mines/math/mines-12-9.tsv +2 -0
- package/engine-examples/mines/math/mines-13-1.tsv +2 -0
- package/engine-examples/mines/math/mines-13-10.tsv +2 -0
- package/engine-examples/mines/math/mines-13-11.tsv +2 -0
- package/engine-examples/mines/math/mines-13-12.tsv +2 -0
- package/engine-examples/mines/math/mines-13-2.tsv +2 -0
- package/engine-examples/mines/math/mines-13-3.tsv +2 -0
- package/engine-examples/mines/math/mines-13-4.tsv +2 -0
- package/engine-examples/mines/math/mines-13-5.tsv +2 -0
- package/engine-examples/mines/math/mines-13-6.tsv +2 -0
- package/engine-examples/mines/math/mines-13-7.tsv +2 -0
- package/engine-examples/mines/math/mines-13-8.tsv +2 -0
- package/engine-examples/mines/math/mines-13-9.tsv +2 -0
- package/engine-examples/mines/math/mines-14-1.tsv +2 -0
- package/engine-examples/mines/math/mines-14-10.tsv +2 -0
- package/engine-examples/mines/math/mines-14-11.tsv +2 -0
- package/engine-examples/mines/math/mines-14-2.tsv +2 -0
- package/engine-examples/mines/math/mines-14-3.tsv +2 -0
- package/engine-examples/mines/math/mines-14-4.tsv +2 -0
- package/engine-examples/mines/math/mines-14-5.tsv +2 -0
- package/engine-examples/mines/math/mines-14-6.tsv +2 -0
- package/engine-examples/mines/math/mines-14-7.tsv +2 -0
- package/engine-examples/mines/math/mines-14-8.tsv +2 -0
- package/engine-examples/mines/math/mines-14-9.tsv +2 -0
- package/engine-examples/mines/math/mines-15-1.tsv +2 -0
- package/engine-examples/mines/math/mines-15-10.tsv +2 -0
- package/engine-examples/mines/math/mines-15-2.tsv +2 -0
- package/engine-examples/mines/math/mines-15-3.tsv +2 -0
- package/engine-examples/mines/math/mines-15-4.tsv +2 -0
- package/engine-examples/mines/math/mines-15-5.tsv +2 -0
- package/engine-examples/mines/math/mines-15-6.tsv +2 -0
- package/engine-examples/mines/math/mines-15-7.tsv +2 -0
- package/engine-examples/mines/math/mines-15-8.tsv +2 -0
- package/engine-examples/mines/math/mines-15-9.tsv +2 -0
- package/engine-examples/mines/math/mines-16-1.tsv +2 -0
- package/engine-examples/mines/math/mines-16-2.tsv +2 -0
- package/engine-examples/mines/math/mines-16-3.tsv +2 -0
- package/engine-examples/mines/math/mines-16-4.tsv +2 -0
- package/engine-examples/mines/math/mines-16-5.tsv +2 -0
- package/engine-examples/mines/math/mines-16-6.tsv +2 -0
- package/engine-examples/mines/math/mines-16-7.tsv +2 -0
- package/engine-examples/mines/math/mines-16-8.tsv +2 -0
- package/engine-examples/mines/math/mines-16-9.tsv +2 -0
- package/engine-examples/mines/math/mines-17-1.tsv +2 -0
- package/engine-examples/mines/math/mines-17-2.tsv +2 -0
- package/engine-examples/mines/math/mines-17-3.tsv +2 -0
- package/engine-examples/mines/math/mines-17-4.tsv +2 -0
- package/engine-examples/mines/math/mines-17-5.tsv +2 -0
- package/engine-examples/mines/math/mines-17-6.tsv +2 -0
- package/engine-examples/mines/math/mines-17-7.tsv +2 -0
- package/engine-examples/mines/math/mines-17-8.tsv +2 -0
- package/engine-examples/mines/math/mines-18-1.tsv +2 -0
- package/engine-examples/mines/math/mines-18-2.tsv +2 -0
- package/engine-examples/mines/math/mines-18-3.tsv +2 -0
- package/engine-examples/mines/math/mines-18-4.tsv +2 -0
- package/engine-examples/mines/math/mines-18-5.tsv +2 -0
- package/engine-examples/mines/math/mines-18-6.tsv +2 -0
- package/engine-examples/mines/math/mines-18-7.tsv +2 -0
- package/engine-examples/mines/math/mines-19-1.tsv +2 -0
- package/engine-examples/mines/math/mines-19-2.tsv +2 -0
- package/engine-examples/mines/math/mines-19-3.tsv +2 -0
- package/engine-examples/mines/math/mines-19-4.tsv +2 -0
- package/engine-examples/mines/math/mines-19-5.tsv +2 -0
- package/engine-examples/mines/math/mines-19-6.tsv +2 -0
- package/engine-examples/mines/math/mines-2-1.tsv +2 -0
- package/engine-examples/mines/math/mines-2-19.tsv +2 -0
- package/engine-examples/mines/math/mines-2-2.tsv +2 -0
- package/engine-examples/mines/math/mines-2-20.tsv +2 -0
- package/engine-examples/mines/math/mines-2-21.tsv +2 -0
- package/engine-examples/mines/math/mines-2-22.tsv +2 -0
- package/engine-examples/mines/math/mines-2-23.tsv +2 -0
- package/engine-examples/mines/math/mines-2-3.tsv +2 -0
- package/engine-examples/mines/math/mines-2-4.tsv +2 -0
- package/engine-examples/mines/math/mines-2-5.tsv +2 -0
- package/engine-examples/mines/math/mines-20-1.tsv +2 -0
- package/engine-examples/mines/math/mines-20-2.tsv +2 -0
- package/engine-examples/mines/math/mines-20-3.tsv +2 -0
- package/engine-examples/mines/math/mines-20-4.tsv +2 -0
- package/engine-examples/mines/math/mines-20-5.tsv +2 -0
- package/engine-examples/mines/math/mines-21-1.tsv +2 -0
- package/engine-examples/mines/math/mines-21-2.tsv +2 -0
- package/engine-examples/mines/math/mines-21-3.tsv +2 -0
- package/engine-examples/mines/math/mines-21-4.tsv +2 -0
- package/engine-examples/mines/math/mines-22-1.tsv +2 -0
- package/engine-examples/mines/math/mines-22-2.tsv +2 -0
- package/engine-examples/mines/math/mines-22-3.tsv +2 -0
- package/engine-examples/mines/math/mines-23-1.tsv +2 -0
- package/engine-examples/mines/math/mines-23-2.tsv +2 -0
- package/engine-examples/mines/math/mines-24-1.tsv +2 -0
- package/engine-examples/mines/math/mines-3-1.tsv +2 -0
- package/engine-examples/mines/math/mines-3-17.tsv +2 -0
- package/engine-examples/mines/math/mines-3-18.tsv +2 -0
- package/engine-examples/mines/math/mines-3-19.tsv +2 -0
- package/engine-examples/mines/math/mines-3-2.tsv +2 -0
- package/engine-examples/mines/math/mines-3-20.tsv +2 -0
- package/engine-examples/mines/math/mines-3-21.tsv +2 -0
- package/engine-examples/mines/math/mines-3-22.tsv +2 -0
- package/engine-examples/mines/math/mines-3-3.tsv +2 -0
- package/engine-examples/mines/math/mines-3-4.tsv +2 -0
- package/engine-examples/mines/math/mines-3-5.tsv +2 -0
- package/engine-examples/mines/math/mines-3-6.tsv +2 -0
- package/engine-examples/mines/math/mines-4-1.tsv +2 -0
- package/engine-examples/mines/math/mines-4-13.tsv +2 -0
- package/engine-examples/mines/math/mines-4-14.tsv +2 -0
- package/engine-examples/mines/math/mines-4-15.tsv +2 -0
- package/engine-examples/mines/math/mines-4-16.tsv +2 -0
- package/engine-examples/mines/math/mines-4-17.tsv +2 -0
- package/engine-examples/mines/math/mines-4-18.tsv +2 -0
- package/engine-examples/mines/math/mines-4-19.tsv +2 -0
- package/engine-examples/mines/math/mines-4-2.tsv +2 -0
- package/engine-examples/mines/math/mines-4-20.tsv +2 -0
- package/engine-examples/mines/math/mines-4-21.tsv +2 -0
- package/engine-examples/mines/math/mines-4-3.tsv +2 -0
- package/engine-examples/mines/math/mines-4-4.tsv +2 -0
- package/engine-examples/mines/math/mines-4-5.tsv +2 -0
- package/engine-examples/mines/math/mines-4-6.tsv +2 -0
- package/engine-examples/mines/math/mines-4-7.tsv +2 -0
- package/engine-examples/mines/math/mines-4-8.tsv +2 -0
- package/engine-examples/mines/math/mines-4-9.tsv +2 -0
- package/engine-examples/mines/math/mines-5-1.tsv +2 -0
- package/engine-examples/mines/math/mines-5-10.tsv +2 -0
- package/engine-examples/mines/math/mines-5-11.tsv +2 -0
- package/engine-examples/mines/math/mines-5-12.tsv +2 -0
- package/engine-examples/mines/math/mines-5-13.tsv +2 -0
- package/engine-examples/mines/math/mines-5-14.tsv +2 -0
- package/engine-examples/mines/math/mines-5-15.tsv +2 -0
- package/engine-examples/mines/math/mines-5-16.tsv +2 -0
- package/engine-examples/mines/math/mines-5-17.tsv +2 -0
- package/engine-examples/mines/math/mines-5-18.tsv +2 -0
- package/engine-examples/mines/math/mines-5-19.tsv +2 -0
- package/engine-examples/mines/math/mines-5-2.tsv +2 -0
- package/engine-examples/mines/math/mines-5-20.tsv +2 -0
- package/engine-examples/mines/math/mines-5-3.tsv +2 -0
- package/engine-examples/mines/math/mines-5-4.tsv +2 -0
- package/engine-examples/mines/math/mines-5-5.tsv +2 -0
- package/engine-examples/mines/math/mines-5-6.tsv +2 -0
- package/engine-examples/mines/math/mines-5-7.tsv +2 -0
- package/engine-examples/mines/math/mines-5-8.tsv +2 -0
- package/engine-examples/mines/math/mines-5-9.tsv +2 -0
- package/engine-examples/mines/math/mines-6-1.tsv +2 -0
- package/engine-examples/mines/math/mines-6-10.tsv +2 -0
- package/engine-examples/mines/math/mines-6-11.tsv +2 -0
- package/engine-examples/mines/math/mines-6-12.tsv +2 -0
- package/engine-examples/mines/math/mines-6-13.tsv +2 -0
- package/engine-examples/mines/math/mines-6-14.tsv +2 -0
- package/engine-examples/mines/math/mines-6-15.tsv +2 -0
- package/engine-examples/mines/math/mines-6-16.tsv +2 -0
- package/engine-examples/mines/math/mines-6-17.tsv +2 -0
- package/engine-examples/mines/math/mines-6-18.tsv +2 -0
- package/engine-examples/mines/math/mines-6-19.tsv +2 -0
- package/engine-examples/mines/math/mines-6-2.tsv +2 -0
- package/engine-examples/mines/math/mines-6-3.tsv +2 -0
- package/engine-examples/mines/math/mines-6-4.tsv +2 -0
- package/engine-examples/mines/math/mines-6-5.tsv +2 -0
- package/engine-examples/mines/math/mines-6-6.tsv +2 -0
- package/engine-examples/mines/math/mines-6-7.tsv +2 -0
- package/engine-examples/mines/math/mines-6-8.tsv +2 -0
- package/engine-examples/mines/math/mines-6-9.tsv +2 -0
- package/engine-examples/mines/math/mines-7-1.tsv +2 -0
- package/engine-examples/mines/math/mines-7-10.tsv +2 -0
- package/engine-examples/mines/math/mines-7-11.tsv +2 -0
- package/engine-examples/mines/math/mines-7-12.tsv +2 -0
- package/engine-examples/mines/math/mines-7-13.tsv +2 -0
- package/engine-examples/mines/math/mines-7-14.tsv +2 -0
- package/engine-examples/mines/math/mines-7-15.tsv +2 -0
- package/engine-examples/mines/math/mines-7-16.tsv +2 -0
- package/engine-examples/mines/math/mines-7-17.tsv +2 -0
- package/engine-examples/mines/math/mines-7-18.tsv +2 -0
- package/engine-examples/mines/math/mines-7-2.tsv +2 -0
- package/engine-examples/mines/math/mines-7-3.tsv +2 -0
- package/engine-examples/mines/math/mines-7-4.tsv +2 -0
- package/engine-examples/mines/math/mines-7-5.tsv +2 -0
- package/engine-examples/mines/math/mines-7-6.tsv +2 -0
- package/engine-examples/mines/math/mines-7-7.tsv +2 -0
- package/engine-examples/mines/math/mines-7-8.tsv +2 -0
- package/engine-examples/mines/math/mines-7-9.tsv +2 -0
- package/engine-examples/mines/math/mines-8-1.tsv +2 -0
- package/engine-examples/mines/math/mines-8-10.tsv +2 -0
- package/engine-examples/mines/math/mines-8-11.tsv +2 -0
- package/engine-examples/mines/math/mines-8-12.tsv +2 -0
- package/engine-examples/mines/math/mines-8-13.tsv +2 -0
- package/engine-examples/mines/math/mines-8-14.tsv +2 -0
- package/engine-examples/mines/math/mines-8-15.tsv +2 -0
- package/engine-examples/mines/math/mines-8-16.tsv +2 -0
- package/engine-examples/mines/math/mines-8-17.tsv +2 -0
- package/engine-examples/mines/math/mines-8-2.tsv +2 -0
- package/engine-examples/mines/math/mines-8-3.tsv +2 -0
- package/engine-examples/mines/math/mines-8-4.tsv +2 -0
- package/engine-examples/mines/math/mines-8-5.tsv +2 -0
- package/engine-examples/mines/math/mines-8-6.tsv +2 -0
- package/engine-examples/mines/math/mines-8-7.tsv +2 -0
- package/engine-examples/mines/math/mines-8-8.tsv +2 -0
- package/engine-examples/mines/math/mines-8-9.tsv +2 -0
- package/engine-examples/mines/math/mines-9-1.tsv +2 -0
- package/engine-examples/mines/math/mines-9-10.tsv +2 -0
- package/engine-examples/mines/math/mines-9-11.tsv +2 -0
- package/engine-examples/mines/math/mines-9-12.tsv +2 -0
- package/engine-examples/mines/math/mines-9-13.tsv +2 -0
- package/engine-examples/mines/math/mines-9-14.tsv +2 -0
- package/engine-examples/mines/math/mines-9-15.tsv +2 -0
- package/engine-examples/mines/math/mines-9-16.tsv +2 -0
- package/engine-examples/mines/math/mines-9-2.tsv +2 -0
- package/engine-examples/mines/math/mines-9-3.tsv +2 -0
- package/engine-examples/mines/math/mines-9-4.tsv +2 -0
- package/engine-examples/mines/math/mines-9-5.tsv +2 -0
- package/engine-examples/mines/math/mines-9-6.tsv +2 -0
- package/engine-examples/mines/math/mines-9-7.tsv +2 -0
- package/engine-examples/mines/math/mines-9-8.tsv +2 -0
- package/engine-examples/mines/math/mines-9-9.tsv +2 -0
- package/engine-examples/plinko/AGENTS.md +3 -0
- package/engine-examples/plinko/README.md +9 -0
- package/engine-examples/plinko/bundle/assets.json +1 -0
- package/engine-examples/plinko/bundle/game.css +5 -0
- package/engine-examples/plinko/bundle/game.js +92 -0
- package/engine-examples/plinko/bundle/hbtest.json +4 -0
- package/engine-examples/plinko/bundle/index.html +16 -0
- package/engine-examples/plinko/bundle/model.json +1 -0
- package/engine-examples/plinko/math/gen.mjs +40 -0
- package/engine-examples/plinko/math/manifest.json +1 -0
- package/engine-examples/plinko/math/plinko-12-high.tsv +13 -0
- package/engine-examples/plinko/math/plinko-12-low.tsv +13 -0
- package/engine-examples/plinko/math/plinko-12-medium.tsv +13 -0
- package/engine-examples/plinko/math/plinko-16-high.tsv +17 -0
- package/engine-examples/plinko/math/plinko-16-low.tsv +17 -0
- package/engine-examples/plinko/math/plinko-16-medium.tsv +17 -0
- package/engine-examples/plinko/math/plinko-8-high.tsv +9 -0
- package/engine-examples/plinko/math/plinko-8-low.tsv +9 -0
- package/engine-examples/plinko/math/plinko-8-medium.tsv +9 -0
- package/engine-examples/plinko/math-kit/pack.mjs +165 -0
- package/engine-examples/plinko/math-kit/package.json +8 -0
- package/engine-examples/plinko/math-kit/slot.mjs +94 -0
- package/engine-examples/plinko/math-kit/tumble.mjs +94 -0
- package/engine-examples/slot/AGENTS.md +3 -0
- package/engine-examples/slot/README.md +26 -0
- package/engine-examples/slot/bundle/assets.json +1 -0
- package/engine-examples/slot/bundle/game.css +19 -0
- package/engine-examples/slot/bundle/game.js +42 -0
- package/engine-examples/slot/bundle/hbtest.json +4 -0
- package/engine-examples/slot/bundle/index.html +23 -0
- package/engine-examples/slot/math/gen.mjs +79 -0
- package/engine-examples/slot/math/manifest.json +1 -0
- package/engine-examples/slot/math/slot.tsv +110592 -0
- package/engine-examples/tower/AGENTS.md +3 -0
- package/engine-examples/tower/README.md +21 -0
- package/engine-examples/tower/bundle/assets.json +1 -0
- package/engine-examples/tower/bundle/game.css +8 -0
- package/engine-examples/tower/bundle/game.js +37 -0
- package/engine-examples/tower/bundle/hbtest.json +5 -0
- package/engine-examples/tower/bundle/index.html +16 -0
- package/engine-examples/tower/math/floor.tsv +4 -0
- package/engine-examples/tower/math/manifest.json +61 -0
- package/engine-examples/tumble/AGENTS.md +3 -0
- package/engine-examples/tumble/README.md +18 -0
- package/engine-examples/tumble/bundle/assets.json +1 -0
- package/engine-examples/tumble/bundle/game.css +13 -0
- package/engine-examples/tumble/bundle/game.js +119 -0
- package/engine-examples/tumble/bundle/hbtest.json +4 -0
- package/engine-examples/tumble/bundle/i18n.json +122 -0
- package/engine-examples/tumble/bundle/index.html +20 -0
- package/engine-examples/tumble/bundle/model.json +1 -0
- package/engine-examples/tumble/math/gen.mjs +38 -0
- package/engine-examples/tumble/math-kit/pack.mjs +165 -0
- package/engine-examples/tumble/math-kit/package.json +8 -0
- package/engine-examples/tumble/math-kit/slot.mjs +94 -0
- package/engine-examples/tumble/math-kit/tumble.mjs +94 -0
- package/engine-examples/wheel/README.md +14 -0
- package/engine-examples/wheel/bundle/assets.json +1 -0
- package/engine-examples/wheel/bundle/game.css +7 -0
- package/engine-examples/wheel/bundle/game.js +51 -0
- package/engine-examples/wheel/bundle/hbtest.json +4 -0
- package/engine-examples/wheel/bundle/index.html +19 -0
- package/engine-examples/wheel/math/high.tsv +24 -0
- package/engine-examples/wheel/math/low.tsv +24 -0
- package/engine-examples/wheel/math/manifest.json +48 -0
- package/engine-examples/wheel/math/medium.tsv +24 -0
- package/engine-math/pack.mjs +165 -0
- package/engine-math/package.json +1 -0
- package/engine-math/slot.mjs +94 -0
- package/engine-math/tumble.mjs +94 -0
- package/engine-mcp/package.json +1 -0
- package/engine-mcp/server.mjs +151 -0
- package/engine-sdk/GUIDE.md +855 -0
- package/engine-sdk/assets.js +92 -0
- package/engine-sdk/autoplay.js +82 -0
- package/engine-sdk/bet-field.js +391 -0
- package/engine-sdk/kit/fiat-coins.js +51 -0
- package/engine-sdk/kit/numeric-input.js +116 -0
- package/engine-sdk/kit/wallet-format.js +423 -0
- package/engine-sdk/marks.js +22 -0
- package/engine-sdk/messages.js +289 -0
- package/engine-sdk/money.js +89 -0
- package/engine-sdk/package.json +1 -0
- package/engine-sdk/protocol.js +263 -0
- package/engine-sdk/sdk.d.ts +138 -0
- package/engine-sdk/sdk.js +330 -0
- package/engine-sdk/stake.js +68 -0
- package/engine-sdk/ui.d.ts +36 -0
- package/engine-sdk/ui.js +340 -0
- package/engine-shell/core/faults.js +127 -0
- package/engine-shell/core/rgs.js +193 -0
- package/engine-shell/core/router.js +917 -0
- package/engine-shell/host/boot.js +408 -0
- package/engine-shell/host/engine-v1.js +438 -0
- package/engine-shell/host/fair.js +285 -0
- package/engine-shell/host/fonts/SOURCE.json +11 -0
- package/engine-shell/host/fonts/figtree-400.woff2 +0 -0
- package/engine-shell/host/fonts/figtree-500.woff2 +0 -0
- package/engine-shell/host/fonts/figtree-600.woff2 +0 -0
- package/engine-shell/host/fonts/red-hat-display-700.woff2 +0 -0
- package/engine-shell/host/index.html +230 -0
- package/engine-shell/host/page.js +809 -0
- package/engine-shell/host/sandbox-panel.js +681 -0
- package/engine-shell/host/sandbox-scenarios.js +554 -0
- package/engine-shell/host/site-bridge.js +87 -0
- package/engine-shell/host/strings.js +916 -0
- package/engine-shell/package.json +1 -0
- package/engine-shell/verifiers/badcat/coin.tsv +2 -0
- package/engine-shell/verifiers/badcat/dice-2.tsv +11 -0
- package/engine-shell/verifiers/badcat/dice-5.tsv +26 -0
- package/engine-shell/verifiers/badcat/dice-9.tsv +46 -0
- package/engine-shell/verifiers/badcat/manifest.json +3344 -0
- package/engine-shell/verifiers/badcat/rps.tsv +3 -0
- package/engine-shell/verifiers/badcat/triple.tsv +66 -0
- package/engine-shell/verifiers/engine-verify.js +358 -0
- package/engine-shell/verifiers/package.json +5 -0
- package/engine-shell/verifiers/parity/manifest.json +27 -0
- package/engine-shell/verifiers/parity/wide.tsv +5 -0
- package/engine-shell/verifiers/parity-vectors.json +244 -0
- package/engine-shell/verifiers/vectors.json +100 -0
- package/package.json +10 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/* GENERATED by tools/sync-kit.mjs from the Originals' dictionaries: do not edit. */
|
|
2
|
+
export const MESSAGES = {
|
|
3
|
+
"en": {
|
|
4
|
+
"betAmount": "Bet Amount",
|
|
5
|
+
"blockOverBalance": "Bet exceeds balance",
|
|
6
|
+
"blockOverMax": "Exceeds maximum bet amount of {amount} {currency}",
|
|
7
|
+
"blockUnderMin": "Minimum bet amount is {amount} {currency}",
|
|
8
|
+
"bet": "Bet",
|
|
9
|
+
"manual": "Manual",
|
|
10
|
+
"auto": "Auto",
|
|
11
|
+
"startAutobet": "Start Autobet",
|
|
12
|
+
"stopAutobet": "Stop Autobet",
|
|
13
|
+
"numberOfBets": "Number of bets (0 = infinite)",
|
|
14
|
+
"onWin": "On Win",
|
|
15
|
+
"onLoss": "On Loss",
|
|
16
|
+
"reset": "Reset",
|
|
17
|
+
"increase": "Increase",
|
|
18
|
+
"stopOnProfit": "Stop on Profit",
|
|
19
|
+
"stopOnLoss": "Stop on Loss",
|
|
20
|
+
"apiRateLimited": "Slow down and try again.",
|
|
21
|
+
"apiRoundUnresolved": "The round did not settle in time. Your balance will update on its own.",
|
|
22
|
+
"apiInternalError": "Something went wrong. Please try again.",
|
|
23
|
+
"cashOut": "Cash out"
|
|
24
|
+
},
|
|
25
|
+
"es": {
|
|
26
|
+
"betAmount": "Importe de la apuesta",
|
|
27
|
+
"blockOverBalance": "La apuesta supera el saldo",
|
|
28
|
+
"blockOverMax": "Supera la apuesta máxima de {amount} {currency}",
|
|
29
|
+
"blockUnderMin": "La apuesta mínima es de {amount} {currency}",
|
|
30
|
+
"bet": "Apostar",
|
|
31
|
+
"manual": "Manual",
|
|
32
|
+
"auto": "Auto",
|
|
33
|
+
"startAutobet": "Iniciar autoapuesta",
|
|
34
|
+
"stopAutobet": "Detener autoapuesta",
|
|
35
|
+
"numberOfBets": "Número de apuestas (0 = ilimitado)",
|
|
36
|
+
"onWin": "Al ganar",
|
|
37
|
+
"onLoss": "Al perder",
|
|
38
|
+
"reset": "Reset",
|
|
39
|
+
"increase": "Subir",
|
|
40
|
+
"stopOnProfit": "Parar en ganancia",
|
|
41
|
+
"stopOnLoss": "Parar en pérdida",
|
|
42
|
+
"apiRateLimited": "Más despacio, inténtalo de nuevo.",
|
|
43
|
+
"apiRoundUnresolved": "La ronda no se resolvió a tiempo. Tu saldo se actualizará por sí solo.",
|
|
44
|
+
"apiInternalError": "Algo salió mal. Inténtalo de nuevo.",
|
|
45
|
+
"cashOut": "Retirar"
|
|
46
|
+
},
|
|
47
|
+
"hu": {
|
|
48
|
+
"betAmount": "Tét összege",
|
|
49
|
+
"blockOverBalance": "A tét meghaladja az egyenleget",
|
|
50
|
+
"blockOverMax": "Meghaladja a maximális tétet: {amount} {currency}",
|
|
51
|
+
"blockUnderMin": "A minimális tét {amount} {currency}",
|
|
52
|
+
"bet": "Fogadás",
|
|
53
|
+
"manual": "Kézi",
|
|
54
|
+
"auto": "Auto",
|
|
55
|
+
"startAutobet": "Autofogadás indítása",
|
|
56
|
+
"stopAutobet": "Autofogadás leállítása",
|
|
57
|
+
"numberOfBets": "Fogadások száma (0 = végtelen)",
|
|
58
|
+
"onWin": "Nyerésnél",
|
|
59
|
+
"onLoss": "Vesztésnél",
|
|
60
|
+
"reset": "Reset",
|
|
61
|
+
"increase": "Növelés",
|
|
62
|
+
"stopOnProfit": "Leállítás nyereségnél",
|
|
63
|
+
"stopOnLoss": "Leállítás veszteségnél",
|
|
64
|
+
"apiRateLimited": "Lassabban, próbáld újra.",
|
|
65
|
+
"apiRoundUnresolved": "A kör nem zárult le időben. Az egyenleg magától frissül.",
|
|
66
|
+
"apiInternalError": "Valami hiba történt. Próbáld újra.",
|
|
67
|
+
"cashOut": "Kiszállás"
|
|
68
|
+
},
|
|
69
|
+
"fr": {
|
|
70
|
+
"betAmount": "Montant du pari",
|
|
71
|
+
"blockOverBalance": "La mise dépasse le solde",
|
|
72
|
+
"blockOverMax": "Dépasse la mise maximale de {amount} {currency}",
|
|
73
|
+
"blockUnderMin": "La mise minimale est de {amount} {currency}",
|
|
74
|
+
"bet": "Parier",
|
|
75
|
+
"manual": "Manuel",
|
|
76
|
+
"auto": "Auto",
|
|
77
|
+
"startAutobet": "Lancer l'autobet",
|
|
78
|
+
"stopAutobet": "Arrêter l'autobet",
|
|
79
|
+
"numberOfBets": "Nombre de paris (0 = illimité)",
|
|
80
|
+
"onWin": "En cas de gain",
|
|
81
|
+
"onLoss": "En cas de perte",
|
|
82
|
+
"reset": "Réinit.",
|
|
83
|
+
"increase": "Hausse",
|
|
84
|
+
"stopOnProfit": "Arrêt sur gain",
|
|
85
|
+
"stopOnLoss": "Arrêt sur perte",
|
|
86
|
+
"apiRateLimited": "Doucement, réessayez.",
|
|
87
|
+
"apiRoundUnresolved": "La partie ne s'est pas dénouée à temps. Votre solde se mettra à jour de lui-même.",
|
|
88
|
+
"apiInternalError": "Une erreur est survenue. Réessayez.",
|
|
89
|
+
"cashOut": "Encaisser"
|
|
90
|
+
},
|
|
91
|
+
"ru": {
|
|
92
|
+
"betAmount": "Сумма ставки",
|
|
93
|
+
"blockOverBalance": "Ставка больше баланса",
|
|
94
|
+
"blockOverMax": "Больше максимальной ставки {amount} {currency}",
|
|
95
|
+
"blockUnderMin": "Минимальная сумма ставки — {amount} {currency}",
|
|
96
|
+
"bet": "Ставка",
|
|
97
|
+
"manual": "Вручную",
|
|
98
|
+
"auto": "Авто",
|
|
99
|
+
"startAutobet": "Запустить автобет",
|
|
100
|
+
"stopAutobet": "Остановить автобет",
|
|
101
|
+
"numberOfBets": "Число ставок (0 — без ограничения)",
|
|
102
|
+
"onWin": "При выигрыше",
|
|
103
|
+
"onLoss": "При проигрыше",
|
|
104
|
+
"reset": "Сброс",
|
|
105
|
+
"increase": "Рост",
|
|
106
|
+
"stopOnProfit": "Стоп при прибыли",
|
|
107
|
+
"stopOnLoss": "Стоп при убытке",
|
|
108
|
+
"apiRateLimited": "Помедленнее, попробуйте ещё раз.",
|
|
109
|
+
"apiRoundUnresolved": "Раунд не разрешился в срок. Баланс обновится сам.",
|
|
110
|
+
"apiInternalError": "Что-то пошло не так. Попробуйте ещё раз.",
|
|
111
|
+
"cashOut": "Забрать"
|
|
112
|
+
},
|
|
113
|
+
"pt": {
|
|
114
|
+
"betAmount": "Valor da aposta",
|
|
115
|
+
"blockOverBalance": "A aposta excede o saldo",
|
|
116
|
+
"blockOverMax": "Excede a aposta máxima de {amount} {currency}",
|
|
117
|
+
"blockUnderMin": "A aposta mínima é de {amount} {currency}",
|
|
118
|
+
"bet": "Apostar",
|
|
119
|
+
"manual": "Manual",
|
|
120
|
+
"auto": "Auto",
|
|
121
|
+
"startAutobet": "Iniciar aposta automática",
|
|
122
|
+
"stopAutobet": "Parar aposta automática",
|
|
123
|
+
"numberOfBets": "Número de apostas (0 = ilimitado)",
|
|
124
|
+
"onWin": "Ao ganhar",
|
|
125
|
+
"onLoss": "Ao perder",
|
|
126
|
+
"reset": "Redefinir",
|
|
127
|
+
"increase": "Subir",
|
|
128
|
+
"stopOnProfit": "Parar no lucro",
|
|
129
|
+
"stopOnLoss": "Parar na perda",
|
|
130
|
+
"apiRateLimited": "Mais devagar, tente novamente.",
|
|
131
|
+
"apiRoundUnresolved": "A rodada não foi liquidada em tempo. Seu saldo será atualizado sozinho.",
|
|
132
|
+
"apiInternalError": "Algo deu errado. Tente novamente.",
|
|
133
|
+
"cashOut": "Sacar"
|
|
134
|
+
},
|
|
135
|
+
"id": {
|
|
136
|
+
"betAmount": "Jumlah taruhan",
|
|
137
|
+
"blockOverBalance": "Taruhan melebihi saldo",
|
|
138
|
+
"blockOverMax": "Melebihi taruhan maksimum {amount} {currency}",
|
|
139
|
+
"blockUnderMin": "Taruhan minimum adalah {amount} {currency}",
|
|
140
|
+
"bet": "Bertaruh",
|
|
141
|
+
"manual": "Manual",
|
|
142
|
+
"auto": "Otomatis",
|
|
143
|
+
"startAutobet": "Mulai taruhan otomatis",
|
|
144
|
+
"stopAutobet": "Hentikan taruhan otomatis",
|
|
145
|
+
"numberOfBets": "Jumlah taruhan (0 = tanpa batas)",
|
|
146
|
+
"onWin": "Saat menang",
|
|
147
|
+
"onLoss": "Saat kalah",
|
|
148
|
+
"reset": "Reset",
|
|
149
|
+
"increase": "Naikkan",
|
|
150
|
+
"stopOnProfit": "Berhenti saat profit",
|
|
151
|
+
"stopOnLoss": "Berhenti saat rugi",
|
|
152
|
+
"apiRateLimited": "Pelan-pelan, coba lagi.",
|
|
153
|
+
"apiRoundUnresolved": "Putaran tidak selesai tepat waktu. Saldo Anda akan diperbarui sendiri.",
|
|
154
|
+
"apiInternalError": "Terjadi kesalahan. Coba lagi.",
|
|
155
|
+
"cashOut": "Cash out"
|
|
156
|
+
},
|
|
157
|
+
"de": {
|
|
158
|
+
"betAmount": "Einsatz",
|
|
159
|
+
"blockOverBalance": "Einsatz übersteigt das Guthaben",
|
|
160
|
+
"blockOverMax": "Übersteigt den Höchsteinsatz von {amount} {currency}",
|
|
161
|
+
"blockUnderMin": "Der Mindesteinsatz beträgt {amount} {currency}",
|
|
162
|
+
"bet": "Wetten",
|
|
163
|
+
"manual": "Manuell",
|
|
164
|
+
"auto": "Auto",
|
|
165
|
+
"startAutobet": "Autobet starten",
|
|
166
|
+
"stopAutobet": "Autobet stoppen",
|
|
167
|
+
"numberOfBets": "Anzahl Wetten (0 = unbegrenzt)",
|
|
168
|
+
"onWin": "Bei Gewinn",
|
|
169
|
+
"onLoss": "Bei Verlust",
|
|
170
|
+
"reset": "Reset",
|
|
171
|
+
"increase": "Erhöhen",
|
|
172
|
+
"stopOnProfit": "Stop bei Gewinn",
|
|
173
|
+
"stopOnLoss": "Stop bei Verlust",
|
|
174
|
+
"apiRateLimited": "Langsamer, bitte erneut versuchen.",
|
|
175
|
+
"apiRoundUnresolved": "Die Runde wurde nicht rechtzeitig abgerechnet. Ihr Guthaben aktualisiert sich von selbst.",
|
|
176
|
+
"apiInternalError": "Etwas ist schiefgelaufen. Bitte erneut versuchen.",
|
|
177
|
+
"cashOut": "Auszahlen"
|
|
178
|
+
},
|
|
179
|
+
"ko": {
|
|
180
|
+
"betAmount": "베팅 금액",
|
|
181
|
+
"blockOverBalance": "베팅이 잔액을 초과합니다",
|
|
182
|
+
"blockOverMax": "최대 베팅 금액 {amount} {currency}을(를) 초과합니다",
|
|
183
|
+
"blockUnderMin": "최소 베팅 금액은 {amount} {currency}입니다",
|
|
184
|
+
"bet": "베팅",
|
|
185
|
+
"manual": "수동",
|
|
186
|
+
"auto": "자동",
|
|
187
|
+
"startAutobet": "자동 베팅 시작",
|
|
188
|
+
"stopAutobet": "자동 베팅 중지",
|
|
189
|
+
"numberOfBets": "베팅 횟수 (0 = 무제한)",
|
|
190
|
+
"onWin": "승리 시",
|
|
191
|
+
"onLoss": "패배 시",
|
|
192
|
+
"reset": "초기화",
|
|
193
|
+
"increase": "증가",
|
|
194
|
+
"stopOnProfit": "수익 도달 시 중지",
|
|
195
|
+
"stopOnLoss": "손실 도달 시 중지",
|
|
196
|
+
"apiRateLimited": "조금 천천히, 다시 시도해 주세요.",
|
|
197
|
+
"apiRoundUnresolved": "라운드가 제때 정산되지 않았습니다. 잔액은 자동으로 업데이트됩니다.",
|
|
198
|
+
"apiInternalError": "문제가 발생했습니다. 다시 시도해 주세요.",
|
|
199
|
+
"cashOut": "캐시아웃"
|
|
200
|
+
},
|
|
201
|
+
"tr": {
|
|
202
|
+
"betAmount": "Bahis tutarı",
|
|
203
|
+
"blockOverBalance": "Bahis bakiyeyi aşıyor",
|
|
204
|
+
"blockOverMax": "Maksimum bahis tutarı {amount} {currency} değerini aşıyor",
|
|
205
|
+
"blockUnderMin": "Minimum bahis tutarı {amount} {currency}",
|
|
206
|
+
"bet": "Bahis yap",
|
|
207
|
+
"manual": "Manuel",
|
|
208
|
+
"auto": "Oto",
|
|
209
|
+
"startAutobet": "Otomatik bahsi başlat",
|
|
210
|
+
"stopAutobet": "Otomatik bahsi durdur",
|
|
211
|
+
"numberOfBets": "Bahis sayısı (0 = sınırsız)",
|
|
212
|
+
"onWin": "Kazanınca",
|
|
213
|
+
"onLoss": "Kaybedince",
|
|
214
|
+
"reset": "Sıfırla",
|
|
215
|
+
"increase": "Artır",
|
|
216
|
+
"stopOnProfit": "Kârda durdur",
|
|
217
|
+
"stopOnLoss": "Zararda durdur",
|
|
218
|
+
"apiRateLimited": "Biraz yavaş, tekrar deneyin.",
|
|
219
|
+
"apiRoundUnresolved": "Tur zamanında sonuçlanmadı. Bakiyeniz kendiliğinden güncellenecek.",
|
|
220
|
+
"apiInternalError": "Bir şeyler ters gitti. Tekrar deneyin.",
|
|
221
|
+
"cashOut": "Nakit al"
|
|
222
|
+
},
|
|
223
|
+
"zh": {
|
|
224
|
+
"betAmount": "投注金额",
|
|
225
|
+
"blockOverBalance": "投注超出余额",
|
|
226
|
+
"blockOverMax": "超出最高投注额 {amount} {currency}",
|
|
227
|
+
"blockUnderMin": "最低投注金额为 {amount} {currency}",
|
|
228
|
+
"bet": "投注",
|
|
229
|
+
"manual": "手动",
|
|
230
|
+
"auto": "自动",
|
|
231
|
+
"startAutobet": "开始自动投注",
|
|
232
|
+
"stopAutobet": "停止自动投注",
|
|
233
|
+
"numberOfBets": "投注次数(0 = 无限)",
|
|
234
|
+
"onWin": "获胜时",
|
|
235
|
+
"onLoss": "失败时",
|
|
236
|
+
"reset": "重置",
|
|
237
|
+
"increase": "增加",
|
|
238
|
+
"stopOnProfit": "达到利润时停止",
|
|
239
|
+
"stopOnLoss": "达到亏损时停止",
|
|
240
|
+
"apiRateLimited": "请慢一点,稍后重试。",
|
|
241
|
+
"apiRoundUnresolved": "本轮未能及时结算。您的余额将自动更新。",
|
|
242
|
+
"apiInternalError": "出现问题,请重试。",
|
|
243
|
+
"cashOut": "提现"
|
|
244
|
+
},
|
|
245
|
+
"vi": {
|
|
246
|
+
"betAmount": "Số tiền cược",
|
|
247
|
+
"blockOverBalance": "Tiền cược vượt quá số dư",
|
|
248
|
+
"blockOverMax": "Vượt quá mức cược tối đa {amount} {currency}",
|
|
249
|
+
"blockUnderMin": "Số tiền cược tối thiểu là {amount} {currency}",
|
|
250
|
+
"bet": "Cược",
|
|
251
|
+
"manual": "Thủ công",
|
|
252
|
+
"auto": "Tự động",
|
|
253
|
+
"startAutobet": "Bắt đầu tự cược",
|
|
254
|
+
"stopAutobet": "Dừng tự cược",
|
|
255
|
+
"numberOfBets": "Số lượt cược (0 = không giới hạn)",
|
|
256
|
+
"onWin": "Khi thắng",
|
|
257
|
+
"onLoss": "Khi thua",
|
|
258
|
+
"reset": "Đặt lại",
|
|
259
|
+
"increase": "Tăng",
|
|
260
|
+
"stopOnProfit": "Dừng khi đạt lợi nhuận",
|
|
261
|
+
"stopOnLoss": "Dừng khi thua lỗ",
|
|
262
|
+
"apiRateLimited": "Chậm lại, hãy thử lại.",
|
|
263
|
+
"apiRoundUnresolved": "Vòng chơi chưa được quyết toán kịp thời. Số dư của bạn sẽ tự cập nhật.",
|
|
264
|
+
"apiInternalError": "Đã xảy ra lỗi. Hãy thử lại.",
|
|
265
|
+
"cashOut": "Rút tiền"
|
|
266
|
+
},
|
|
267
|
+
"ja": {
|
|
268
|
+
"betAmount": "ベット額",
|
|
269
|
+
"blockOverBalance": "ベット額が残高を超えています",
|
|
270
|
+
"blockOverMax": "最大ベット額 {amount} {currency} を超えています",
|
|
271
|
+
"blockUnderMin": "最低ベット額は {amount} {currency} です",
|
|
272
|
+
"bet": "ベット",
|
|
273
|
+
"manual": "手動",
|
|
274
|
+
"auto": "オート",
|
|
275
|
+
"startAutobet": "オートベット開始",
|
|
276
|
+
"stopAutobet": "オートベット停止",
|
|
277
|
+
"numberOfBets": "ベット回数(0 = 無制限)",
|
|
278
|
+
"onWin": "勝利時",
|
|
279
|
+
"onLoss": "敗北時",
|
|
280
|
+
"reset": "リセット",
|
|
281
|
+
"increase": "増やす",
|
|
282
|
+
"stopOnProfit": "利益で停止",
|
|
283
|
+
"stopOnLoss": "損失で停止",
|
|
284
|
+
"apiRateLimited": "少しゆっくり、もう一度お試しください。",
|
|
285
|
+
"apiRoundUnresolved": "ラウンドが時間内に精算されませんでした。残高は自動的に更新されます。",
|
|
286
|
+
"apiInternalError": "問題が発生しました。もう一度お試しください。",
|
|
287
|
+
"cashOut": "キャッシュアウト"
|
|
288
|
+
}
|
|
289
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Money on screen, exactly as the House Originals show it: the Originals' own
|
|
3
|
+
* code (@housegames/game-kit core/wallet-format.js and numeric-input.js,
|
|
4
|
+
* carried unchanged in kit/ and held to the source by kit.test.js), so a
|
|
5
|
+
* studio game and Dice can never disagree about a currency.
|
|
6
|
+
*
|
|
7
|
+
* The wallet is the platform's currency for the session (what our own games
|
|
8
|
+
* receive as currentlycurrency): any Housebets coin, shown in the coin or in
|
|
9
|
+
* the player's fiat at the platform's rate. What a player types is in the
|
|
10
|
+
* field's unit (euros in a EUR display); toWallet turns it into the wallet
|
|
11
|
+
* amount, truncated to the wallet's precision, and that is what engine.play
|
|
12
|
+
* takes. Balances and payouts come from the server and are only formatted.
|
|
13
|
+
*
|
|
14
|
+
* Every picture is ours and travels inside the SDK: the site's coin marks
|
|
15
|
+
* (marks.js) and the Originals' fiat coins (kit/fiat-coins.js).
|
|
16
|
+
*/
|
|
17
|
+
import * as kit from './kit/wallet-format.js';
|
|
18
|
+
import { fiatCoinSrc } from './kit/fiat-coins.js';
|
|
19
|
+
import { sanitizeDecimal, filterNumericInput } from './kit/numeric-input.js';
|
|
20
|
+
import { COIN_MARKS, LOGO_MARK } from './marks.js';
|
|
21
|
+
|
|
22
|
+
export { sanitizeDecimal, filterNumericInput };
|
|
23
|
+
|
|
24
|
+
/** The mark of a currency code: our coin for a fiat, the site's for a coin,
|
|
25
|
+
* the logo for a coin it has no picture of. */
|
|
26
|
+
export function markOf(code) {
|
|
27
|
+
const c = String(code || '').trim().toUpperCase();
|
|
28
|
+
return fiatCoinSrc(c) || COIN_MARKS[c] || LOGO_MARK;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The money helpers bound to one session's wallet. */
|
|
32
|
+
export function moneyFor(w) {
|
|
33
|
+
const fiatView = kit.isFiatView(w);
|
|
34
|
+
// The wallet's own currency: in a fiat display the platform renames
|
|
35
|
+
// `symbol` to the fiat and keeps the coin in `name` (wallet-format.js).
|
|
36
|
+
const coin = (w && (w.name || w.symbol)) || '';
|
|
37
|
+
return Object.freeze({
|
|
38
|
+
wallet: w,
|
|
39
|
+
coin,
|
|
40
|
+
isFiat: fiatView,
|
|
41
|
+
unit: kit.viewUnit(w),
|
|
42
|
+
sign: kit.fieldSign(w),
|
|
43
|
+
decimals: kit.viewPrecision(w),
|
|
44
|
+
walletDecimals: kit.walletPrecision(w),
|
|
45
|
+
mark: markOf(fiatView ? kit.viewUnit(w) : coin),
|
|
46
|
+
/** One smallest wallet unit (10⁻⁸ for a coin): the precision a stake is cut to, never a
|
|
47
|
+
* bet button's increment, and neither is the minimum bet — bet up / down walks levels()
|
|
48
|
+
* (a slot's €0.10, €0.20, €0.50 …). */
|
|
49
|
+
step: 10 ** -kit.walletPrecision(w),
|
|
50
|
+
toView: (amount) => kit.viewFromWallet(amount, w),
|
|
51
|
+
toWallet: (value) => kit.walletFromView(value, w),
|
|
52
|
+
format: (amount) => kit.fmtView(amount, w),
|
|
53
|
+
caption: (amount) => kit.counterText(amount, w),
|
|
54
|
+
parse: (text) => kit.parseView(text, w),
|
|
55
|
+
payout: (amount, mult) => kit.payoutAtWalletPrecision(amount, mult, w),
|
|
56
|
+
filter: (input) => filterNumericInput(input, 'decimal'),
|
|
57
|
+
levels: (min, max) => betLevels(w, min, max),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Bet levels as a slot shows them: round stakes in the player's display unit
|
|
63
|
+
* (1, 2, 5 × a power of ten: €0.10, €0.20, €0.50, €1, €2 … or 0.0001 BTC …),
|
|
64
|
+
* each with the wallet amount engine.play takes, its text as the header
|
|
65
|
+
* formats it, and its label as a bet button says it. Only the levels
|
|
66
|
+
* between min and max (wallet units, engine.config.limits) whose wallet amount
|
|
67
|
+
* shows back as the same round number: a stake the player sees is the stake
|
|
68
|
+
* that is sent, and no converted limit ("2,000.62019200 USDT") is ever offered.
|
|
69
|
+
* At most 24, from the smallest up.
|
|
70
|
+
*/
|
|
71
|
+
export function betLevels(w, min = 0, max = Infinity) {
|
|
72
|
+
const dp = kit.viewPrecision(w);
|
|
73
|
+
const out = [];
|
|
74
|
+
for (let e = -dp; e <= 9 && out.length < 24; e++) {
|
|
75
|
+
for (const k of [1, 2, 5]) {
|
|
76
|
+
const view = Number((k * 10 ** e).toFixed(Math.max(0, -e)));
|
|
77
|
+
const amount = kit.walletFromView(view, w);
|
|
78
|
+
if (!(amount > 0) || amount < min || amount > max) continue;
|
|
79
|
+
if (Math.abs(kit.viewFromWallet(amount, w) - view) > 10 ** -dp / 2) continue; // would not show as the round number
|
|
80
|
+
const text = kit.fmtView(amount, w);
|
|
81
|
+
// The level as a button says it: €2.00 in a fiat display, 2 USDT / 0.0005 BTC in a coin
|
|
82
|
+
// (a round level needs none of the wallet's trailing zeros).
|
|
83
|
+
const label = kit.isFiatView(w) ? kit.fieldSign(w) + text : `${text.includes('.') ? text.replace(/\.?0+$/, '') : text} ${kit.viewUnit(w)}`;
|
|
84
|
+
out.push({ view, amount, text, label });
|
|
85
|
+
if (out.length === 24) break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "module" }
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The message contract between the engine shell (our code) and a studio game
|
|
3
|
+
* (theirs), which runs in a sandboxed iframe with no network of its own.
|
|
4
|
+
*
|
|
5
|
+
* The shell is the only client of the engine API. The game asks it for
|
|
6
|
+
* everything — a bet, an action, its saved state — and the shell answers with
|
|
7
|
+
* what the server said. Nothing the game sends can move money by itself: a
|
|
8
|
+
* request is a wish the server decides on, and the balance and outcome the
|
|
9
|
+
* game shows are the ones the shell hands back. A bet is also the player's
|
|
10
|
+
* act: the shell takes a play only on the player's click (the browser's user
|
|
11
|
+
* activation, which a click inside the game frame hands the shell) or inside
|
|
12
|
+
* an autoplay session the player started, so a game cannot bet on its own.
|
|
13
|
+
*
|
|
14
|
+
* Every message is one envelope:
|
|
15
|
+
*
|
|
16
|
+
* { hb: 1, kind: 'req', id, type, body } game -> shell, answered
|
|
17
|
+
* { hb: 1, kind: 'res', id, ok: true, body } shell -> game, the answer
|
|
18
|
+
* { hb: 1, kind: 'res', id, ok: false, error } shell -> game, a refusal
|
|
19
|
+
* { hb: 1, kind: 'evt', type, body } either way, not answered
|
|
20
|
+
*
|
|
21
|
+
* Both sides drop anything that does not validate here, without answering:
|
|
22
|
+
* a malformed message is never a reason to act. The sender is checked by
|
|
23
|
+
* window, not by origin — a sandboxed frame's origin is the string "null",
|
|
24
|
+
* which any other sandboxed frame shares.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export const PROTOCOL = 1;
|
|
28
|
+
|
|
29
|
+
/** Requests the game may make; each is answered exactly once. */
|
|
30
|
+
export const REQUESTS = Object.freeze({
|
|
31
|
+
PLAY: 'play',
|
|
32
|
+
ACTION: 'action',
|
|
33
|
+
ROUND: 'round',
|
|
34
|
+
STATE_GET: 'state.get',
|
|
35
|
+
STATE_PUT: 'state.put',
|
|
36
|
+
// Autoplay is the shell's: the game asks for a session (on the player's
|
|
37
|
+
// click; the shell confirms it with the player in its own dialog) and
|
|
38
|
+
// plays inside it; the shell counts the rounds, holds the plays to the
|
|
39
|
+
// bet and the stake granted, shows its own Stop and ends it. The game
|
|
40
|
+
// cannot run bets on its own.
|
|
41
|
+
AUTOPLAY_START: 'autoplay.start',
|
|
42
|
+
AUTOPLAY_STOP: 'autoplay.stop',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/** The most rounds one autoplay session may hold. */
|
|
46
|
+
export const AUTOPLAY_MAX_ROUNDS = 1000;
|
|
47
|
+
|
|
48
|
+
/** Events the game may send; none is answered and none is trusted for money. */
|
|
49
|
+
export const GAME_EVENTS = Object.freeze({
|
|
50
|
+
HELLO: 'hello',
|
|
51
|
+
READY: 'ready',
|
|
52
|
+
LOADING: 'loading',
|
|
53
|
+
REVEALED: 'revealed',
|
|
54
|
+
FAIRNESS: 'fairness.open',
|
|
55
|
+
ERROR: 'error',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
/** Events the shell sends the game. */
|
|
59
|
+
export const SHELL_EVENTS = Object.freeze({
|
|
60
|
+
INIT: 'init',
|
|
61
|
+
BALANCE: 'balance',
|
|
62
|
+
CONTROL: 'control',
|
|
63
|
+
PAUSE: 'pause',
|
|
64
|
+
RESUME: 'resume',
|
|
65
|
+
ENDED: 'ended',
|
|
66
|
+
// The autoplay session changed: {active, left, played, stake?, reason?}.
|
|
67
|
+
// Sent when one starts, after each of its plays, and when it ends
|
|
68
|
+
// (reason: stopped, done, profit, loss, refused, paused, ended).
|
|
69
|
+
AUTOPLAY: 'autoplay',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/** Refusal codes the shell answers with. The game shows the message; the
|
|
73
|
+
* code tells it whether trying again can help. */
|
|
74
|
+
export const ERRORS = Object.freeze({
|
|
75
|
+
INVALID: 'invalid', // the request does not validate; never retry
|
|
76
|
+
BUSY: 'busy', // another play/action is still with the server
|
|
77
|
+
INSUFFICIENT: 'insufficient-balance',
|
|
78
|
+
LIMITS: 'limits', // below min, above max, or over the max win
|
|
79
|
+
PACING: 'pacing', // too fast; retry after retryAfterMs
|
|
80
|
+
PENDING: 'pending', // the wallet has not answered yet; retry after retryAfterMs
|
|
81
|
+
UNAVAILABLE: 'unavailable', // the game is paused or the server is down
|
|
82
|
+
SESSION: 'session-ended', // the session is over; the shell will say so
|
|
83
|
+
ROUND: 'round', // no such round, it moved on or closed, or one is already open
|
|
84
|
+
// (the refusal carries the round as it stands: redraw it)
|
|
85
|
+
CONFLICT: 'conflict', // state.put with a stale revision
|
|
86
|
+
SERVER: 'server',
|
|
87
|
+
CLICK: 'needs-click', // no click of the player's behind the bet, the step, the cash-out
|
|
88
|
+
// or the autoplay request (or a browser that cannot confirm one,
|
|
89
|
+
// or the click was on the shell's own controls); ask again from
|
|
90
|
+
// the player's click handler, after retryAfterMs when given
|
|
91
|
+
AUTOPLAY: 'autoplay', // autoplay refused: not allowed for the player, one already
|
|
92
|
+
// running or asked for, cancelled a moment ago (retryAfterMs), or
|
|
93
|
+
// a play outside the session's bet, stake or count
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
/** The most a saved state may weigh, as the server counts it. */
|
|
97
|
+
export const STATE_MAX_BYTES = 256 * 1024;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The most a player may stake on one bet under the maximum win per round, as
|
|
101
|
+
* the session's `limits.maxStake[mode][bet]` names it (SPEC §3.1): a decimal
|
|
102
|
+
* string in the wallet coin at its precision, rounded down by the server so
|
|
103
|
+
* that stake × the bet's top multiplier stays within the cap. A high
|
|
104
|
+
* multiplier means a low figure. A figure of 0 is a figure: the server names
|
|
105
|
+
* it for every bet while the coin has no USD rate to price the cap in, and
|
|
106
|
+
* refuses every stake meanwhile (503, `unavailable`), so nothing can be
|
|
107
|
+
* staked until the rate is back. null only when the session names none for
|
|
108
|
+
* the bet (an older server, a sandbox without limits, a malformed value):
|
|
109
|
+
* then the coin's `limits.max` alone holds here, and the server is the last
|
|
110
|
+
* word anyway.
|
|
111
|
+
*/
|
|
112
|
+
export function maxStakeFor(limits, mode, bet) {
|
|
113
|
+
if (!isObject(limits) || !isObject(limits.maxStake) || !Object.hasOwn(limits.maxStake, mode)) return null;
|
|
114
|
+
const byMode = limits.maxStake[mode];
|
|
115
|
+
if (!isObject(byMode) || !Object.hasOwn(byMode, bet)) return null;
|
|
116
|
+
const v = byMode[bet];
|
|
117
|
+
const n = typeof v === 'number' ? v : typeof v === 'string' && /^\d+(\.\d+)?$/.test(v) ? Number(v) : NaN;
|
|
118
|
+
return Number.isFinite(n) && n >= 0 ? n : null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const ID_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
122
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]{0,31}$/;
|
|
123
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
124
|
+
const GROUP_RE = /^[a-z0-9][a-z0-9-]{0,31}$/;
|
|
125
|
+
|
|
126
|
+
const isObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
127
|
+
const isCount = (v) => Number.isSafeInteger(v) && v >= 0;
|
|
128
|
+
const keysWithin = (o, allowed) => Object.keys(o).every((k) => allowed.includes(k));
|
|
129
|
+
|
|
130
|
+
/** Body validators: each returns null when the body is acceptable, else why not. */
|
|
131
|
+
const REQUEST_BODY = {
|
|
132
|
+
[REQUESTS.PLAY]: (b) => {
|
|
133
|
+
if (!keysWithin(b, ['mode', 'bet', 'amount'])) return 'unknown key';
|
|
134
|
+
if (typeof b.mode !== 'string' || !SLUG_RE.test(b.mode)) return 'mode';
|
|
135
|
+
if (typeof b.bet !== 'string' || !SLUG_RE.test(b.bet)) return 'bet';
|
|
136
|
+
// A stake is a positive amount: there is no free round (a round that
|
|
137
|
+
// costs nothing would still consume a nonce of the player's seed
|
|
138
|
+
// pair), so a play of 0 is not a play and never reaches the shell's
|
|
139
|
+
// money path. The SDK refuses it with a reason before it is sent.
|
|
140
|
+
if (typeof b.amount !== 'number' || !Number.isFinite(b.amount) || b.amount <= 0) return 'amount';
|
|
141
|
+
return null;
|
|
142
|
+
},
|
|
143
|
+
// `step` is the step the game saw the round at (the round's own `step`):
|
|
144
|
+
// an action decided on an older view is refused, never applied late.
|
|
145
|
+
[REQUESTS.ACTION]: (b) => {
|
|
146
|
+
if (!keysWithin(b, ['roundId', 'step', 'action'])) return 'unknown key';
|
|
147
|
+
if (typeof b.roundId !== 'string' || !UUID_RE.test(b.roundId)) return 'roundId';
|
|
148
|
+
if (!isCount(b.step)) return 'step';
|
|
149
|
+
if (b.action !== 'advance' && b.action !== 'cashout') return 'action';
|
|
150
|
+
return null;
|
|
151
|
+
},
|
|
152
|
+
[REQUESTS.ROUND]: (b) => {
|
|
153
|
+
if (!keysWithin(b, ['roundId'])) return 'unknown key';
|
|
154
|
+
return typeof b.roundId === 'string' && UUID_RE.test(b.roundId) ? null : 'roundId';
|
|
155
|
+
},
|
|
156
|
+
[REQUESTS.STATE_GET]: (b) => (Object.keys(b).length === 0 ? null : 'unknown key'),
|
|
157
|
+
[REQUESTS.STATE_PUT]: (b) => {
|
|
158
|
+
if (!keysWithin(b, ['revision', 'data'])) return 'unknown key';
|
|
159
|
+
if (!isCount(b.revision)) return 'revision';
|
|
160
|
+
if (!isObject(b.data)) return 'data';
|
|
161
|
+
if (utf8Length(JSON.stringify(b.data)) > STATE_MAX_BYTES) return 'data too large';
|
|
162
|
+
return null;
|
|
163
|
+
},
|
|
164
|
+
// A session of at most `rounds` plays of one bet (`mode`, `bet`: the run
|
|
165
|
+
// is for that bet and no other), none above `stake`; the two stops end it
|
|
166
|
+
// when the session's net result reaches the figure (profit up, loss
|
|
167
|
+
// down). Every figure is in wallet units.
|
|
168
|
+
[REQUESTS.AUTOPLAY_START]: (b) => {
|
|
169
|
+
if (!keysWithin(b, ['mode', 'bet', 'rounds', 'stake', 'stopOnProfit', 'stopOnLoss'])) return 'unknown key';
|
|
170
|
+
if (typeof b.mode !== 'string' || !SLUG_RE.test(b.mode)) return 'mode';
|
|
171
|
+
if (typeof b.bet !== 'string' || !SLUG_RE.test(b.bet)) return 'bet';
|
|
172
|
+
if (!Number.isSafeInteger(b.rounds) || b.rounds < 1 || b.rounds > AUTOPLAY_MAX_ROUNDS) return 'rounds';
|
|
173
|
+
if (!isMoney(b.stake)) return 'stake';
|
|
174
|
+
if (b.stopOnProfit !== undefined && !isMoney(b.stopOnProfit)) return 'stopOnProfit';
|
|
175
|
+
if (b.stopOnLoss !== undefined && !isMoney(b.stopOnLoss)) return 'stopOnLoss';
|
|
176
|
+
return null;
|
|
177
|
+
},
|
|
178
|
+
[REQUESTS.AUTOPLAY_STOP]: (b) => (Object.keys(b).length === 0 ? null : 'unknown key'),
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const isMoney = (v) => typeof v === 'number' && Number.isFinite(v) && v > 0;
|
|
182
|
+
|
|
183
|
+
const GAME_EVENT_BODY = {
|
|
184
|
+
// The game's page is up and asks for its config; repeated until answered.
|
|
185
|
+
[GAME_EVENTS.HELLO]: (b) => (Object.keys(b).length === 0 ? null : 'unknown key'),
|
|
186
|
+
[GAME_EVENTS.READY]: (b) => (Object.keys(b).length === 0 ? null : 'unknown key'),
|
|
187
|
+
[GAME_EVENTS.LOADING]: (b) => {
|
|
188
|
+
if (!keysWithin(b, ['group', 'loaded', 'total'])) return 'unknown key';
|
|
189
|
+
if (typeof b.group !== 'string' || !GROUP_RE.test(b.group)) return 'group';
|
|
190
|
+
if (!isCount(b.loaded) || !isCount(b.total) || b.loaded > b.total) return 'progress';
|
|
191
|
+
return null;
|
|
192
|
+
},
|
|
193
|
+
// The outcome of a round is on screen; the shell moves the site's header
|
|
194
|
+
// balance now (or at its own deadline, whichever is first).
|
|
195
|
+
[GAME_EVENTS.REVEALED]: (b) => {
|
|
196
|
+
if (!keysWithin(b, ['roundId'])) return 'unknown key';
|
|
197
|
+
return typeof b.roundId === 'string' && UUID_RE.test(b.roundId) ? null : 'roundId';
|
|
198
|
+
},
|
|
199
|
+
[GAME_EVENTS.FAIRNESS]: (b) => {
|
|
200
|
+
if (!keysWithin(b, ['roundId'])) return 'unknown key';
|
|
201
|
+
return typeof b.roundId === 'string' && UUID_RE.test(b.roundId) ? null : 'roundId';
|
|
202
|
+
},
|
|
203
|
+
[GAME_EVENTS.ERROR]: (b) => {
|
|
204
|
+
if (!keysWithin(b, ['message'])) return 'unknown key';
|
|
205
|
+
return typeof b.message === 'string' && b.message.length <= 500 ? null : 'message';
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
function utf8Length(s) {
|
|
210
|
+
return new TextEncoder().encode(s).length;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Validates a message a game sent. Returns the message when the shell may act
|
|
215
|
+
* on it, else null.
|
|
216
|
+
*/
|
|
217
|
+
export function readGameMessage(data) {
|
|
218
|
+
if (!isObject(data) || data.hb !== PROTOCOL || !isObject(data.body)) return null;
|
|
219
|
+
if (data.kind === 'req') {
|
|
220
|
+
if (!keysWithin(data, ['hb', 'kind', 'id', 'type', 'body'])) return null;
|
|
221
|
+
if (typeof data.id !== 'string' || !ID_RE.test(data.id)) return null;
|
|
222
|
+
const check = Object.hasOwn(REQUEST_BODY, data.type) ? REQUEST_BODY[data.type] : null;
|
|
223
|
+
return check && check(data.body) === null ? data : null;
|
|
224
|
+
}
|
|
225
|
+
if (data.kind === 'evt') {
|
|
226
|
+
if (!keysWithin(data, ['hb', 'kind', 'type', 'body'])) return null;
|
|
227
|
+
const check = Object.hasOwn(GAME_EVENT_BODY, data.type) ? GAME_EVENT_BODY[data.type] : null;
|
|
228
|
+
return check && check(data.body) === null ? data : null;
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Validates a message the shell sent. Returns it when the game may act on
|
|
235
|
+
* it, else null. The game trusts the shell (it is the page that framed it),
|
|
236
|
+
* so this only guards against foreign or broken messages.
|
|
237
|
+
*/
|
|
238
|
+
export function readShellMessage(data) {
|
|
239
|
+
if (!isObject(data) || data.hb !== PROTOCOL) return null;
|
|
240
|
+
if (data.kind === 'res') {
|
|
241
|
+
if (typeof data.id !== 'string' || !ID_RE.test(data.id) || typeof data.ok !== 'boolean') return null;
|
|
242
|
+
if (data.ok) return isObject(data.body) ? data : null;
|
|
243
|
+
return isObject(data.error) && typeof data.error.code === 'string' ? data : null;
|
|
244
|
+
}
|
|
245
|
+
if (data.kind === 'evt') {
|
|
246
|
+
return Object.values(SHELL_EVENTS).includes(data.type) && isObject(data.body) ? data : null;
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export const request = (id, type, body) => ({ hb: PROTOCOL, kind: 'req', id, type, body });
|
|
252
|
+
export const answer = (id, body) => ({ hb: PROTOCOL, kind: 'res', id, ok: true, body });
|
|
253
|
+
// `maxStake` rides on a `limits` refusal over the maximum win per round (SPEC
|
|
254
|
+
// §3.1): the most the bet takes, as the server wrote it (a decimal string at
|
|
255
|
+
// the coin's precision), so the game can set its field to the figure.
|
|
256
|
+
export const refuse = (id, code, message, retryAfterMs, round, maxStake) => {
|
|
257
|
+
const error = { code, message };
|
|
258
|
+
if (retryAfterMs > 0) error.retryAfterMs = retryAfterMs;
|
|
259
|
+
if (round) error.round = round;
|
|
260
|
+
if (typeof maxStake === 'string' && maxStake !== '') error.maxStake = maxStake;
|
|
261
|
+
return { hb: PROTOCOL, kind: 'res', id, ok: false, error };
|
|
262
|
+
};
|
|
263
|
+
export const event = (type, body = {}) => ({ hb: PROTOCOL, kind: 'evt', type, body });
|