Done and done.
This commit is contained in:
		
							parent
							
								
									477301157e
								
							
						
					
					
						commit
						b08f259447
					
				
					 4 changed files with 402 additions and 38 deletions
				
			
		
							
								
								
									
										6
									
								
								node/nodemon.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								node/nodemon.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| { | ||||
|     "watch": ["src"], | ||||
|     "ext": "ts,json", | ||||
|     "ignore": ["src/**/*.spec.ts"], | ||||
|     "exec": "npx tsx ./src/index.ts" | ||||
| } | ||||
							
								
								
									
										350
									
								
								node/package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										350
									
								
								node/package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -1,12 +1,12 @@ | |||
| { | ||||
|   "name": "hit_counter", | ||||
|   "version": "0.0.1", | ||||
|   "version": "0.0.2", | ||||
|   "lockfileVersion": 3, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "hit_counter", | ||||
|       "version": "0.0.1", | ||||
|       "version": "0.0.2", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "better-sqlite3": "^11.5.0", | ||||
|  | @ -17,6 +17,7 @@ | |||
|         "@types/better-sqlite3": "^7.6.11", | ||||
|         "@types/express": "^5.0.0", | ||||
|         "@types/node": "^22.8.7", | ||||
|         "nodemon": "^3.1.7", | ||||
|         "tsx": "^4.19.2", | ||||
|         "typescript": "^5.6.3" | ||||
|       } | ||||
|  | @ -931,12 +932,33 @@ | |||
|         "node": ">= 0.6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/anymatch": { | ||||
|       "version": "3.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", | ||||
|       "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", | ||||
|       "dev": true, | ||||
|       "license": "ISC", | ||||
|       "dependencies": { | ||||
|         "normalize-path": "^3.0.0", | ||||
|         "picomatch": "^2.0.4" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/array-flatten": { | ||||
|       "version": "1.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", | ||||
|       "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/balanced-match": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", | ||||
|       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", | ||||
|       "dev": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/base64-js": { | ||||
|       "version": "1.5.1", | ||||
|       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", | ||||
|  | @ -968,6 +990,19 @@ | |||
|         "prebuild-install": "^7.1.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/binary-extensions": { | ||||
|       "version": "2.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", | ||||
|       "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/sindresorhus" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/bindings": { | ||||
|       "version": "1.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", | ||||
|  | @ -1012,6 +1047,30 @@ | |||
|         "npm": "1.2.8000 || >= 1.4.16" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/brace-expansion": { | ||||
|       "version": "1.1.11", | ||||
|       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", | ||||
|       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "balanced-match": "^1.0.0", | ||||
|         "concat-map": "0.0.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/braces": { | ||||
|       "version": "3.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", | ||||
|       "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "fill-range": "^7.1.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/buffer": { | ||||
|       "version": "5.7.1", | ||||
|       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", | ||||
|  | @ -1064,6 +1123,31 @@ | |||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/chokidar": { | ||||
|       "version": "3.6.0", | ||||
|       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", | ||||
|       "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "anymatch": "~3.1.2", | ||||
|         "braces": "~3.0.2", | ||||
|         "glob-parent": "~5.1.2", | ||||
|         "is-binary-path": "~2.1.0", | ||||
|         "is-glob": "~4.0.1", | ||||
|         "normalize-path": "~3.0.0", | ||||
|         "readdirp": "~3.6.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 8.10.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://paulmillr.com/funding/" | ||||
|       }, | ||||
|       "optionalDependencies": { | ||||
|         "fsevents": "~2.3.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/chownr": { | ||||
|       "version": "1.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", | ||||
|  | @ -1111,6 +1195,13 @@ | |||
|         "simple-swizzle": "^0.2.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/concat-map": { | ||||
|       "version": "0.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | ||||
|       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", | ||||
|       "dev": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/content-disposition": { | ||||
|       "version": "0.5.4", | ||||
|       "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", | ||||
|  | @ -1382,6 +1473,19 @@ | |||
|       "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/fill-range": { | ||||
|       "version": "7.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", | ||||
|       "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "to-regex-range": "^5.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/finalhandler": { | ||||
|       "version": "1.3.1", | ||||
|       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", | ||||
|  | @ -1486,6 +1590,19 @@ | |||
|       "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/glob-parent": { | ||||
|       "version": "5.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", | ||||
|       "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", | ||||
|       "dev": true, | ||||
|       "license": "ISC", | ||||
|       "dependencies": { | ||||
|         "is-glob": "^4.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/gopd": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", | ||||
|  | @ -1498,6 +1615,16 @@ | |||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/has-flag": { | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", | ||||
|       "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/has-property-descriptors": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", | ||||
|  | @ -1594,6 +1721,13 @@ | |||
|       ], | ||||
|       "license": "BSD-3-Clause" | ||||
|     }, | ||||
|     "node_modules/ignore-by-default": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", | ||||
|       "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", | ||||
|       "dev": true, | ||||
|       "license": "ISC" | ||||
|     }, | ||||
|     "node_modules/inherits": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", | ||||
|  | @ -1621,6 +1755,52 @@ | |||
|       "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/is-binary-path": { | ||||
|       "version": "2.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", | ||||
|       "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "binary-extensions": "^2.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/is-extglob": { | ||||
|       "version": "2.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", | ||||
|       "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=0.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/is-glob": { | ||||
|       "version": "4.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", | ||||
|       "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "is-extglob": "^2.1.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=0.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/is-number": { | ||||
|       "version": "7.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", | ||||
|       "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=0.12.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/media-typer": { | ||||
|       "version": "0.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", | ||||
|  | @ -1693,6 +1873,19 @@ | |||
|         "url": "https://github.com/sponsors/sindresorhus" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/minimatch": { | ||||
|       "version": "3.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", | ||||
|       "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", | ||||
|       "dev": true, | ||||
|       "license": "ISC", | ||||
|       "dependencies": { | ||||
|         "brace-expansion": "^1.1.7" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/minimist": { | ||||
|       "version": "1.2.8", | ||||
|       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", | ||||
|  | @ -1741,6 +1934,70 @@ | |||
|         "node": ">=10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/nodemon": { | ||||
|       "version": "3.1.7", | ||||
|       "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", | ||||
|       "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "chokidar": "^3.5.2", | ||||
|         "debug": "^4", | ||||
|         "ignore-by-default": "^1.0.1", | ||||
|         "minimatch": "^3.1.2", | ||||
|         "pstree.remy": "^1.1.8", | ||||
|         "semver": "^7.5.3", | ||||
|         "simple-update-notifier": "^2.0.0", | ||||
|         "supports-color": "^5.5.0", | ||||
|         "touch": "^3.1.0", | ||||
|         "undefsafe": "^2.0.5" | ||||
|       }, | ||||
|       "bin": { | ||||
|         "nodemon": "bin/nodemon.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/nodemon" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/nodemon/node_modules/debug": { | ||||
|       "version": "4.3.7", | ||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", | ||||
|       "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "ms": "^2.1.3" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=6.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "supports-color": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/nodemon/node_modules/ms": { | ||||
|       "version": "2.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | ||||
|       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | ||||
|       "dev": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/normalize-path": { | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", | ||||
|       "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=0.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/object-inspect": { | ||||
|       "version": "1.13.2", | ||||
|       "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", | ||||
|  | @ -1789,6 +2046,19 @@ | |||
|       "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/picomatch": { | ||||
|       "version": "2.3.1", | ||||
|       "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", | ||||
|       "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=8.6" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/jonschlinkert" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/prebuild-install": { | ||||
|       "version": "7.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", | ||||
|  | @ -1828,6 +2098,13 @@ | |||
|         "node": ">= 0.10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/pstree.remy": { | ||||
|       "version": "1.1.8", | ||||
|       "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", | ||||
|       "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", | ||||
|       "dev": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/pump": { | ||||
|       "version": "3.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", | ||||
|  | @ -1906,6 +2183,19 @@ | |||
|         "node": ">= 6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/readdirp": { | ||||
|       "version": "3.6.0", | ||||
|       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", | ||||
|       "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "picomatch": "^2.2.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/resolve-pkg-maps": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", | ||||
|  | @ -2142,6 +2432,19 @@ | |||
|         "is-arrayish": "^0.3.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/simple-update-notifier": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", | ||||
|       "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "semver": "^7.5.3" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/statuses": { | ||||
|       "version": "2.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", | ||||
|  | @ -2169,6 +2472,19 @@ | |||
|         "node": ">=0.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/supports-color": { | ||||
|       "version": "5.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", | ||||
|       "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "has-flag": "^3.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/tar-fs": { | ||||
|       "version": "2.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", | ||||
|  | @ -2197,6 +2513,19 @@ | |||
|         "node": ">=6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/to-regex-range": { | ||||
|       "version": "5.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", | ||||
|       "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "is-number": "^7.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/toidentifier": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", | ||||
|  | @ -2206,6 +2535,16 @@ | |||
|         "node": ">=0.6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/touch": { | ||||
|       "version": "3.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", | ||||
|       "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", | ||||
|       "dev": true, | ||||
|       "license": "ISC", | ||||
|       "bin": { | ||||
|         "nodetouch": "bin/nodetouch.js" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/tslib": { | ||||
|       "version": "2.8.1", | ||||
|       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", | ||||
|  | @ -2272,6 +2611,13 @@ | |||
|         "node": ">=14.17" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/undefsafe": { | ||||
|       "version": "2.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", | ||||
|       "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", | ||||
|       "dev": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/undici-types": { | ||||
|       "version": "6.19.8", | ||||
|       "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| { | ||||
|   "name": "hit_counter", | ||||
|   "version": "0.0.1", | ||||
|   "version": "0.0.2", | ||||
|   "type": "module", | ||||
|   "description": "A simple hit counter", | ||||
|   "main": "dist/index.js", | ||||
|  | @ -12,7 +12,7 @@ | |||
|   "scripts": { | ||||
|     "build": "npx tsc", | ||||
|     "start": "npm run build && node dist/index.js", | ||||
|     "dev": "npx tsx src/index.ts" | ||||
|     "dev": "npx nodemon" | ||||
|   }, | ||||
|   "author": "zeyus", | ||||
|   "license": "MIT", | ||||
|  | @ -20,6 +20,7 @@ | |||
|     "@types/better-sqlite3": "^7.6.11", | ||||
|     "@types/express": "^5.0.0", | ||||
|     "@types/node": "^22.8.7", | ||||
|     "nodemon": "^3.1.7", | ||||
|     "tsx": "^4.19.2", | ||||
|     "typescript": "^5.6.3" | ||||
|   } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ import { type Database as DB } from 'better-sqlite3'; | |||
| import { type Statement } from 'better-sqlite3'; | ||||
| import Database from 'better-sqlite3'; | ||||
| // import sharp for images
 | ||||
| import sharp, { FormatEnum, AvailableFormatInfo, Sharp, Metadata } from 'sharp'; | ||||
| import sharp, { FormatEnum, AvailableFormatInfo, Sharp, Metadata, TextAlign } from 'sharp'; | ||||
| import * as fs from 'fs'; | ||||
| import * as https from 'https'; | ||||
| 
 | ||||
|  | @ -173,41 +173,38 @@ class ImageHitCounterRenderer extends BaseHitCounterRenderer { | |||
|         const bgInfo = await bgImage.metadata(); | ||||
|         const imgWidth = bgInfo.width; | ||||
|         const imgHeight = bgInfo.height; | ||||
|         if (typeof imgWidth === 'undefined' || typeof imgHeight === 'undefined') { | ||||
|         const imgDensity = bgInfo.density; | ||||
|         if (typeof imgWidth === 'undefined' || typeof imgHeight === 'undefined' || typeof imgDensity === 'undefined') { | ||||
|             throw new Error('Invalid image dimensions'); | ||||
|         } | ||||
| 
 | ||||
|         const svgFrame = ` | ||||
|             <svg width="${bgInfo.width}" height="${bgInfo.height}" xmlns="http://www.w3.org/2000/svg"> | ||||
|                 <rect x="${this.config.borderWidth}" y="${this.config.borderWidth}" width="${imgWidth - 2 * this.config.borderWidth}" height="${imgHeight - 2 * this.config.borderWidth}" fill="none" stroke-alignment="inner" stroke="rgb(${this.config.frameColorRGB.r},${this.config.frameColorRGB.g},${this.config.frameColorRGB.b})" stroke-width="${this.config.borderWidth}"/> | ||||
|             </svg> | ||||
|         `;
 | ||||
|         let svgFrame = ''; | ||||
|         if (this.config.drawFrame) { | ||||
|             svgFrame = `<rect x="0" y="0" width="100%" height="100%" fill="none" stroke-alignment="inner" stroke="rgb(${this.config.frameColorRGB.r},${this.config.frameColorRGB.g},${this.config.frameColorRGB.b})" stroke-width="${this.config.borderWidth}" />`; | ||||
|              | ||||
|         } | ||||
|          | ||||
|         const svgOverlay = ` | ||||
|             <svg width="${bgInfo.width}" height="${bgInfo.height}" xmlns="http://www.w3.org/2000/svg"> | ||||
|                 <text x="${this.config.textPositionX}" y="${this.config.textPositionY}" fill="rgb(${this.config.textColorRGB.r},${this.config.textColorRGB.g},${this.config.textColorRGB.b})" font-size="${this.config.fontSize}" font-family="${this.config.fontFace}">${this.config.customText}</text> | ||||
|                 <text x="${this.config.textPositionX}" y="${this.config.textPositionY + 15}" fill="rgb(${this.config.textColorRGB.r},${this.config.textColorRGB.g},${this.config.textColorRGB.b})" font-size="${this.config.fontSize}" font-family="${this.config.fontFace}">${this.config.secondaryText}</text> | ||||
|             <svg xmlns="http://www.w3.org/2000/svg" width="${imgWidth}" height="${imgHeight}"> | ||||
|                 <text y="${this.config.textPositionY}" font-family="${this.config.fontFace}" font-size="${this.config.fontSize}"> | ||||
|                     <tspan x="${this.config.textPositionX}" dy="0" fill="rgb(${this.config.textColorRGB.r},${this.config.textColorRGB.g},${this.config.textColorRGB.b})">${this.config.customText}</tspan> | ||||
|                     <tspan x="${this.config.textPositionX}" dy="1.2em" fill="rgb(${this.config.secondaryTextColorRGB.r},${this.config.secondaryTextColorRGB.g},${this.config.secondaryTextColorRGB.b})">${this.config.secondaryText}</tspan> | ||||
|                 </text> | ||||
|                 ${svgFrame} | ||||
|             </svg> | ||||
|         `;
 | ||||
| 
 | ||||
|         const overlay = sharp(Buffer.from(svgOverlay)); | ||||
| 
 | ||||
|         if (this.config.drawFrame) { | ||||
|             const frame = sharp(Buffer.from(svgFrame)); | ||||
|             const composite = bgImage.composite([ | ||||
|                 { input: await overlay.toBuffer(), gravity: 'northwest' }, | ||||
|                 { input: await frame.toBuffer(), gravity: 'northwest' } | ||||
|             ]); | ||||
|             const preparedImg = composite.toFormat(this.imageFormat); | ||||
|             this.baseImageMetadata = await preparedImg.metadata(); | ||||
|             this.baseImage = await preparedImg.toBuffer();; | ||||
|         } | ||||
|         const overlay = Buffer.from(svgOverlay); | ||||
| 
 | ||||
|         const composite = bgImage.composite([ | ||||
|             { input: await overlay.toBuffer(), gravity: 'northwest' } | ||||
|             { | ||||
|                 input: overlay, | ||||
|                 top: 0, | ||||
|                 left: 0 | ||||
|             } | ||||
|         ]); | ||||
| 
 | ||||
|         const preparedImg = composite.toFormat(this.imageFormat); | ||||
|         const preparedImg = composite.toFormat(this.imageFormat).withMetadata(); | ||||
|         this.baseImageMetadata = await preparedImg.metadata(); | ||||
|         this.baseImage = await preparedImg.toBuffer(); | ||||
| 
 | ||||
|  | @ -216,19 +213,33 @@ class ImageHitCounterRenderer extends BaseHitCounterRenderer { | |||
|     async render(): Promise<Buffer> { | ||||
|         const hits = await this.counter.getHits(); | ||||
|          | ||||
|         const numberColor = this.config.numberColorRGB; | ||||
|         const numberX = this.config.numberPositionX; | ||||
|         const numberY = this.config.numberPositionY; | ||||
| 
 | ||||
|         await this.prepareBaseImage(); | ||||
|         const overlay = ` | ||||
|             <svg width="${this.baseImageMetadata.width}" height="${this.baseImageMetadata.height}" xmlns="http://www.w3.org/2000/svg"> | ||||
|                 <text x="${numberX}" y="${numberY}" fill="rgb(${numberColor.r},${numberColor.g},${numberColor.b})" font-size="12">${hits}</text> | ||||
| 
 | ||||
|         const imgWidth = this.baseImageMetadata.width; | ||||
|         const imgHeight = this.baseImageMetadata.height; | ||||
|         if (typeof imgWidth === 'undefined' || typeof imgHeight === 'undefined') { | ||||
|             throw new Error('Invalid image dimensions'); | ||||
|         } | ||||
|          | ||||
|         const svgNumber = ` | ||||
|             <svg xmlns="http://www.w3.org/2000/svg" width="${imgWidth}" height="${imgHeight}"> | ||||
|                 <text x="${numberX}" y="${numberY}" font-family="${this.config.fontFace}" font-size="${this.config.fontSize}" text-anchor="end" fill="rgb(${this.config.numberColorRGB.r},${this.config.numberColorRGB.g},${this.config.numberColorRGB.b})">${hits}</text> | ||||
|             </svg> | ||||
|         `;
 | ||||
| 
 | ||||
|         const numberOverlay = Buffer.from(svgNumber); | ||||
| 
 | ||||
|         const composite = sharp(this.baseImage).composite([ | ||||
|             { input: Buffer.from(overlay), gravity: 'northwest' } | ||||
|             { | ||||
|                 input: numberOverlay, | ||||
|                 top: 0, | ||||
|                 left: 0 | ||||
|             } | ||||
|         ]); | ||||
| 
 | ||||
|         return composite.toBuffer(); | ||||
|          | ||||
|     } | ||||
|  | @ -274,11 +285,11 @@ const defaultHitCounterConfig: HitCounterConfig = { | |||
|     customText: 'Hit Counter!', | ||||
|     secondaryText: 'Super cyber, super cool!', | ||||
|     textPositionX: 5, | ||||
|     textPositionY: 5, | ||||
|     numberPositionX: 160, | ||||
|     numberPositionY: 15, | ||||
|     fontSize: 12, | ||||
|     fontFace: 'Arial', | ||||
|     textPositionY: 11, | ||||
|     numberPositionX: 170, | ||||
|     numberPositionY: 18, | ||||
|     fontSize: 10, | ||||
|     fontFace: 'fixed', | ||||
|     borderWidth: 3, | ||||
|     textColorRGB: { r: 253, g: 252, b: 1 }, | ||||
|     secondaryTextColorRGB: { r: 0, g: 255, b: 0 }, | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue