Implemented AI (“Rando”), refactored card rendering.
This commit is contained in:
@@ -32,6 +32,8 @@
|
||||
"allowTypedFunctionExpressions": true,
|
||||
"allowHigherOrderFunctions": true
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
"@typescript-eslint/no-empty-interface": "off"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+203
-155
@@ -5,18 +5,18 @@
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
|
||||
"integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
|
||||
"version": "7.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
|
||||
"integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
|
||||
"integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
|
||||
"integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.0.0",
|
||||
@@ -154,6 +154,12 @@
|
||||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz",
|
||||
"integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/json-stable-stringify": {
|
||||
"version": "1.0.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.32.tgz",
|
||||
@@ -237,9 +243,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz",
|
||||
"integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==",
|
||||
"version": "3.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.5.tgz",
|
||||
"integrity": "sha512-MNL15wC3EKyw1VLF+RoVO4hJJdk9t/Hlv3rt1OL65Qvuadm4BYo6g9ZJQqoq7X8NBFSsQXgAujWciovh2lpVjA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
@@ -262,12 +268,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.11.0.tgz",
|
||||
"integrity": "sha512-mXv9ccCou89C8/4avKHuPB2WkSZyY/XcTQUXd5LFZAcLw1I3mWYVjUu6eS9Ja0QkP/ClolbcW9tb3Ov/pMdcqw==",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz",
|
||||
"integrity": "sha512-WQHCozMnuNADiqMtsNzp96FNox5sOVpU8Xt4meaT4em8lOG1SrOv92/mUbEHQVh90sldKSfcOc/I0FOb/14G1g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "1.11.0",
|
||||
"@typescript-eslint/experimental-utils": "1.13.0",
|
||||
"eslint-utils": "^1.3.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"regexpp": "^2.0.1",
|
||||
@@ -275,31 +281,32 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.11.0.tgz",
|
||||
"integrity": "sha512-7LbfaqF6B8oa8cp/315zxKk8FFzosRzzhF8Kn/ZRsRsnpm7Qcu25cR/9RnAQo5utZ2KIWVgaALr+ZmcbG47ruw==",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz",
|
||||
"integrity": "sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "1.11.0",
|
||||
"@types/json-schema": "^7.0.3",
|
||||
"@typescript-eslint/typescript-estree": "1.13.0",
|
||||
"eslint-scope": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.11.0.tgz",
|
||||
"integrity": "sha512-5xBExyXaxVyczrZvbRKEXvaTUFFq7gIM9BynXukXZE0zF3IQP/FxF4mPmmh3gJ9egafZFqByCpPTFm3dk4SY7Q==",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.13.0.tgz",
|
||||
"integrity": "sha512-ITMBs52PCPgLb2nGPoeT4iU3HdQZHcPaZVw+7CsFagRJHUhyeTgorEwHXhFf3e7Evzi8oujKNpHc8TONth8AdQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/eslint-visitor-keys": "^1.0.0",
|
||||
"@typescript-eslint/experimental-utils": "1.11.0",
|
||||
"@typescript-eslint/typescript-estree": "1.11.0",
|
||||
"@typescript-eslint/experimental-utils": "1.13.0",
|
||||
"@typescript-eslint/typescript-estree": "1.13.0",
|
||||
"eslint-visitor-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.11.0.tgz",
|
||||
"integrity": "sha512-fquUHF5tAx1sM2OeRCC7wVxFd1iMELWMGCzOSmJ3pLzArj9+kRixdlC4d5MncuzXpjEqc6045p3KwM0o/3FuUA==",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz",
|
||||
"integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash.unescape": "4.0.1",
|
||||
@@ -330,9 +337,9 @@
|
||||
}
|
||||
},
|
||||
"acorn": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
|
||||
"integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz",
|
||||
"integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==",
|
||||
"dev": true
|
||||
},
|
||||
"acorn-jsx": {
|
||||
@@ -342,9 +349,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
|
||||
"integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
|
||||
"version": "6.10.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
|
||||
"integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -871,12 +878,6 @@
|
||||
"text-hex": "1.0.x"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"component-emitter": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||
@@ -912,9 +913,9 @@
|
||||
}
|
||||
},
|
||||
"content-security-policy-builder": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.0.0.tgz",
|
||||
"integrity": "sha512-j+Nhmj1yfZAikJLImCvPJFE29x/UuBi+/MWqggGGc515JKaZrjuei2RhULJmy0MsstW3E3htl002bwmBNMKr7w=="
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz",
|
||||
"integrity": "sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ=="
|
||||
},
|
||||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
@@ -1067,9 +1068,9 @@
|
||||
}
|
||||
},
|
||||
"dns-prefetch-control": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz",
|
||||
"integrity": "sha1-YN20V3dOF48flBXwyrsOhbCzALI="
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz",
|
||||
"integrity": "sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q=="
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "3.0.0",
|
||||
@@ -1081,9 +1082,9 @@
|
||||
}
|
||||
},
|
||||
"dont-sniff-mimetype": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz",
|
||||
"integrity": "sha1-WTKJDcn04vGeXrAqIAJuXl78j1g="
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz",
|
||||
"integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug=="
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "4.2.0",
|
||||
@@ -1157,9 +1158,9 @@
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"eslint": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz",
|
||||
"integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.1.0.tgz",
|
||||
"integrity": "sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
@@ -1168,7 +1169,7 @@
|
||||
"cross-spawn": "^6.0.5",
|
||||
"debug": "^4.0.1",
|
||||
"doctrine": "^3.0.0",
|
||||
"eslint-scope": "^4.0.3",
|
||||
"eslint-scope": "^5.0.0",
|
||||
"eslint-utils": "^1.3.1",
|
||||
"eslint-visitor-keys": "^1.0.0",
|
||||
"espree": "^6.0.0",
|
||||
@@ -1176,30 +1177,37 @@
|
||||
"esutils": "^2.0.2",
|
||||
"file-entry-cache": "^5.0.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"glob-parent": "^3.1.0",
|
||||
"glob-parent": "^5.0.0",
|
||||
"globals": "^11.7.0",
|
||||
"ignore": "^4.0.6",
|
||||
"import-fresh": "^3.0.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"inquirer": "^6.2.2",
|
||||
"inquirer": "^6.4.1",
|
||||
"is-glob": "^4.0.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.3.0",
|
||||
"lodash": "^4.17.11",
|
||||
"lodash": "^4.17.14",
|
||||
"minimatch": "^3.0.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.8.2",
|
||||
"progress": "^2.0.0",
|
||||
"regexpp": "^2.0.1",
|
||||
"semver": "^5.5.1",
|
||||
"strip-ansi": "^4.0.0",
|
||||
"strip-json-comments": "^2.0.1",
|
||||
"semver": "^6.1.2",
|
||||
"strip-ansi": "^5.2.0",
|
||||
"strip-json-comments": "^3.0.1",
|
||||
"table": "^5.2.3",
|
||||
"text-table": "^0.2.0"
|
||||
"text-table": "^0.2.0",
|
||||
"v8-compile-cache": "^2.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
||||
@@ -1211,6 +1219,14 @@
|
||||
"semver": "^5.5.0",
|
||||
"shebang-command": "^1.2.0",
|
||||
"which": "^1.2.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
@@ -1222,11 +1238,57 @@
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
|
||||
"integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esrecurse": "^4.1.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz",
|
||||
"integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
|
||||
"integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1259,10 +1321,13 @@
|
||||
}
|
||||
},
|
||||
"eslint-utils": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
|
||||
"integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
|
||||
"dev": true
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz",
|
||||
"integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-visitor-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"eslint-visitor-keys": {
|
||||
"version": "1.0.0",
|
||||
@@ -1420,9 +1485,9 @@
|
||||
"integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng=="
|
||||
},
|
||||
"express-winston": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/express-winston/-/express-winston-3.2.0.tgz",
|
||||
"integrity": "sha512-AcVSV016U7aPs1Uknoil962SU124UgNkdakP564X6w+lH0oS1FhV3uctUj2/dOog7np4uvsAHhBmSoICjZMDmA==",
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/express-winston/-/express-winston-3.2.1.tgz",
|
||||
"integrity": "sha512-yh49mpFcoLAFs4yuplIutTAqs+jgRQYB2bLoDTpMvQDARzQKHvABfj2PYMPfmk087+OsEBJmm96i6//q9RJnnw==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.1",
|
||||
"lodash": "^4.17.10"
|
||||
@@ -1458,9 +1523,9 @@
|
||||
}
|
||||
},
|
||||
"external-editor": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
|
||||
"integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chardet": "^0.7.0",
|
||||
@@ -2406,25 +2471,25 @@
|
||||
"integrity": "sha512-dEHCG2LraR6PNvSGxosZHIRgxF5sNLOIBFEHbj8lfP9WWmu/PWPMzsip1drdVSOFi51N2pU7gZavrgn7sbGFuw=="
|
||||
},
|
||||
"helmet": {
|
||||
"version": "3.18.0",
|
||||
"resolved": "https://registry.npmjs.org/helmet/-/helmet-3.18.0.tgz",
|
||||
"integrity": "sha512-TsKlGE5UVkV0NiQ4PllV9EVfZklPjyzcMEMjWlyI/8S6epqgRT+4s4GHVgc25x0TixsKvp3L7c91HQQt5l0+QA==",
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/helmet/-/helmet-3.20.0.tgz",
|
||||
"integrity": "sha512-Ob+TqmQFZ5f7WgP8kBbAzNPsbf6p1lOj5r+327/ymw/IILWih3wcx9u/u/S8Mwv5wbBkO7Li6x5s23t3COhUKw==",
|
||||
"requires": {
|
||||
"depd": "2.0.0",
|
||||
"dns-prefetch-control": "0.1.0",
|
||||
"dont-sniff-mimetype": "1.0.0",
|
||||
"dns-prefetch-control": "0.2.0",
|
||||
"dont-sniff-mimetype": "1.1.0",
|
||||
"expect-ct": "0.2.0",
|
||||
"feature-policy": "0.3.0",
|
||||
"frameguard": "3.1.0",
|
||||
"helmet-crossdomain": "0.3.0",
|
||||
"helmet-csp": "2.7.1",
|
||||
"hide-powered-by": "1.0.0",
|
||||
"helmet-crossdomain": "0.4.0",
|
||||
"helmet-csp": "2.8.0",
|
||||
"hide-powered-by": "1.1.0",
|
||||
"hpkp": "2.0.0",
|
||||
"hsts": "2.2.0",
|
||||
"ienoopen": "1.1.0",
|
||||
"nocache": "2.1.0",
|
||||
"referrer-policy": "1.2.0",
|
||||
"x-xss-protection": "1.1.0"
|
||||
"x-xss-protection": "1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"depd": {
|
||||
@@ -2435,25 +2500,25 @@
|
||||
}
|
||||
},
|
||||
"helmet-crossdomain": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.3.0.tgz",
|
||||
"integrity": "sha512-YiXhj0E35nC4Na5EPE4mTfoXMf9JTGpN4OtB4aLqShKuH9d2HNaJX5MQoglO6STVka0uMsHyG5lCut5Kzsy7Lg=="
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz",
|
||||
"integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA=="
|
||||
},
|
||||
"helmet-csp": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.7.1.tgz",
|
||||
"integrity": "sha512-sCHwywg4daQ2mY0YYwXSZRsgcCeerUwxMwNixGA7aMLkVmPTYBl7gJoZDHOZyXkqPrtuDT3s2B1A+RLI7WxSdQ==",
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.8.0.tgz",
|
||||
"integrity": "sha512-MlCPeM0Sm3pS9RACRihx70VeTHmkQwa7sum9EK1tfw1VZyvFU0dBWym9nHh3CRkTRNlyNm/WFCMvuh9zXkOjNw==",
|
||||
"requires": {
|
||||
"camelize": "1.0.0",
|
||||
"content-security-policy-builder": "2.0.0",
|
||||
"content-security-policy-builder": "2.1.0",
|
||||
"dasherize": "2.0.0",
|
||||
"platform": "1.3.5"
|
||||
}
|
||||
},
|
||||
"hide-powered-by": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.0.0.tgz",
|
||||
"integrity": "sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys="
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz",
|
||||
"integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg=="
|
||||
},
|
||||
"hpkp": {
|
||||
"version": "2.0.0",
|
||||
@@ -2518,9 +2583,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"import-fresh": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz",
|
||||
"integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz",
|
||||
"integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"parent-module": "^1.0.0",
|
||||
@@ -2561,9 +2626,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.4.1.tgz",
|
||||
"integrity": "sha512-/Jw+qPZx4EDYsaT6uz7F4GJRNFMRdKNeUZw3ZnKV8lyuUgz/YWRCSUAJMZSVhSq4Ec0R2oYnyi6b3d4JXcL5Nw==",
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz",
|
||||
"integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-escapes": "^3.2.0",
|
||||
@@ -2572,7 +2637,7 @@
|
||||
"cli-width": "^2.0.0",
|
||||
"external-editor": "^3.0.3",
|
||||
"figures": "^2.0.0",
|
||||
"lodash": "^4.17.11",
|
||||
"lodash": "^4.17.12",
|
||||
"mute-stream": "0.0.7",
|
||||
"run-async": "^2.2.0",
|
||||
"rxjs": "^6.4.0",
|
||||
@@ -2587,6 +2652,12 @@
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
@@ -2976,9 +3047,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.11",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
||||
},
|
||||
"lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
@@ -3175,9 +3246,9 @@
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||
},
|
||||
"mixin-deep": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
|
||||
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
|
||||
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"for-in": "^1.0.2",
|
||||
@@ -3954,9 +4025,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"set-value": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
|
||||
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
|
||||
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
@@ -4269,13 +4340,13 @@
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-5.4.1.tgz",
|
||||
"integrity": "sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w==",
|
||||
"version": "5.4.4",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-5.4.4.tgz",
|
||||
"integrity": "sha512-IIfEAUx5QlODLblLrGTTLJA7Tk0iLSGBvgY8essPRVNGHAzThujww1YqHLs6h3HfTg55h++RzLHH5Xw/rfv+mg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.9.1",
|
||||
"lodash": "^4.17.11",
|
||||
"ajv": "^6.10.2",
|
||||
"lodash": "^4.17.14",
|
||||
"slice-ansi": "^2.1.0",
|
||||
"string-width": "^3.0.0"
|
||||
},
|
||||
@@ -4286,6 +4357,12 @@
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
@@ -4410,18 +4487,6 @@
|
||||
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
|
||||
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
|
||||
},
|
||||
"ts-json-schema-generator": {
|
||||
"version": "0.50.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-0.50.2.tgz",
|
||||
"integrity": "sha512-S6n8kHpU2y7IJvr07rA2Xn9wbKRWTs31jvgpFQnkWn4n7jWXOj/yGEzp1UN/qQOBB0r3qSZjsOMr2KzuaSWTGA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "~2.20.0",
|
||||
"glob": "~7.1.4",
|
||||
"json-stable-stringify": "^1.0.1",
|
||||
"typescript": "~3.5.2"
|
||||
}
|
||||
},
|
||||
"ts-postgres": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-postgres/-/ts-postgres-1.1.0.tgz",
|
||||
@@ -4454,9 +4519,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "3.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz",
|
||||
"integrity": "sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==",
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.1.tgz",
|
||||
"integrity": "sha512-kiuZzD1uUA5DxGj/uxbde+ymp6VVdAxdzOIlAFbYKrPyla8/uiJ9JLBm1QsPhOm4Muj0/+cWEDP99yoCUcSl6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.8.1"
|
||||
@@ -4481,9 +4546,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz",
|
||||
"integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==",
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
|
||||
"integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-json-schema": {
|
||||
@@ -4543,38 +4608,15 @@
|
||||
}
|
||||
},
|
||||
"union-value": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
|
||||
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
|
||||
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arr-union": "^3.1.0",
|
||||
"get-value": "^2.0.6",
|
||||
"is-extendable": "^0.1.1",
|
||||
"set-value": "^0.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"set-value": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
|
||||
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-extendable": "^0.1.1",
|
||||
"is-plain-object": "^2.0.1",
|
||||
"to-object-path": "^0.3.0"
|
||||
}
|
||||
}
|
||||
"set-value": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"unique-string": {
|
||||
@@ -4705,6 +4747,12 @@
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
|
||||
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz",
|
||||
"integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==",
|
||||
"dev": true
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
@@ -4856,9 +4904,9 @@
|
||||
"integrity": "sha1-fnLj+6I+D/Zp3dU34chX09SxYU8="
|
||||
},
|
||||
"x-xss-protection": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.1.0.tgz",
|
||||
"integrity": "sha512-rx3GzJlgEeZ08MIcDsU2vY2B1QEriUKJTSiNHHUIem6eg9pzVOr2TL3Y4Pd6TMAM5D5azGjcxqI62piITBDHVg=="
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.2.0.tgz",
|
||||
"integrity": "sha512-xN0kV+8XfOQM2OPPBdEbGtbvJNNP1pvZR7sE6d44cjJFQG4OiGDdienPg5iOUGswBTiGbBvtYDURd30BMJwwqg=="
|
||||
},
|
||||
"xdg-basedir": {
|
||||
"version": "3.0.0",
|
||||
|
||||
+8
-8
@@ -25,16 +25,16 @@
|
||||
"config.json5"
|
||||
],
|
||||
"dependencies": {
|
||||
"ajv": "^6.10.0",
|
||||
"ajv": "^6.10.2",
|
||||
"axios": "^0.19.0",
|
||||
"body-parser": "^1.19.0",
|
||||
"express": "^4.17.1",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"express-winston": "^3.2.0",
|
||||
"express-winston": "^3.2.1",
|
||||
"express-ws": "^4.0.0",
|
||||
"generic-pool": "^3.7.1",
|
||||
"hashids": "^1.2.2",
|
||||
"helmet": "^3.18.0",
|
||||
"helmet": "^3.20.0",
|
||||
"http-status-codes": "^1.3.2",
|
||||
"json5": "^2.1.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
@@ -55,16 +55,16 @@
|
||||
"@types/json5": "0.0.30",
|
||||
"@types/jsonwebtoken": "^8.3.2",
|
||||
"@types/source-map-support": "^0.5.0",
|
||||
"@types/uuid": "^3.4.4",
|
||||
"@types/uuid": "^3.4.5",
|
||||
"@types/wu": "^2.1.39",
|
||||
"@typescript-eslint/eslint-plugin": "^1.11.0",
|
||||
"@typescript-eslint/parser": "^1.11.0",
|
||||
"eslint": "^6.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^1.13.0",
|
||||
"@typescript-eslint/parser": "^1.13.0",
|
||||
"eslint": "^6.1.0",
|
||||
"eslint-config-prettier": "^6.0.0",
|
||||
"eslint-plugin-prettier": "^3.1.0",
|
||||
"nodemon": "^1.19.1",
|
||||
"prettier": "1.18.2",
|
||||
"typescript": "^3.5.2",
|
||||
"typescript": "^3.5.3",
|
||||
"typescript-json-validator": "^2.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as rules from "../../../games/rules";
|
||||
import { Handler } from "../../handler";
|
||||
import * as configure from "../configure";
|
||||
import * as houseRuleChanged from "../../../events/lobby-event/configured/house-rule-changed";
|
||||
import * as rando from "../../../games/rules/rando";
|
||||
|
||||
/**
|
||||
* Set the hand size for the lobby.
|
||||
@@ -24,24 +25,40 @@ export const is = (action: Action): action is ChangeHouseRule =>
|
||||
action.action === name;
|
||||
|
||||
export const handle: Handler<ChangeHouseRule> = (auth, lobby, action) => {
|
||||
const houseRules = lobby.config.rules.houseRules;
|
||||
const hr = lobby.config.rules.houseRules;
|
||||
const events = [];
|
||||
let changed = false;
|
||||
switch (action.change.houseRule) {
|
||||
case "PackingHeat":
|
||||
houseRules.packingHeat = action.change.settings;
|
||||
if (hr.packingHeat !== action.change.settings) {
|
||||
hr.packingHeat = action.change.settings;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
case "Rando":
|
||||
houseRules.rando = action.change.settings;
|
||||
const userEvents = rando.change(lobby, hr.rando, action.change.settings);
|
||||
if (userEvents !== null) {
|
||||
events.push(...userEvents);
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
case "Reboot":
|
||||
houseRules.reboot = action.change.settings;
|
||||
if (hr.reboot !== action.change.settings) {
|
||||
hr.reboot = action.change.settings;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
lobby.config.version += 1;
|
||||
|
||||
return {
|
||||
lobby,
|
||||
events: [
|
||||
if (changed) {
|
||||
lobby.config.version += 1;
|
||||
events.push(
|
||||
event.targetAll(houseRuleChanged.of(action.change, lobby.config.version))
|
||||
]
|
||||
};
|
||||
);
|
||||
return {
|
||||
lobby,
|
||||
events
|
||||
};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as card from "../../games/cards/card";
|
||||
import * as round from "../../games/game/round";
|
||||
import * as publicRound from "../../games/game/round/public";
|
||||
|
||||
/**
|
||||
@@ -11,10 +12,10 @@ export interface GameStarted {
|
||||
}
|
||||
|
||||
export const of = (
|
||||
round: publicRound.Playing,
|
||||
startedRound: round.Playing,
|
||||
hand?: card.Response[]
|
||||
): GameStarted => ({
|
||||
event: "GameStarted",
|
||||
round,
|
||||
round: round.censor(startedRound),
|
||||
...(hand !== undefined ? { hand } : {})
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as card from "../../games/cards/card";
|
||||
import { Round } from "../../games/game/round";
|
||||
import * as user from "../../user";
|
||||
import * as round from "../../games/game/round";
|
||||
|
||||
/**
|
||||
* Indicates a new round has started.
|
||||
@@ -14,17 +14,11 @@ export interface RoundStarted {
|
||||
drawn?: card.Response[];
|
||||
}
|
||||
|
||||
export const of = (
|
||||
id: round.Id,
|
||||
czar: user.Id,
|
||||
players: user.Id[],
|
||||
call: card.Call,
|
||||
drawn?: card.Response[]
|
||||
): RoundStarted => ({
|
||||
export const of = (round: Round, drawn?: card.Response[]): RoundStarted => ({
|
||||
event: "RoundStarted",
|
||||
id: id.toString(),
|
||||
czar,
|
||||
players,
|
||||
call,
|
||||
id: round.id.toString(),
|
||||
czar: round.czar,
|
||||
players: Array.from(round.players.keys()),
|
||||
call: round.call,
|
||||
...(drawn === undefined ? {} : { drawn })
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { User } from "../../user";
|
||||
import * as user from "../../user";
|
||||
|
||||
/**
|
||||
@@ -15,12 +16,16 @@ interface Base {
|
||||
export interface Joined extends Base {
|
||||
event: "Joined";
|
||||
name: user.Name;
|
||||
privilege?: user.Privilege;
|
||||
control?: user.Control;
|
||||
}
|
||||
|
||||
export const joined = (user: user.Id, name: user.Name): Joined => ({
|
||||
export const joined = (id: user.Id, user: User): Joined => ({
|
||||
event: "Joined",
|
||||
user,
|
||||
name
|
||||
user: id,
|
||||
name: user.name,
|
||||
...(user.privilege !== "Unprivileged" ? { privilege: user.privilege } : {}),
|
||||
...(user.control !== "Human" ? { control: user.control } : {})
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
+103
-5
@@ -1,7 +1,16 @@
|
||||
import * as event from "../event";
|
||||
import * as gameStarted from "../events/game-event/game-started";
|
||||
import * as playSubmitted from "../events/game-event/play-submitted";
|
||||
import * as roundStarted from "../events/game-event/round-started";
|
||||
import { ServerState } from "../server-state";
|
||||
import * as finishedPlaying from "../timeout/finished-playing";
|
||||
import { User } from "../user";
|
||||
import * as user from "../user";
|
||||
import * as util from "../util";
|
||||
import * as card from "./cards/card";
|
||||
import { Decks } from "./cards/decks";
|
||||
import * as decks from "./cards/decks";
|
||||
import * as play from "./cards/play";
|
||||
import * as round from "./game/round";
|
||||
import { Round } from "./game/round";
|
||||
import * as publicRound from "./game/round/public";
|
||||
@@ -10,6 +19,8 @@ import * as player from "./player";
|
||||
import { Player } from "./player";
|
||||
import * as rules from "./rules";
|
||||
import { Rules } from "./rules";
|
||||
import * as lobby from "../lobby";
|
||||
import * as timeout from "../timeout";
|
||||
import wu from "wu";
|
||||
|
||||
/**
|
||||
@@ -45,7 +56,6 @@ export const censor: (game: Game) => Public = game => ({
|
||||
|
||||
const newPlayerForUser = (decks: Decks, rules: Rules): Player => ({
|
||||
hand: decks.responses.draw(rules.handSize),
|
||||
control: "Human",
|
||||
score: 0
|
||||
});
|
||||
|
||||
@@ -79,8 +89,96 @@ export const start = (
|
||||
};
|
||||
};
|
||||
|
||||
export const nextCzar = (game: Game): user.Id => {
|
||||
const current = game.round.czar;
|
||||
const index = game.playerOrder.findIndex(id => id === current) + 1;
|
||||
return game.playerOrder[index >= game.playerOrder.length ? 0 : index];
|
||||
export const atStartOfRound = (
|
||||
server: ServerState,
|
||||
first: boolean,
|
||||
game: Game & { round: round.Playing }
|
||||
): {
|
||||
game: Game & { round: round.Playing };
|
||||
events?: Iterable<event.Distributor>;
|
||||
timeouts?: Iterable<timeout.TimeoutAfter>;
|
||||
} => {
|
||||
const slotCount = card.slotCount(game.round.call);
|
||||
|
||||
const events = [];
|
||||
if (
|
||||
slotCount > 2 ||
|
||||
(slotCount === 2 && game.rules.houseRules.packingHeat !== undefined)
|
||||
) {
|
||||
const responseDeck = game.decks.responses;
|
||||
const drawnByPlayer = new Map();
|
||||
for (const [id, playerState] of game.players) {
|
||||
if (player.role(game, id) === "Player") {
|
||||
const drawn = responseDeck.draw(slotCount - 1);
|
||||
drawnByPlayer.set(id, { drawn });
|
||||
playerState.hand.push(...drawn);
|
||||
}
|
||||
}
|
||||
if (!first) {
|
||||
events.push(
|
||||
event.additionally(roundStarted.of(game.round), drawnByPlayer)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!first) {
|
||||
events.push(event.targetAll(roundStarted.of(game.round)));
|
||||
}
|
||||
}
|
||||
|
||||
if (first) {
|
||||
events.push(
|
||||
event.playerSpecificAddition(
|
||||
gameStarted.of(game.round),
|
||||
(id, user, player) => ({
|
||||
hand: player.hand
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const ais = game.rules.houseRules.rando.current;
|
||||
for (const ai of ais) {
|
||||
const player = game.players.get(ai) as Player;
|
||||
const plays = game.round.plays;
|
||||
const playId = play.id();
|
||||
plays.push({
|
||||
id: playId,
|
||||
play: player.hand.slice(0, slotCount),
|
||||
playedBy: ai,
|
||||
revealed: false
|
||||
});
|
||||
events.push(event.targetAll(playSubmitted.of(ai)));
|
||||
}
|
||||
|
||||
const timeouts = [];
|
||||
const timeout = finishedPlaying.ifNeeded(game.round);
|
||||
if (timeout !== undefined) {
|
||||
timeouts.push({
|
||||
timeout: timeout,
|
||||
after: server.config.timeouts.finishedPlayingDelay
|
||||
});
|
||||
}
|
||||
|
||||
return { game, events, timeouts };
|
||||
};
|
||||
|
||||
const canBeCzar = (user: User): boolean =>
|
||||
user.control !== "Computer" &&
|
||||
user.presence === "Joined" &&
|
||||
user.role === "Player";
|
||||
|
||||
const czarAfter = (lobby: lobby.WithActiveGame, nextIndex: number): user.Id => {
|
||||
const game = lobby.game;
|
||||
const potentialCzar =
|
||||
game.playerOrder[nextIndex >= game.playerOrder.length ? 0 : nextIndex];
|
||||
return canBeCzar(lobby.users.get(potentialCzar) as User)
|
||||
? potentialCzar
|
||||
: czarAfter(lobby, nextIndex + 1);
|
||||
};
|
||||
|
||||
export const nextCzar = (lobby: lobby.WithActiveGame): user.Id => {
|
||||
const game = lobby.game;
|
||||
const current = game.round.czar;
|
||||
const nextIndex = game.playerOrder.findIndex(id => id === current) + 1;
|
||||
return czarAfter(lobby, nextIndex);
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@ import { Game } from "./game";
|
||||
*/
|
||||
export interface Player {
|
||||
hand: Hand;
|
||||
control: Control;
|
||||
score: Score;
|
||||
}
|
||||
|
||||
@@ -15,7 +14,6 @@ export interface Player {
|
||||
* A player containing only state all users can see.
|
||||
*/
|
||||
export interface Public {
|
||||
control: Control;
|
||||
score: Score;
|
||||
}
|
||||
|
||||
@@ -24,11 +22,6 @@ export interface Public {
|
||||
*/
|
||||
export type Role = "Czar" | "Player";
|
||||
|
||||
/**
|
||||
* Who controls the player.
|
||||
*/
|
||||
export type Control = "Human" | "Computer";
|
||||
|
||||
/**
|
||||
* How many points the player has scored.
|
||||
* @TJS-type integer
|
||||
@@ -40,7 +33,6 @@ export type Score = number;
|
||||
* Produce a public version of the given player.
|
||||
*/
|
||||
export const censor = (player: Player): Public => ({
|
||||
control: player.control,
|
||||
score: player.score
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
/** The rules for a standard game.*/
|
||||
import { HouseRules } from "./rules/houseRules";
|
||||
import * as houseRules from "./rules/houseRules";
|
||||
import * as rando from "./rules/rando";
|
||||
|
||||
/** The rules for a standard game.
|
||||
*/
|
||||
export interface Rules {
|
||||
/**
|
||||
* The number of cards in each player's hand.
|
||||
@@ -21,13 +26,7 @@ export interface Rules {
|
||||
export interface Public {
|
||||
handSize: number;
|
||||
scoreLimit?: number;
|
||||
houseRules: HouseRules;
|
||||
}
|
||||
|
||||
export interface HouseRules {
|
||||
packingHeat?: PackingHeat;
|
||||
reboot?: Reboot;
|
||||
rando?: Rando;
|
||||
houseRules: houseRules.Public;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,13 +35,12 @@ export interface HouseRules {
|
||||
export const create = (): Rules => ({
|
||||
handSize: 10,
|
||||
scoreLimit: 25,
|
||||
houseRules: {}
|
||||
houseRules: houseRules.create()
|
||||
});
|
||||
|
||||
/**
|
||||
* Configuration for the "Packing Heat" house rule.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface PackingHeat {}
|
||||
|
||||
/**
|
||||
@@ -60,18 +58,9 @@ export interface Reboot {
|
||||
cost: number;
|
||||
}
|
||||
|
||||
export interface Rando {
|
||||
/**
|
||||
* The number of AI players to add to the game.
|
||||
* @TJS-type integer
|
||||
* @minimum 1
|
||||
* @maximum 10
|
||||
*/
|
||||
number: number;
|
||||
}
|
||||
|
||||
export const censor = (rules: Rules): Public => ({
|
||||
...rules
|
||||
...rules,
|
||||
houseRules: houseRules.censor(rules.houseRules)
|
||||
});
|
||||
|
||||
export interface ChangeBase<Name extends string, HouseRule> {
|
||||
@@ -80,7 +69,7 @@ export interface ChangeBase<Name extends string, HouseRule> {
|
||||
}
|
||||
|
||||
export type ChangePackingHeat = ChangeBase<"PackingHeat", PackingHeat>;
|
||||
export type ChangeRando = ChangeBase<"Rando", Rando>;
|
||||
export type ChangeRando = ChangeBase<"Rando", rando.Public>;
|
||||
export type ChangeReboot = ChangeBase<"Reboot", Reboot>;
|
||||
|
||||
export type Change = ChangePackingHeat | ChangeRando | ChangeReboot;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { PackingHeat, Reboot, Rules } from "../rules";
|
||||
import { Rando } from "./rando";
|
||||
import * as rando from "./rando";
|
||||
|
||||
/**
|
||||
* Non-standard rules that can be applied to a game.
|
||||
*/
|
||||
export interface HouseRules {
|
||||
packingHeat?: PackingHeat;
|
||||
reboot?: Reboot;
|
||||
rando: Rando;
|
||||
}
|
||||
|
||||
/**
|
||||
* The public view of the internal model.
|
||||
*/
|
||||
export interface Public {
|
||||
packingHeat?: PackingHeat;
|
||||
reboot?: Reboot;
|
||||
rando?: rando.Public;
|
||||
}
|
||||
|
||||
export const create = (): HouseRules => ({
|
||||
rando: rando.create()
|
||||
});
|
||||
|
||||
export const censor = (houseRules: HouseRules): Public => ({
|
||||
...houseRules,
|
||||
rando: rando.censor(houseRules.rando)
|
||||
});
|
||||
@@ -0,0 +1,149 @@
|
||||
import { RegisterUser } from "../../action/initial/register-user";
|
||||
import * as event from "../../event";
|
||||
import * as presenceChanged from "../../events/lobby-event/presence-changed";
|
||||
import { Lobby } from "../../lobby";
|
||||
import * as lobby from "../../lobby";
|
||||
import { User } from "../../user";
|
||||
import * as util from "../../util";
|
||||
import * as user from "../../user";
|
||||
|
||||
/**
|
||||
* The maximum number of AI players allowed in a single game.
|
||||
*/
|
||||
const max = 10;
|
||||
|
||||
/**
|
||||
* The default name for an AI.
|
||||
*/
|
||||
export const aiName = "Rando Cardrissian";
|
||||
|
||||
/**
|
||||
* Apart from the one inherited from Cards against Humanity (a reference to
|
||||
* Star Wars), we use some references to famous AIs and computers from films
|
||||
* and games.
|
||||
*/
|
||||
export const aiNames = new Set([
|
||||
"HAL 9000", // 2001: A Space Odyssey
|
||||
"GLaDOS", // Portal
|
||||
"Wheatley", // Portal
|
||||
"TEC-XX", // Paper Mario
|
||||
"EDI", // Mass Effect
|
||||
"343 Guilty Spark", // Halo
|
||||
"Cortana", // Halo
|
||||
"J.A.R.V.I.S.", // MCU
|
||||
"Deep Thought", // HHGTTG
|
||||
"Gibson", // Hackers
|
||||
"Skynet", // Terminator
|
||||
"Project 2501", // GITS
|
||||
"SHODAN", // System Shock
|
||||
"Mr. House" // Fallout: New Vegas
|
||||
]);
|
||||
|
||||
/**
|
||||
* The internal model of the Rando house rule.
|
||||
*/
|
||||
export interface Rando {
|
||||
/**
|
||||
* The ids of active AI players in the game.
|
||||
*/
|
||||
current: user.Id[];
|
||||
/**
|
||||
* The names or ids of potential AI players that are not currently active in
|
||||
* the game.
|
||||
*/
|
||||
unused: (user.Id | RegisterUser)[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the initial model.
|
||||
*/
|
||||
export const create = (): Rando => ({
|
||||
current: [],
|
||||
unused: [aiName]
|
||||
.concat(util.shuffled(aiNames).slice(0, max - 1))
|
||||
.map(name => ({ name }))
|
||||
});
|
||||
|
||||
/**
|
||||
* The public view of the Rando house rule.
|
||||
*/
|
||||
export interface Public {
|
||||
/**
|
||||
* The number of AI players to add to the game.
|
||||
* @TJS-type integer
|
||||
* @minimum 1
|
||||
* @maximum 10
|
||||
*/
|
||||
number: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the public view of the given internal model.
|
||||
*/
|
||||
export const censor = (rando: Rando): Public | undefined =>
|
||||
rando.current.length > 0 ? { number: rando.current.length } : undefined;
|
||||
|
||||
const isId = (ai: user.Id | RegisterUser): ai is user.Id =>
|
||||
typeof ai === "string";
|
||||
|
||||
export const createIfNeeded = (
|
||||
inLobby: Lobby,
|
||||
ai: user.Id | RegisterUser
|
||||
): { user: user.Id; events: Iterable<event.Distributor> } => {
|
||||
if (isId(ai)) {
|
||||
return {
|
||||
user: ai,
|
||||
events: [
|
||||
event.targetAll(
|
||||
presenceChanged.joined(ai, inLobby.users.get(ai) as User)
|
||||
)
|
||||
]
|
||||
};
|
||||
} else {
|
||||
return lobby.addUser(inLobby, ai, user => ({
|
||||
...user,
|
||||
control: "Computer"
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the internal model to match the given public representation.
|
||||
*/
|
||||
export function* change(
|
||||
inLobby: Lobby,
|
||||
config: Rando,
|
||||
changeTo?: Public
|
||||
): Iterable<event.Distributor> | null {
|
||||
const want = changeTo !== undefined ? changeTo.number : 0;
|
||||
const have = config.current.length;
|
||||
const eventsCollection = [];
|
||||
if (want === have) {
|
||||
return null;
|
||||
}
|
||||
if (want > have) {
|
||||
const toAdd = want - have;
|
||||
const added = config.unused
|
||||
.splice(0, toAdd)
|
||||
.map(ai => createIfNeeded(inLobby, ai));
|
||||
for (const { user, events } of added) {
|
||||
const userData = inLobby.users.get(user) as User;
|
||||
userData.presence = "Joined";
|
||||
config.current.push(user);
|
||||
eventsCollection.push(...events);
|
||||
}
|
||||
} else if (have > want) {
|
||||
const toRemove = have - want;
|
||||
const removed = config.current.splice(
|
||||
config.current.length - toRemove,
|
||||
toRemove
|
||||
);
|
||||
for (const ai of removed) {
|
||||
const user = inLobby.users.get(ai) as User;
|
||||
user.presence = "Left";
|
||||
eventsCollection.push(event.targetAll(presenceChanged.left(ai)));
|
||||
}
|
||||
config.unused.splice(0, 0, ...removed);
|
||||
}
|
||||
yield* eventsCollection;
|
||||
}
|
||||
@@ -126,7 +126,7 @@ async function main(): Promise<void> {
|
||||
return {
|
||||
change: {
|
||||
lobby,
|
||||
events: [event.targetAll(presenceChanged.joined(id, newUser.name))],
|
||||
events: [event.targetAll(presenceChanged.joined(id, newUser))],
|
||||
timeouts: [
|
||||
{
|
||||
timeout: userDisconnect.of(id),
|
||||
|
||||
+22
-1
@@ -1,4 +1,7 @@
|
||||
import { CreateLobby } from "./action/initial/create-lobby";
|
||||
import { RegisterUser } from "./action/initial/register-user";
|
||||
import * as event from "./event";
|
||||
import * as presenceChanged from "./events/lobby-event/presence-changed";
|
||||
import * as game from "./games/game";
|
||||
import { Game } from "./games/game";
|
||||
import * as rules from "./games/rules";
|
||||
@@ -8,7 +11,6 @@ import { GameCode } from "./lobby/game-code";
|
||||
import * as user from "./user";
|
||||
import { User } from "./user";
|
||||
import * as util from "./util";
|
||||
import * as token from "./user/token";
|
||||
|
||||
/**
|
||||
* A game lobby.
|
||||
@@ -132,3 +134,22 @@ export const censor = (lobby: Lobby): Public => ({
|
||||
config: config.censor(lobby.config),
|
||||
...(lobby.game === undefined ? {} : { game: game.censor(lobby.game) })
|
||||
});
|
||||
|
||||
export const addUser = (
|
||||
lobby: Lobby,
|
||||
registration: RegisterUser,
|
||||
change?: (user: User) => User
|
||||
): {
|
||||
user: user.Id;
|
||||
events: Iterable<event.Distributor>;
|
||||
} => {
|
||||
const newUser = user.create(registration);
|
||||
const changedUser = change === undefined ? newUser : change(newUser);
|
||||
const id = lobby.nextUserId.toString();
|
||||
lobby.nextUserId += 1;
|
||||
lobby.users.set(id, changedUser);
|
||||
return {
|
||||
user: id,
|
||||
events: [event.targetAll(presenceChanged.joined(id, changedUser))]
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,12 +15,16 @@ export abstract class TaskBase<T> implements Task {
|
||||
}
|
||||
|
||||
protected abstract async begin(server: ServerState): Promise<T>;
|
||||
protected abstract resolve(lobby: Lobby, work: T): Change;
|
||||
protected abstract resolve(
|
||||
lobby: Lobby,
|
||||
work: T,
|
||||
server: ServerState
|
||||
): Change;
|
||||
|
||||
public async handle(server: ServerState): Promise<void> {
|
||||
const work = await this.begin(server);
|
||||
await change.apply(server, this.gameCode, lobby =>
|
||||
this.resolve(lobby, work)
|
||||
this.resolve(lobby, work, server)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import wu from "wu";
|
||||
import * as event from "../event";
|
||||
import * as gameStarted from "../events/game-event/game-started";
|
||||
import * as decks from "../games/cards/decks";
|
||||
import * as source from "../games/cards/source";
|
||||
import * as sources from "../games/cards/sources";
|
||||
import * as game from "../games/game";
|
||||
import * as round from "../games/game/round";
|
||||
import { Lobby } from "../lobby";
|
||||
import { Change } from "../lobby/change";
|
||||
import { GameCode } from "../lobby/game-code";
|
||||
@@ -28,20 +25,23 @@ export class StartGame extends task.TaskBase<decks.Templates[]> {
|
||||
);
|
||||
}
|
||||
|
||||
protected resolve(lobby: Lobby, work: decks.Templates[]): Change {
|
||||
protected resolve(
|
||||
lobby: Lobby,
|
||||
work: decks.Templates[],
|
||||
server: ServerState
|
||||
): Change {
|
||||
if (lobby.game !== undefined) {
|
||||
return {};
|
||||
}
|
||||
const lobbyGame = game.start(work, lobby.users.keys(), lobby.config.rules);
|
||||
const gameRound = round.censor(lobbyGame.round);
|
||||
const baseEvent = gameStarted.of(gameRound);
|
||||
const events = [
|
||||
event.playerSpecificAddition(baseEvent, (id, user, player) => ({
|
||||
hand: player.hand
|
||||
}))
|
||||
];
|
||||
lobby.game = lobbyGame;
|
||||
return { lobby, events };
|
||||
|
||||
const atStartOfRound = game.atStartOfRound(server, true, lobbyGame);
|
||||
lobby.game = atStartOfRound.game;
|
||||
return {
|
||||
lobby,
|
||||
events: atStartOfRound.events,
|
||||
timeouts: atStartOfRound.timeouts
|
||||
};
|
||||
}
|
||||
|
||||
// This is super unlikely timing-wise, and if it happens, the user just has
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import wu from "wu";
|
||||
import * as event from "../event";
|
||||
import * as roundStarted from "../events/game-event/round-started";
|
||||
import { Game } from "../games/game";
|
||||
import * as game from "../games/game";
|
||||
import * as lobby from "../lobby";
|
||||
import { Playing } from "../games/game/round";
|
||||
import * as timeout from "../timeout";
|
||||
import * as card from "../games/cards/card";
|
||||
import * as player from "../games/player";
|
||||
|
||||
/**
|
||||
* Indicates that the round should start if it is still appropriate to do so.
|
||||
@@ -21,15 +20,14 @@ export const handle: timeout.Handler<RoundStart> = (
|
||||
server,
|
||||
timeout,
|
||||
gameCode,
|
||||
lobby
|
||||
inLobby
|
||||
) => {
|
||||
const lobbyGame = lobby.game;
|
||||
if (lobbyGame !== undefined) {
|
||||
if (lobby.hasActiveGame(inLobby)) {
|
||||
const lobbyGame = inLobby.game;
|
||||
const gameRound = lobbyGame.round;
|
||||
if (gameRound.stage === "Complete") {
|
||||
const czar = game.nextCzar(lobbyGame);
|
||||
const czar = game.nextCzar(inLobby);
|
||||
const [call] = lobbyGame.decks.calls.replace(gameRound.call);
|
||||
const slotCount = card.slotCount(call);
|
||||
const roundId = gameRound.id + 1;
|
||||
const playersInRound = new Set(
|
||||
wu(lobbyGame.playerOrder).filter(id => id !== czar)
|
||||
@@ -37,37 +35,24 @@ export const handle: timeout.Handler<RoundStart> = (
|
||||
lobbyGame.decks.responses.discard(
|
||||
gameRound.plays.flatMap(play => play.play)
|
||||
);
|
||||
lobbyGame.round = {
|
||||
stage: "Playing",
|
||||
id: roundId,
|
||||
czar: czar,
|
||||
players: playersInRound,
|
||||
call: call,
|
||||
plays: []
|
||||
};
|
||||
const playersArray = Array.from(playersInRound);
|
||||
const baseEvent = roundStarted.of(roundId, czar, playersArray, call);
|
||||
|
||||
let events;
|
||||
if (
|
||||
slotCount > 2 ||
|
||||
(slotCount === 2 &&
|
||||
lobbyGame.rules.houseRules.packingHeat !== undefined)
|
||||
) {
|
||||
const responseDeck = lobbyGame.decks.responses;
|
||||
const drawnByPlayer = new Map();
|
||||
for (const [id, playerState] of lobbyGame.players) {
|
||||
if (player.role(lobbyGame, id) === "Player") {
|
||||
const drawn = responseDeck.draw(slotCount - 1);
|
||||
drawnByPlayer.set(id, { drawn });
|
||||
playerState.hand.push(...drawn);
|
||||
}
|
||||
const updatedGame: Game & { round: Playing } = {
|
||||
...lobbyGame,
|
||||
round: {
|
||||
stage: "Playing",
|
||||
id: roundId,
|
||||
czar: czar,
|
||||
players: playersInRound,
|
||||
call: call,
|
||||
plays: []
|
||||
}
|
||||
events = [event.additionally(baseEvent, drawnByPlayer)];
|
||||
} else {
|
||||
events = [event.targetAll(baseEvent)];
|
||||
}
|
||||
return { lobby, events };
|
||||
};
|
||||
const atStartOfRound = game.atStartOfRound(server, false, updatedGame);
|
||||
inLobby.game = atStartOfRound.game;
|
||||
return {
|
||||
inLobby,
|
||||
events: atStartOfRound.events,
|
||||
timeouts: atStartOfRound.timeouts
|
||||
};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
|
||||
+17
-15
@@ -6,6 +6,7 @@ export interface User {
|
||||
presence: Presence;
|
||||
connection: Connection;
|
||||
privilege: Privilege;
|
||||
control: Control;
|
||||
role: Role;
|
||||
}
|
||||
|
||||
@@ -17,6 +18,7 @@ export interface Public {
|
||||
presence: Presence;
|
||||
connection: Connection;
|
||||
privilege: Privilege;
|
||||
control: Control;
|
||||
role: Role;
|
||||
}
|
||||
|
||||
@@ -52,6 +54,11 @@ export type Connection = "Connected" | "Disconnected";
|
||||
*/
|
||||
export type Role = "Spectator" | "Player";
|
||||
|
||||
/**
|
||||
* Who/what is controlling the player—a human or the computer?
|
||||
*/
|
||||
export type Control = "Human" | "Computer";
|
||||
|
||||
/**
|
||||
* If the user is playing.
|
||||
*/
|
||||
@@ -69,26 +76,21 @@ export const isSpectating: (user: User) => boolean = user =>
|
||||
* @param registration The details of the user to create.
|
||||
* @param privilege The level of privilege the user has.
|
||||
*/
|
||||
export function create(
|
||||
export const create = (
|
||||
registration: RegisterUser,
|
||||
privilege: Privilege = "Unprivileged"
|
||||
): User {
|
||||
return {
|
||||
name: registration.name,
|
||||
presence: "Joined",
|
||||
connection: "Connected",
|
||||
privilege: privilege,
|
||||
role: "Player"
|
||||
};
|
||||
}
|
||||
): User => ({
|
||||
name: registration.name,
|
||||
presence: "Joined",
|
||||
connection: "Connected",
|
||||
privilege: privilege,
|
||||
control: "Human",
|
||||
role: "Player"
|
||||
});
|
||||
|
||||
/**
|
||||
* Gives a version of the user with only publicly visible properties.
|
||||
*/
|
||||
export const censor: (user: User) => Public = user => ({
|
||||
name: user.name,
|
||||
presence: user.presence,
|
||||
connection: user.connection,
|
||||
privilege: user.privilege,
|
||||
role: user.role
|
||||
...user
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user