YEAH!
This commit is contained in:
parent
68b738056b
commit
393538951a
|
@ -14,13 +14,17 @@
|
|||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/color": "^3.0.6",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^20.14.2",
|
||||
"@types/seedrandom": "^3.0.8",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.2",
|
||||
"canvas": "^2.11.2",
|
||||
"color": "^4.2.3",
|
||||
"isolated-vm": "^5.0.0"
|
||||
"express": "^4.19.2",
|
||||
"isolated-vm": "^5.0.0",
|
||||
"seedrandom": "^3.0.5"
|
||||
}
|
||||
}
|
||||
|
|
521
pnpm-lock.yaml
521
pnpm-lock.yaml
|
@ -14,17 +14,29 @@ dependencies:
|
|||
color:
|
||||
specifier: ^4.2.3
|
||||
version: 4.2.3
|
||||
express:
|
||||
specifier: ^4.19.2
|
||||
version: 4.19.2
|
||||
isolated-vm:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
seedrandom:
|
||||
specifier: ^3.0.5
|
||||
version: 3.0.5
|
||||
|
||||
devDependencies:
|
||||
'@types/color':
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6
|
||||
'@types/express':
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
'@types/node':
|
||||
specifier: ^20.14.2
|
||||
version: 20.14.2
|
||||
'@types/seedrandom':
|
||||
specifier: ^3.0.8
|
||||
version: 3.0.8
|
||||
typescript:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
|
@ -49,6 +61,13 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@types/body-parser@1.19.5:
|
||||
resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
|
||||
dependencies:
|
||||
'@types/connect': 3.4.38
|
||||
'@types/node': 20.14.2
|
||||
dev: true
|
||||
|
||||
/@types/color-convert@2.0.3:
|
||||
resolution: {integrity: sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==}
|
||||
dependencies:
|
||||
|
@ -65,16 +84,83 @@ packages:
|
|||
'@types/color-convert': 2.0.3
|
||||
dev: true
|
||||
|
||||
/@types/connect@3.4.38:
|
||||
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
||||
dependencies:
|
||||
'@types/node': 20.14.2
|
||||
dev: true
|
||||
|
||||
/@types/express-serve-static-core@4.19.3:
|
||||
resolution: {integrity: sha512-KOzM7MhcBFlmnlr/fzISFF5vGWVSvN6fTd4T+ExOt08bA/dA5kpSzY52nMsI1KDFmUREpJelPYyuslLRSjjgCg==}
|
||||
dependencies:
|
||||
'@types/node': 20.14.2
|
||||
'@types/qs': 6.9.15
|
||||
'@types/range-parser': 1.2.7
|
||||
'@types/send': 0.17.4
|
||||
dev: true
|
||||
|
||||
/@types/express@4.17.21:
|
||||
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
|
||||
dependencies:
|
||||
'@types/body-parser': 1.19.5
|
||||
'@types/express-serve-static-core': 4.19.3
|
||||
'@types/qs': 6.9.15
|
||||
'@types/serve-static': 1.15.7
|
||||
dev: true
|
||||
|
||||
/@types/http-errors@2.0.4:
|
||||
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
|
||||
dev: true
|
||||
|
||||
/@types/mime@1.3.5:
|
||||
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
|
||||
dev: true
|
||||
|
||||
/@types/node@20.14.2:
|
||||
resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==}
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
dev: true
|
||||
|
||||
/@types/qs@6.9.15:
|
||||
resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==}
|
||||
dev: true
|
||||
|
||||
/@types/range-parser@1.2.7:
|
||||
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
||||
dev: true
|
||||
|
||||
/@types/seedrandom@3.0.8:
|
||||
resolution: {integrity: sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ==}
|
||||
dev: true
|
||||
|
||||
/@types/send@0.17.4:
|
||||
resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
|
||||
dependencies:
|
||||
'@types/mime': 1.3.5
|
||||
'@types/node': 20.14.2
|
||||
dev: true
|
||||
|
||||
/@types/serve-static@1.15.7:
|
||||
resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
|
||||
dependencies:
|
||||
'@types/http-errors': 2.0.4
|
||||
'@types/node': 20.14.2
|
||||
'@types/send': 0.17.4
|
||||
dev: true
|
||||
|
||||
/abbrev@1.1.1:
|
||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
||||
dev: false
|
||||
|
||||
/accepts@1.3.8:
|
||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dependencies:
|
||||
mime-types: 2.1.35
|
||||
negotiator: 0.6.3
|
||||
dev: false
|
||||
|
||||
/agent-base@6.0.2:
|
||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||
engines: {node: '>= 6.0.0'}
|
||||
|
@ -102,6 +188,10 @@ packages:
|
|||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
|
||||
/array-flatten@1.1.1:
|
||||
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
|
||||
dev: false
|
||||
|
||||
/asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
dev: false
|
||||
|
@ -132,6 +222,26 @@ packages:
|
|||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
|
||||
/body-parser@1.20.2:
|
||||
resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
|
||||
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
||||
dependencies:
|
||||
bytes: 3.1.2
|
||||
content-type: 1.0.5
|
||||
debug: 2.6.9
|
||||
depd: 2.0.0
|
||||
destroy: 1.2.0
|
||||
http-errors: 2.0.0
|
||||
iconv-lite: 0.4.24
|
||||
on-finished: 2.4.1
|
||||
qs: 6.11.0
|
||||
raw-body: 2.5.2
|
||||
type-is: 1.6.18
|
||||
unpipe: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/brace-expansion@1.1.11:
|
||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||
dependencies:
|
||||
|
@ -146,6 +256,22 @@ packages:
|
|||
ieee754: 1.2.1
|
||||
dev: false
|
||||
|
||||
/bytes@3.1.2:
|
||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/call-bind@1.0.7:
|
||||
resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
es-define-property: 1.0.0
|
||||
es-errors: 1.3.0
|
||||
function-bind: 1.1.2
|
||||
get-intrinsic: 1.2.4
|
||||
set-function-length: 1.2.2
|
||||
dev: false
|
||||
|
||||
/canvas@2.11.2:
|
||||
resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -214,6 +340,38 @@ packages:
|
|||
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
|
||||
dev: false
|
||||
|
||||
/content-disposition@0.5.4:
|
||||
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/content-type@1.0.5:
|
||||
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/cookie-signature@1.0.6:
|
||||
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
|
||||
dev: false
|
||||
|
||||
/cookie@0.6.0:
|
||||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/debug@2.6.9:
|
||||
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
dev: false
|
||||
|
||||
/debug@4.3.5:
|
||||
resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
|
||||
engines: {node: '>=6.0'}
|
||||
|
@ -245,6 +403,15 @@ packages:
|
|||
engines: {node: '>=4.0.0'}
|
||||
dev: false
|
||||
|
||||
/define-data-property@1.1.4:
|
||||
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
es-define-property: 1.0.0
|
||||
es-errors: 1.3.0
|
||||
gopd: 1.0.1
|
||||
dev: false
|
||||
|
||||
/delayed-stream@1.0.0:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
@ -254,26 +421,120 @@ packages:
|
|||
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
|
||||
dev: false
|
||||
|
||||
/depd@2.0.0:
|
||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/destroy@1.2.0:
|
||||
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
|
||||
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
||||
dev: false
|
||||
|
||||
/detect-libc@2.0.3:
|
||||
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
dev: false
|
||||
|
||||
/emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
dev: false
|
||||
|
||||
/encodeurl@1.0.2:
|
||||
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/end-of-stream@1.4.4:
|
||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
dev: false
|
||||
|
||||
/es-define-property@1.0.0:
|
||||
resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.4
|
||||
dev: false
|
||||
|
||||
/es-errors@1.3.0:
|
||||
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: false
|
||||
|
||||
/escape-html@1.0.3:
|
||||
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||
dev: false
|
||||
|
||||
/etag@1.8.1:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/expand-template@2.0.3:
|
||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/express@4.19.2:
|
||||
resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==}
|
||||
engines: {node: '>= 0.10.0'}
|
||||
dependencies:
|
||||
accepts: 1.3.8
|
||||
array-flatten: 1.1.1
|
||||
body-parser: 1.20.2
|
||||
content-disposition: 0.5.4
|
||||
content-type: 1.0.5
|
||||
cookie: 0.6.0
|
||||
cookie-signature: 1.0.6
|
||||
debug: 2.6.9
|
||||
depd: 2.0.0
|
||||
encodeurl: 1.0.2
|
||||
escape-html: 1.0.3
|
||||
etag: 1.8.1
|
||||
finalhandler: 1.2.0
|
||||
fresh: 0.5.2
|
||||
http-errors: 2.0.0
|
||||
merge-descriptors: 1.0.1
|
||||
methods: 1.1.2
|
||||
on-finished: 2.4.1
|
||||
parseurl: 1.3.3
|
||||
path-to-regexp: 0.1.7
|
||||
proxy-addr: 2.0.7
|
||||
qs: 6.11.0
|
||||
range-parser: 1.2.1
|
||||
safe-buffer: 5.2.1
|
||||
send: 0.18.0
|
||||
serve-static: 1.15.0
|
||||
setprototypeof: 1.2.0
|
||||
statuses: 2.0.1
|
||||
type-is: 1.6.18
|
||||
utils-merge: 1.0.1
|
||||
vary: 1.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/finalhandler@1.2.0:
|
||||
resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
debug: 2.6.9
|
||||
encodeurl: 1.0.2
|
||||
escape-html: 1.0.3
|
||||
on-finished: 2.4.1
|
||||
parseurl: 1.3.3
|
||||
statuses: 2.0.1
|
||||
unpipe: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/follow-redirects@1.15.6:
|
||||
resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
|
||||
engines: {node: '>=4.0'}
|
||||
|
@ -293,6 +554,16 @@ packages:
|
|||
mime-types: 2.1.35
|
||||
dev: false
|
||||
|
||||
/forwarded@0.2.0:
|
||||
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/fresh@0.5.2:
|
||||
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/fs-constants@1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
dev: false
|
||||
|
@ -308,6 +579,10 @@ packages:
|
|||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
dev: false
|
||||
|
||||
/function-bind@1.1.2:
|
||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||
dev: false
|
||||
|
||||
/gauge@3.0.2:
|
||||
resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -324,6 +599,17 @@ packages:
|
|||
wide-align: 1.1.5
|
||||
dev: false
|
||||
|
||||
/get-intrinsic@1.2.4:
|
||||
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
function-bind: 1.1.2
|
||||
has-proto: 1.0.3
|
||||
has-symbols: 1.0.3
|
||||
hasown: 2.0.2
|
||||
dev: false
|
||||
|
||||
/github-from-package@0.0.0:
|
||||
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
|
||||
dev: false
|
||||
|
@ -340,10 +626,50 @@ packages:
|
|||
path-is-absolute: 1.0.1
|
||||
dev: false
|
||||
|
||||
/gopd@1.0.1:
|
||||
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.4
|
||||
dev: false
|
||||
|
||||
/has-property-descriptors@1.0.2:
|
||||
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
|
||||
dependencies:
|
||||
es-define-property: 1.0.0
|
||||
dev: false
|
||||
|
||||
/has-proto@1.0.3:
|
||||
resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: false
|
||||
|
||||
/has-symbols@1.0.3:
|
||||
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: false
|
||||
|
||||
/has-unicode@2.0.1:
|
||||
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
|
||||
dev: false
|
||||
|
||||
/hasown@2.0.2:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
dev: false
|
||||
|
||||
/http-errors@2.0.0:
|
||||
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
depd: 2.0.0
|
||||
inherits: 2.0.4
|
||||
setprototypeof: 1.2.0
|
||||
statuses: 2.0.1
|
||||
toidentifier: 1.0.1
|
||||
dev: false
|
||||
|
||||
/https-proxy-agent@5.0.1:
|
||||
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -354,6 +680,13 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/iconv-lite@0.4.24:
|
||||
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
dev: false
|
||||
|
||||
/ieee754@1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
dev: false
|
||||
|
@ -374,6 +707,11 @@ packages:
|
|||
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
|
||||
dev: false
|
||||
|
||||
/ipaddr.js@1.9.1:
|
||||
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
dev: false
|
||||
|
||||
/is-arrayish@0.3.2:
|
||||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||
dev: false
|
||||
|
@ -398,6 +736,20 @@ packages:
|
|||
semver: 6.3.1
|
||||
dev: false
|
||||
|
||||
/media-typer@0.3.0:
|
||||
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/merge-descriptors@1.0.1:
|
||||
resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
|
||||
dev: false
|
||||
|
||||
/methods@1.1.2:
|
||||
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/mime-db@1.52.0:
|
||||
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
@ -410,6 +762,12 @@ packages:
|
|||
mime-db: 1.52.0
|
||||
dev: false
|
||||
|
||||
/mime@1.6.0:
|
||||
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/mimic-response@2.1.0:
|
||||
resolution: {integrity: sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -460,10 +818,18 @@ packages:
|
|||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/ms@2.0.0:
|
||||
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||
dev: false
|
||||
|
||||
/ms@2.1.2:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
dev: false
|
||||
|
||||
/ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
dev: false
|
||||
|
||||
/nan@2.20.0:
|
||||
resolution: {integrity: sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==}
|
||||
dev: false
|
||||
|
@ -472,6 +838,11 @@ packages:
|
|||
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
||||
dev: false
|
||||
|
||||
/negotiator@0.6.3:
|
||||
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/node-abi@3.65.0:
|
||||
resolution: {integrity: sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -514,17 +885,37 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/object-inspect@1.13.1:
|
||||
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
|
||||
dev: false
|
||||
|
||||
/on-finished@2.4.1:
|
||||
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
ee-first: 1.1.1
|
||||
dev: false
|
||||
|
||||
/once@1.4.0:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
dev: false
|
||||
|
||||
/parseurl@1.3.3:
|
||||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/path-is-absolute@1.0.1:
|
||||
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/path-to-regexp@0.1.7:
|
||||
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
|
||||
dev: false
|
||||
|
||||
/prebuild-install@7.1.2:
|
||||
resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -544,6 +935,14 @@ packages:
|
|||
tunnel-agent: 0.6.0
|
||||
dev: false
|
||||
|
||||
/proxy-addr@2.0.7:
|
||||
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
||||
engines: {node: '>= 0.10'}
|
||||
dependencies:
|
||||
forwarded: 0.2.0
|
||||
ipaddr.js: 1.9.1
|
||||
dev: false
|
||||
|
||||
/proxy-from-env@1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
dev: false
|
||||
|
@ -555,6 +954,28 @@ packages:
|
|||
once: 1.4.0
|
||||
dev: false
|
||||
|
||||
/qs@6.11.0:
|
||||
resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
|
||||
engines: {node: '>=0.6'}
|
||||
dependencies:
|
||||
side-channel: 1.0.6
|
||||
dev: false
|
||||
|
||||
/range-parser@1.2.1:
|
||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/raw-body@2.5.2:
|
||||
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
bytes: 3.1.2
|
||||
http-errors: 2.0.0
|
||||
iconv-lite: 0.4.24
|
||||
unpipe: 1.0.0
|
||||
dev: false
|
||||
|
||||
/rc@1.2.8:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
|
@ -586,6 +1007,14 @@ packages:
|
|||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
dev: false
|
||||
|
||||
/safer-buffer@2.1.2:
|
||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||
dev: false
|
||||
|
||||
/seedrandom@3.0.5:
|
||||
resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
|
||||
dev: false
|
||||
|
||||
/semver@6.3.1:
|
||||
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
||||
hasBin: true
|
||||
|
@ -597,10 +1026,69 @@ packages:
|
|||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/send@0.18.0:
|
||||
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
dependencies:
|
||||
debug: 2.6.9
|
||||
depd: 2.0.0
|
||||
destroy: 1.2.0
|
||||
encodeurl: 1.0.2
|
||||
escape-html: 1.0.3
|
||||
etag: 1.8.1
|
||||
fresh: 0.5.2
|
||||
http-errors: 2.0.0
|
||||
mime: 1.6.0
|
||||
ms: 2.1.3
|
||||
on-finished: 2.4.1
|
||||
range-parser: 1.2.1
|
||||
statuses: 2.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/serve-static@1.15.0:
|
||||
resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
dependencies:
|
||||
encodeurl: 1.0.2
|
||||
escape-html: 1.0.3
|
||||
parseurl: 1.3.3
|
||||
send: 0.18.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/set-blocking@2.0.0:
|
||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||
dev: false
|
||||
|
||||
/set-function-length@1.2.2:
|
||||
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
define-data-property: 1.1.4
|
||||
es-errors: 1.3.0
|
||||
function-bind: 1.1.2
|
||||
get-intrinsic: 1.2.4
|
||||
gopd: 1.0.1
|
||||
has-property-descriptors: 1.0.2
|
||||
dev: false
|
||||
|
||||
/setprototypeof@1.2.0:
|
||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||
dev: false
|
||||
|
||||
/side-channel@1.0.6:
|
||||
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.2.4
|
||||
object-inspect: 1.13.1
|
||||
dev: false
|
||||
|
||||
/signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
dev: false
|
||||
|
@ -631,6 +1119,11 @@ packages:
|
|||
is-arrayish: 0.3.2
|
||||
dev: false
|
||||
|
||||
/statuses@2.0.1:
|
||||
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -690,6 +1183,11 @@ packages:
|
|||
yallist: 4.0.0
|
||||
dev: false
|
||||
|
||||
/toidentifier@1.0.1:
|
||||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||
engines: {node: '>=0.6'}
|
||||
dev: false
|
||||
|
||||
/tr46@0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
dev: false
|
||||
|
@ -700,6 +1198,14 @@ packages:
|
|||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/type-is@1.6.18:
|
||||
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dependencies:
|
||||
media-typer: 0.3.0
|
||||
mime-types: 2.1.35
|
||||
dev: false
|
||||
|
||||
/typescript@5.4.5:
|
||||
resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
|
||||
engines: {node: '>=14.17'}
|
||||
|
@ -710,10 +1216,25 @@ packages:
|
|||
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
||||
dev: true
|
||||
|
||||
/unpipe@1.0.0:
|
||||
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
dev: false
|
||||
|
||||
/utils-merge@1.0.1:
|
||||
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dev: false
|
||||
|
||||
/vary@1.1.2:
|
||||
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/webidl-conversions@3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
dev: false
|
||||
|
|
138
src/index.ts
138
src/index.ts
|
@ -1,120 +1,52 @@
|
|||
import { createCanvas, loadImage } from "canvas";
|
||||
import { fetchScript, extractDataFromScript, getAsset, dirname } from "./util.js";
|
||||
import { writeFile } from "fs/promises";
|
||||
import axios from "axios";
|
||||
import express from "express";
|
||||
import crypto from "crypto";
|
||||
import { generatePicrew } from "./picrew.js";
|
||||
import { dirname, isValidSha256 } from "./util.js";
|
||||
import { HttpRespondError } from "./types.js";
|
||||
import path from "path";
|
||||
import Color from "color";
|
||||
|
||||
const MAKER_ID = "1904634";
|
||||
const app = express();
|
||||
|
||||
await fetchScript(MAKER_ID);
|
||||
const { config, commonImages, cdnRoot, partsId2Index } = await extractDataFromScript(MAKER_ID);
|
||||
app.get("/generate/:makerid/:hash", async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const makerid = req.params.makerid as string;
|
||||
const hash = req.params.hash as string;
|
||||
|
||||
type UrlsList = { colorId: string, url: string };
|
||||
type LayerList = { layerId: string, urls: UrlsList[] };
|
||||
type ItemList = { itemId: string, layers: LayerList[] };
|
||||
type LayerColorList = { layerIndex: number, cpId: string, colors: string[] };
|
||||
type CategoryList = { cpId: string, pId: string, items: ItemList[], index: number, isRmv: boolean };
|
||||
if (!isValidSha256(hash)) return res.status(400).send("The hash you provided is not a valid hex-encoded sha256 hash.");
|
||||
if (isNaN(Number(makerid))) return res.status(400).send("You did not provide a valid Picrew maker ID.");
|
||||
|
||||
const exclusions: number[][] = Object.values(config.ruleList)
|
||||
.filter((rule) => rule.pId == 0) // Not sure what pId is but just to be sure that this won't break something else
|
||||
.map((rule) => rule.list);
|
||||
if (["true", "1"].includes(`${req.query.gravatar || ""}`.toLowerCase())) {
|
||||
const gravatarExists = !!(await axios.head(`https://gravatar.com/avatar/${hash}?d=404`).catch(() => false));
|
||||
|
||||
const items: ItemList[] = [];
|
||||
const categories: CategoryList[] = [];
|
||||
const layerColors: LayerColorList[] = [];
|
||||
|
||||
for (const c in config.pList) {
|
||||
const category = config.pList[c];
|
||||
|
||||
layerColors.push({
|
||||
layerIndex: Number(c),
|
||||
cpId: category.cpId,
|
||||
colors: config.cpList[category.cpId].map((c) => c.cId.toString()),
|
||||
});
|
||||
|
||||
const localItems: ItemList[] = [];
|
||||
for (const item of category.items) {
|
||||
const id = item.itmId;
|
||||
|
||||
const obj = commonImages[id];
|
||||
const layers: LayerList[] = [];
|
||||
|
||||
for (const layer of category.lyrs) {
|
||||
if (!obj[layer]) continue; // Not every entry uses all layers
|
||||
const variants = Object.keys(obj[layer]);
|
||||
|
||||
const urls: UrlsList[] = variants.map((v) => ({
|
||||
colorId: v,
|
||||
url: cdnRoot + obj[layer][v].url,
|
||||
}));
|
||||
|
||||
layers.push({ layerId: layer.toString(), urls });
|
||||
if (gravatarExists) return res.redirect(`https://gravatar.com/avatar/${hash}?s=256`);
|
||||
}
|
||||
|
||||
localItems.push({ itemId: id.toString(), layers: layers });
|
||||
}
|
||||
|
||||
items.push(...localItems);
|
||||
categories.push({
|
||||
cpId: category.cpId,
|
||||
pId: category.pId.toString(),
|
||||
items: localItems,
|
||||
index: partsId2Index[category.pId.toString()],
|
||||
isRmv: !!category.isRmv,
|
||||
});
|
||||
}
|
||||
|
||||
const images: { layer: number, url: string, categoryId: number }[] = [];
|
||||
|
||||
categoryLoop: for (const category of categories.sort((a, b) => b.index - a.index)) {
|
||||
const canHide = category.isRmv;
|
||||
const inRuleset = exclusions.find((arr) => arr.includes(Number(category.pId)));
|
||||
|
||||
if (canHide) {
|
||||
// If there's other things that would be blocked by this,
|
||||
// it should be more likely for this one to be hidden so
|
||||
// the other item appears more frequently.
|
||||
if (Math.random() < (inRuleset ? 0.5 : 0.2)) continue;
|
||||
}
|
||||
|
||||
// Check if a conflicting object already exists, and if so, skip this one
|
||||
for (const rule of exclusions) {
|
||||
if (rule.includes(Number(category.pId))) {
|
||||
if (images.find((i) => rule.includes(i.categoryId))) continue categoryLoop;
|
||||
const path = await generatePicrew(hash, makerid);
|
||||
res.sendFile(path);
|
||||
} catch(e) {
|
||||
if (e instanceof HttpRespondError) {
|
||||
res.status(e.statusCode).send(e.message);
|
||||
} else {
|
||||
res.status(500).send(`${e}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const colors = layerColors.find((c) => c.cpId == category.cpId)!.colors;
|
||||
const colorId = colors[Math.floor(Math.random() * colors.length)];
|
||||
const item = category.items[Math.floor(Math.random() * category.items.length)];
|
||||
app.get("/generate-by-email/:makerid/:email", async (req: express.Request, res: express.Response) => {
|
||||
const hash = crypto.createHash("sha256").update(req.params.email).digest("hex");
|
||||
const url = path.join("/", "generate", req.params.makerid, hash);
|
||||
|
||||
for (const layer of item.layers) {
|
||||
const url = (layer.urls.find((i) => i.colorId == colorId) ?? layer.urls?.[0])?.url;
|
||||
|
||||
if (url) {
|
||||
images.push({ layer: Number(layer.layerId), url, categoryId: Number(category.pId) });
|
||||
}
|
||||
const params = new URLSearchParams();
|
||||
for (const [k, v] of Object.entries(req.query)) {
|
||||
if (typeof v == "string") params.append(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
const canvas = createCanvas(config.w, config.h);
|
||||
const ctx = canvas.getContext('2d');
|
||||
res.redirect(url + (params.size ? "?" + params.toString() : ""));
|
||||
});
|
||||
|
||||
// So we don't accidentally end up with a transparent background
|
||||
const bgCol = Color.hsv(Math.floor(Math.random() * 360), 20, 100).hex();
|
||||
ctx.fillStyle = bgCol;
|
||||
ctx.fillRect(0, 0, config.w, config.h);
|
||||
app.use(express.static(path.join(dirname, "..", "web")));
|
||||
|
||||
// Retains the correct order
|
||||
const imgPaths = await Promise.all(
|
||||
images
|
||||
.sort((a, b) => config.lyrList[a.layer] - config.lyrList[b.layer])
|
||||
.map((img) => getAsset(img.url))
|
||||
);
|
||||
// 1904634
|
||||
|
||||
for (const path of imgPaths) {
|
||||
const img = await loadImage(path);
|
||||
ctx.drawImage(img, 0, 0, config.w, config.h);
|
||||
}
|
||||
|
||||
await writeFile(path.join(dirname, "..", "cache", MAKER_ID + ".png"), canvas.toBuffer());
|
||||
app.listen(3000, () => console.log("Listening on http://127.0.0.1:3000"));
|
||||
|
|
138
src/picrew.ts
Normal file
138
src/picrew.ts
Normal file
|
@ -0,0 +1,138 @@
|
|||
import { createCanvas, loadImage } from "canvas";
|
||||
import { fetchScript, extractDataFromScript, getAsset, dirname } from "./util.js";
|
||||
import fs from "fs/promises";
|
||||
import crypto from "crypto";
|
||||
import path from "path";
|
||||
import Color from "color";
|
||||
import seedrandom from "seedrandom";
|
||||
|
||||
// Generates a picrew from a given maker ID using the provided hash.
|
||||
// Returns the output file path.
|
||||
export async function generatePicrew(hash: string, maker: string) {
|
||||
const outDir = path.join(dirname, "..", "cache", "outputs", maker);
|
||||
const filePath = path.join(outDir, hash + ".png");
|
||||
|
||||
// If the file is already cached, just send that again
|
||||
if (!!(await fs.stat(filePath).catch(() => false))) {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
const rng = seedrandom(hash);
|
||||
|
||||
await fetchScript(maker);
|
||||
const { config, commonImages, cdnRoot, partsId2Index } = await extractDataFromScript(maker);
|
||||
|
||||
type UrlsList = { colorId: string, url: string };
|
||||
type LayerList = { layerId: string, urls: UrlsList[] };
|
||||
type ItemList = { itemId: string, layers: LayerList[] };
|
||||
type LayerColorList = { layerIndex: number, cpId: string, colors: string[] };
|
||||
type CategoryList = { cpId: string, pId: string, items: ItemList[], index: number, isRmv: boolean };
|
||||
|
||||
const exclusions: number[][] = Object.values(config.ruleList)
|
||||
.filter((rule) => rule.pId == 0) // Not sure what pId is but just to be sure that this won't break something else
|
||||
.map((rule) => rule.list);
|
||||
|
||||
const items: ItemList[] = [];
|
||||
const categories: CategoryList[] = [];
|
||||
const layerColors: LayerColorList[] = [];
|
||||
|
||||
for (const c in config.pList) {
|
||||
const category = config.pList[c];
|
||||
|
||||
layerColors.push({
|
||||
layerIndex: Number(c),
|
||||
cpId: category.cpId,
|
||||
colors: config.cpList[category.cpId].map((c) => c.cId.toString()),
|
||||
});
|
||||
|
||||
const localItems: ItemList[] = [];
|
||||
for (const item of category.items) {
|
||||
const id = item.itmId;
|
||||
|
||||
const obj = commonImages[id];
|
||||
const layers: LayerList[] = [];
|
||||
|
||||
for (const layer of category.lyrs) {
|
||||
if (!obj[layer]) continue; // Not every entry uses all layers
|
||||
const variants = Object.keys(obj[layer]);
|
||||
|
||||
const urls: UrlsList[] = variants.map((v) => ({
|
||||
colorId: v,
|
||||
url: cdnRoot + obj[layer][v].url,
|
||||
}));
|
||||
|
||||
layers.push({ layerId: layer.toString(), urls });
|
||||
}
|
||||
|
||||
localItems.push({ itemId: id.toString(), layers: layers });
|
||||
}
|
||||
|
||||
items.push(...localItems);
|
||||
categories.push({
|
||||
cpId: category.cpId,
|
||||
pId: category.pId.toString(),
|
||||
items: localItems,
|
||||
index: partsId2Index[category.pId.toString()],
|
||||
isRmv: !!category.isRmv,
|
||||
});
|
||||
}
|
||||
|
||||
const images: { layer: number, url: string, categoryId: number }[] = [];
|
||||
|
||||
categoryLoop: for (const category of categories.sort((a, b) => b.index - a.index)) {
|
||||
const canHide = category.isRmv;
|
||||
const inRuleset = exclusions.find((arr) => arr.includes(Number(category.pId)));
|
||||
|
||||
if (canHide) {
|
||||
// If there's other things that would be blocked by this,
|
||||
// it should be more likely for this one to be hidden so
|
||||
// the other item appears more frequently.
|
||||
if (rng() < (inRuleset ? 0.5 : 0.2)) continue;
|
||||
}
|
||||
|
||||
// Check if a conflicting object already exists, and if so, skip this one
|
||||
for (const rule of exclusions) {
|
||||
if (rule.includes(Number(category.pId))) {
|
||||
if (images.find((i) => rule.includes(i.categoryId))) continue categoryLoop;
|
||||
}
|
||||
}
|
||||
|
||||
const colors = layerColors.find((c) => c.cpId == category.cpId)!.colors;
|
||||
const colorId = colors[Math.floor(rng() * colors.length)];
|
||||
const item = category.items[Math.floor(rng() * category.items.length)];
|
||||
|
||||
for (const layer of item.layers) {
|
||||
const url = (layer.urls.find((i) => i.colorId == colorId) ?? layer.urls?.[0])?.url;
|
||||
|
||||
if (url) {
|
||||
images.push({ layer: Number(layer.layerId), url, categoryId: Number(category.pId) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const canvas = createCanvas(config.w, config.h);
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// So we don't accidentally end up with a transparent background
|
||||
const bgCol = Color.hsv(Math.floor(rng() * 360), 20, 100).hex();
|
||||
ctx.fillStyle = bgCol;
|
||||
ctx.fillRect(0, 0, config.w, config.h);
|
||||
|
||||
// Retains the correct order
|
||||
const imgPaths = await Promise.all(
|
||||
images
|
||||
.sort((a, b) => config.lyrList[a.layer] - config.lyrList[b.layer])
|
||||
.map((img) => getAsset(img.url))
|
||||
);
|
||||
|
||||
for (const path of imgPaths) {
|
||||
const img = await loadImage(path);
|
||||
ctx.drawImage(img, 0, 0, config.w, config.h);
|
||||
}
|
||||
await fs.mkdir(outDir, { recursive: true })
|
||||
.catch((e) => { if (e?.code != "EEXIST") throw e; }); // Ignore "already exists" error
|
||||
|
||||
await fs.writeFile(filePath, canvas.toBuffer());
|
||||
|
||||
return filePath;
|
||||
}
|
|
@ -54,3 +54,12 @@ export type CommonImages = {
|
|||
export type PartsId2Index = {
|
||||
[key: string]: number;
|
||||
}
|
||||
|
||||
export class HttpRespondError extends Error {
|
||||
statusCode: number;
|
||||
|
||||
constructor(message: string, statusCode: number) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
}
|
||||
|
|
21
src/util.ts
21
src/util.ts
|
@ -1,10 +1,10 @@
|
|||
import path from "path";
|
||||
import { fileURLToPath, URL } from "url";
|
||||
import fs from "fs/promises";
|
||||
import axios from "axios";
|
||||
import axios, { AxiosError } from "axios";
|
||||
import { createWriteStream } from "fs";
|
||||
import ivm from "isolated-vm";
|
||||
import { CommonImages, Config, PartsId2Index } from "./types.js";
|
||||
import { CommonImages, Config, HttpRespondError, PartsId2Index } from "./types.js";
|
||||
|
||||
export const dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
|
@ -33,7 +33,14 @@ export async function fetchScript(makerId: string) {
|
|||
const scriptExists = await fsExists(scriptPath);
|
||||
|
||||
if (!htmlExists) {
|
||||
await downloadToPath(`https://picrew.me/en/image_maker/${encodeURIComponent(makerId)}`, htmlPath);
|
||||
try {
|
||||
await downloadToPath(`https://picrew.me/en/image_maker/${encodeURIComponent(makerId)}`, htmlPath);
|
||||
} catch(e) {
|
||||
if (e instanceof AxiosError && e.status == 404) {
|
||||
throw new HttpRespondError(`There is no Picrew maker with ID ${makerId}.`, 400);
|
||||
}
|
||||
else throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (!scriptExists) {
|
||||
|
@ -76,7 +83,7 @@ export async function getAsset(url: string) {
|
|||
// https://cdn.picrew.me/app/image_maker/{makerId}/{pId}/{random_string}.png
|
||||
const [ makerId, cId, filename ] = new URL(url).pathname.split("/").slice(-3);
|
||||
|
||||
console.log(`Starting download: ${makerId}/${cId}/${filename}`);
|
||||
//console.log(`Starting download: ${makerId}/${cId}/${filename}`);
|
||||
|
||||
const dir = path.join(dirname, "..", "cache", "assets", makerId, cId);
|
||||
const filePath = path.join(dir, filename);
|
||||
|
@ -88,6 +95,10 @@ export async function getAsset(url: string) {
|
|||
await downloadToPath(url, filePath);
|
||||
}
|
||||
|
||||
console.log(`Finished download: ${makerId}/${cId}/${filename}`);
|
||||
//console.log(`Finished download: ${makerId}/${cId}/${filename}`);
|
||||
return filePath;
|
||||
}
|
||||
|
||||
export async function isValidSha256(hash: string) {
|
||||
return /^[0-9A-f]{64}$/.test(hash);
|
||||
}
|
||||
|
|
111
web/index.html
Normal file
111
web/index.html
Normal file
|
@ -0,0 +1,111 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Picvatar</title>
|
||||
<style>
|
||||
body {
|
||||
width: min(calc(100% - 16px), 50em);
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
padding: 3em 0;
|
||||
}
|
||||
|
||||
.output-img {
|
||||
border-radius: 2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Picvatar</h1>
|
||||
<p>Generate unique avatars from a Picrew - Like Gravatar, but cooler!</p>
|
||||
|
||||
<div class="input-wrapper">
|
||||
<div class="input-field">
|
||||
<label for="email-input">Email address</label>
|
||||
<input id="email-input" type="text" placeholder="webmistress@amogus.cloud" />
|
||||
</div>
|
||||
<div class="input-field">
|
||||
<label for="maker-input">Picrew maker ID</label>
|
||||
<input id="maker-input" type="text" placeholder="47882" value="47882" />
|
||||
</div>
|
||||
<button style="height: 50%; align-self: flex-end;" onclick="generate()">Generate!</button>
|
||||
</div>
|
||||
|
||||
<div class="image-wrapper">
|
||||
<img
|
||||
class="output-img"
|
||||
id="output-img"
|
||||
src="/kitty.png"
|
||||
style="width: 100%; height: auto;"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h3 id="api">API</h3>
|
||||
|
||||
<h4 id="api-from-sha256">Generate an image from a sha256 hash</h4>
|
||||
<b><code>/generate/:makerid/:hash?gravatar=bool</code></b>
|
||||
<p>
|
||||
<b>Returns:</b> The generated image in png format.
|
||||
</p>
|
||||
<p>
|
||||
<code>:makerid</code> - The ID of the Picrew maker you want to use. You can get this from the Picrew URL: <code>https://picrew.me/en/image_maker/000000</code>
|
||||
</p>
|
||||
<p>
|
||||
<code>:hash</code> - Hex-encoded sha256 hash of the email address (or whatever other identifier you want to use).
|
||||
</p>
|
||||
<p>
|
||||
<code>?gravatar=bool</code> - If this is set to <code>true</code> or <code>1</code>, and the provided hash belongs to an email on Gravatar that has a custom avatar set, a redirect to that avatar will be returned and no Picrew will be generated. Any other value will disable this behaviour.
|
||||
<br />
|
||||
Note that this will slow down load times.
|
||||
</p>
|
||||
|
||||
<h4 id="api-from-email">Generate an image from an email address</h4>
|
||||
<b><code>/generate/:makerid/:email</code></b>
|
||||
<p>
|
||||
<b>Returns:</b> a redirect to <code>/generate/:makerid/:hash</code>, where <code>:hash</code> is a sha256 hash created from the provided email address. This is useful when you don't have access to relevant APIs to generate a sha256 hash, such as on a vanilla JS website without external dependencies.
|
||||
<br />
|
||||
Query parameters will be forwarded, so any parameters for <code>/generate/:makerid/:hash</code> are available.
|
||||
</p>
|
||||
<p>
|
||||
<code>:makerid</code> - <a href="#api-from-sha256">See above.</a>
|
||||
</p>
|
||||
<p>
|
||||
<code>:email</code> - The email address you want to generate an avatar for. Make sure this is URL-encoded!
|
||||
</p>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const outputImg = document.getElementById("output-img");
|
||||
|
||||
outputImg.onerror = (event) => {
|
||||
if (outputImg.src != '/kitty.png') outputImg.src = '/kitty.png';
|
||||
alert(`Ooprs! That didn't work: ${JSON.stringify(event)}`);
|
||||
}
|
||||
|
||||
function generate() {
|
||||
const email = document.getElementById("email-input").value;
|
||||
const maker = document.getElementById("maker-input").value;
|
||||
|
||||
if (!email || !maker) return;
|
||||
|
||||
const url = `/generate-by-email/${encodeURIComponent(maker)}/${encodeURIComponent(email)}`;
|
||||
outputImg.src = url;
|
||||
}
|
||||
</script>
|
||||
</html>
|
BIN
web/kitty.png
Normal file
BIN
web/kitty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
Loading…
Reference in a new issue