commit 298b005929a95a95a56f8bb8bfb0d546304b8f7c Author: DrMint <29893320+DrMint@users.noreply.github.com> Date: Sat Jul 13 15:37:59 2024 +0200 Synchro script at server bootup diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b115fab --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules +server/data.ms +server/dumps + +.env \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2c28f1e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/shared"] + path = src/shared + url = https://github.com/Accords-Library/shared-library.git diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b4fabdc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "editor.rulers": [100], + "editor.tabSize": 2, + "typescript.preferences.importModuleSpecifier": "non-relative", + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.patterns": { + "package.json": ".git*, package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb, .ncurc.*, .nvmrc, *.config.cjs, *.config.js, *.config.ts, *config.json, .*ignore", + ".env": ".env.*", + "README.md": "*.md" + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7794fed --- /dev/null +++ b/package-lock.json @@ -0,0 +1,548 @@ +{ + "name": "meili.accords-library.com", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "meili.accords-library.com", + "version": "1.0.0", + "dependencies": { + "meilisearch": "^0.41.0" + }, + "devDependencies": { + "@types/node": "^20.14.9", + "tsx": "^4.16.2" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/node": { + "version": "20.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", + "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/meilisearch": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.41.0.tgz", + "integrity": "sha512-5KcGLxEXD7E+uNO7R68rCbGSHgCqeM3Q3RFFLSsN7ZrIgr8HPDXVAIlP4LHggAZfk0FkSzo8VSXifHCwa2k80g==", + "dependencies": { + "cross-fetch": "^3.1.6" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tsx": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.16.2.tgz", + "integrity": "sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==", + "dev": true, + "dependencies": { + "esbuild": "~0.21.5", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d7e9048 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "meili.accords-library.com", + "version": "1.0.0", + "type": "module", + "scripts": { + "podman": "podman run -it --rm -p 33655:7700 --env-file .env -v $(pwd)/server:/meili_data docker.io/getmeili/meilisearch:v1.9", + "dev": "tsx watch --env-file=.env src/index.ts", + "fetch-submodules": "cd src/shared && git pull && cd ../.." + }, + "dependencies": { + "meilisearch": "^0.41.0" + }, + "devDependencies": { + "@types/node": "^20.14.9", + "tsx": "^4.16.2" + } +} diff --git a/server/config.toml b/server/config.toml new file mode 100644 index 0000000..8febcd9 --- /dev/null +++ b/server/config.toml @@ -0,0 +1,134 @@ +# This file shows the default configuration of Meilisearch. +# All variables are defined here: https://www.meilisearch.com/docs/learn/configuration/instance_options#environment-variables + +# Designates the location where database files will be created and retrieved. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#database-path +db_path = "./data.ms" + +# Configures the instance's environment. Value must be either `production` or `development`. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#environment +env = "development" + +# The address on which the HTTP server will listen. +http_addr = "localhost:7700" + +# Sets the instance's master key, automatically protecting all routes except GET /health. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#master-key +# master_key = "" + +# Deactivates Meilisearch's built-in telemetry when provided. +# Meilisearch automatically collects data from all instances that do not opt out using this flag. +# All gathered data is used solely for the purpose of improving Meilisearch, and can be deleted at any time. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#disable-analytics +no_analytics = true + +# Sets the maximum size of accepted payloads. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#payload-limit-size +http_payload_size_limit = "100 MB" + +# Defines how much detail should be present in Meilisearch's logs. +# Meilisearch currently supports six log levels, listed in order of increasing verbosity: `OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE` +# https://www.meilisearch.com/docs/learn/configuration/instance_options#log-level +log_level = "INFO" + +# Sets the maximum amount of RAM Meilisearch can use when indexing. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#max-indexing-memory +# max_indexing_memory = "2 GiB" + +# Sets the maximum number of threads Meilisearch can use during indexing. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#max-indexing-threads +# max_indexing_threads = 4 + +############# +### DUMPS ### +############# + +# Sets the directory where Meilisearch will create dump files. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#dump-directory +dump_dir = "dumps/" + +# Imports the dump file located at the specified path. Path must point to a .dump file. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#import-dump +# import_dump = "./path/to/my/file.dump" + +# Prevents Meilisearch from throwing an error when `import_dump` does not point to a valid dump file. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ignore-missing-dump +ignore_missing_dump = false + +# Prevents a Meilisearch instance with an existing database from throwing an error when using `import_dump`. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ignore-dump-if-db-exists +ignore_dump_if_db_exists = false + + +################# +### SNAPSHOTS ### +################# + +# Enables scheduled snapshots when true, disable when false (the default). +# If the value is given as an integer, then enables the scheduled snapshot with the passed value as the interval +# between each snapshot, in seconds. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#schedule-snapshot-creation +schedule_snapshot = false + +# Sets the directory where Meilisearch will store snapshots. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#snapshot-destination +snapshot_dir = "snapshots/" + +# Launches Meilisearch after importing a previously-generated snapshot at the given filepath. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#import-snapshot +# import_snapshot = "./path/to/my/snapshot" + +# Prevents a Meilisearch instance from throwing an error when `import_snapshot` does not point to a valid snapshot file. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ignore-missing-snapshot +ignore_missing_snapshot = false + +# Prevents a Meilisearch instance with an existing database from throwing an error when using `import_snapshot`. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ignore-snapshot-if-db-exists +ignore_snapshot_if_db_exists = false + + +########### +### SSL ### +########### + +# Enables client authentication in the specified path. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ssl-authentication-path +# ssl_auth_path = "./path/to/root" + +# Sets the server's SSL certificates. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ssl-certificates-path +# ssl_cert_path = "./path/to/certfile" + +# Sets the server's SSL key files. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ssl-key-path +# ssl_key_path = "./path/to/private-key" + +# Sets the server's OCSP file. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ssl-ocsp-path +# ssl_ocsp_path = "./path/to/ocsp-file" + +# Makes SSL authentication mandatory. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ssl-require-auth +ssl_require_auth = false + +# Activates SSL session resumption. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ssl-resumption +ssl_resumption = false + +# Activates SSL tickets. +# https://www.meilisearch.com/docs/learn/configuration/instance_options#ssl-tickets +ssl_tickets = false + +############################# +### Experimental features ### +############################# + +# Experimental metrics feature. For more information, see: +# Enables the Prometheus metrics on the `GET /metrics` endpoint. +experimental_enable_metrics = false + +# Experimental RAM reduction during indexing, do not use in production, see: +experimental_reduce_indexing_memory_usage = false + +# Experimentally reduces the maximum number of tasks that will be processed at once, see: +# experimental_max_number_of_batched_tasks = 100 diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..eec18c4 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,33 @@ +import http from "http"; +import { synchronizeMeiliDocs } from "./synchro"; + + +await synchronizeMeiliDocs(); + +export const requestListener: http.RequestListener = async (req, res) => { + if (req.method !== "POST") { + res + .writeHead(405, { "Content-Type": "application/json" }) + .end(JSON.stringify({ message: "Method Not Allowed. Use POST." })); + return; + } + + if (req.headers.authorization !== `Bearer ${process.env.WEBHOOK_TOKEN}`) { + res + .writeHead(403, { "Content-Type": "application/json" }) + .end(JSON.stringify({ message: "Invalid auth token." })); + return; + } + + res.writeHead(200, { "Content-Type": "application/json" }).end( + JSON.stringify({ + message: "Done.", + }) + ); +}; + +http.createServer(requestListener).listen(process.env.PORT, () => { + console.log(`Server started: http://localhost:${process.env.PORT}`); +}); + + diff --git a/src/services.ts b/src/services.ts new file mode 100644 index 0000000..b404373 --- /dev/null +++ b/src/services.ts @@ -0,0 +1,18 @@ +import { MeiliSearch } from "meilisearch"; +import { PayloadSDK } from "./shared/payload/sdk"; +import { TokenCache } from "./tokenCache"; + +export const meili = new MeiliSearch({ + host: process.env.MEILI_URL ?? "", + apiKey: process.env.MEILI_MASTER_KEY ?? "", +}); + +const tokenCache = new TokenCache(); + +export const payload = new PayloadSDK( + process.env.PAYLOAD_API_URL ?? "", + process.env.PAYLOAD_USER ?? "", + process.env.PAYLOAD_PASSWORD ?? "" +); + +payload.addTokenCache(tokenCache); diff --git a/src/synchro.ts b/src/synchro.ts new file mode 100644 index 0000000..5c2d300 --- /dev/null +++ b/src/synchro.ts @@ -0,0 +1,264 @@ +import { meili, payload } from "src/services"; +import type { MeiliDocument } from "src/shared/meilisearch/types"; +import { Collections } from "src/shared/payload/constants"; +import { + formatInlineTitle, + formatRichTextContentToString, +} from "src/shared/payload/format"; + +enum Indexes { + DOCUMENT = "DOCUMENT", +} + +export const synchronizeMeiliDocs = async () => { + const version = await meili.getVersion(); + console.log("Success connecting to Meili!"); + console.log("Meili version:", version.pkgVersion); + + const indexes = await meili.getIndexes({ limit: 1_000 }); + + await Promise.all( + indexes.results.map((index) => { + console.log("Deleting index", index.uid); + return index.delete(); + }) + ); + + await meili.createIndex(Indexes.DOCUMENT, { primaryKey: "meilid" }); + const index = meili.index(Indexes.DOCUMENT); + await index.updatePagination({ maxTotalHits: 100_000 }); + await index.updateFilterableAttributes(["languages", "type"]); + await index.updateSortableAttributes(["title", "updatedAt"]); + await index.updateSearchableAttributes(["title", "content"]); + await index.updateDistinctAttribute("id"); + // await index.updateDisplayedAttributes(["type", "page"]); + + const documents: MeiliDocument[] = []; + + const allIds = (await payload.getAllIds()).data; + + for (const slug of allIds.pages.slugs) { + const page = (await payload.getPage(slug)).data; + documents.push( + ...page.translations.map( + ({ language, pretitle, title, subtitle, content, summary }) => ({ + meilid: `${page.id}_${language}`, + id: page.id, + languages: page.translations.map(({ language }) => language), + title: formatInlineTitle({ pretitle, title, subtitle }), + content: `${ + summary ? `${formatRichTextContentToString(summary)}\n\n\n` : "" + }${formatRichTextContentToString(content)}`, + updatedAt: Date.parse(page.updatedAt), + type: Collections.Pages, + data: page, + }) + ) + ); + } + + for (const slug of allIds.collectibles.slugs) { + const collectible = (await payload.getCollectible(slug)).data; + documents.push( + ...collectible.translations.map( + ({ language, pretitle, title, subtitle, description }) => ({ + meilid: `${collectible.id}_${language}`, + id: collectible.id, + languages: collectible.translations.map(({ language }) => language), // Add languages from languages field + title: formatInlineTitle({ pretitle, title, subtitle }), + ...(description + ? { description: formatRichTextContentToString(description) } + : {}), + updatedAt: Date.parse(collectible.updatedAt), + type: Collections.Collectibles, + data: collectible, + }) + ) + ); + } + + for (const slug of allIds.folders.slugs) { + const folder = (await payload.getFolder(slug)).data; + documents.push( + ...folder.translations.map( + ({ language, title, description }) => ({ + meilid: `${folder.id}_${language}`, + id: folder.id, + languages: [], + title, + ...(description + ? { description: formatRichTextContentToString(description) } + : {}), + type: Collections.Folders, + data: folder, + }) + ) + ); + } + + for (const id of allIds.audios.ids) { + const audio = (await payload.getAudioByID(id)).data; + documents.push( + ...audio.translations.map( + ({ language, title, description }) => ({ + meilid: `${audio.id}_${language}`, + id: audio.id, + languages: audio.translations.map(({ language }) => language), + title, + ...(description + ? { description: formatRichTextContentToString(description) } + : {}), + updatedAt: Date.parse(audio.updatedAt), + type: Collections.Audios, + data: audio, + }) + ) + ); + } + + for (const id of allIds.images.ids) { + const image = (await payload.getImageByID(id)).data; + + if (image.translations.length > 0) { + documents.push( + ...image.translations.map( + ({ language, title, description }) => ({ + meilid: `${image.id}_${language}`, + id: image.id, + languages: [], + title, + ...(description + ? { description: formatRichTextContentToString(description) } + : {}), + updatedAt: Date.parse(image.updatedAt), + type: Collections.Images, + data: image, + }) + ) + ); + } else { + documents.push({ + meilid: image.id, + id: image.id, + languages: [], + title: image.filename, + updatedAt: Date.parse(image.updatedAt), + type: Collections.Images, + data: image, + }); + } + } + + for (const id of allIds.videos.ids) { + const video = (await payload.getVideoByID(id)).data; + documents.push( + ...video.translations.map( + ({ language, title, description }) => ({ + meilid: `${video.id}_${language}`, + id: video.id, + languages: video.translations.map(({ language }) => language), + title, + ...(description + ? { description: formatRichTextContentToString(description) } + : {}), + updatedAt: Date.parse(video.updatedAt), + type: Collections.Videos, + data: video, + }) + ) + ); + } + + for (const id of allIds.recorders.ids) { + const recorder = (await payload.getRecorderByID(id)).data; + if (recorder.translations.length > 0) { + documents.push( + ...recorder.translations.map( + ({ language, biography }) => ({ + meilid: `${recorder.id}_${language}`, + id: recorder.id, + languages: [], + title: recorder.username, + ...(biography + ? { description: formatRichTextContentToString(biography) } + : {}), + type: Collections.Recorders, + data: recorder, + }) + ) + ); + } else { + documents.push({ + meilid: recorder.id, + id: recorder.id, + languages: [], + title: recorder.username, + type: Collections.Recorders, + data: recorder, + }); + } + } + + for (const id of allIds.files.ids) { + const file = (await payload.getFileByID(id)).data; + if (file.translations.length > 0) { + documents.push( + ...file.translations.map( + ({ language, title, description }) => ({ + meilid: `${file.id}_${language}`, + id: file.id, + languages: [], + title, + ...(description + ? { description: formatRichTextContentToString(description) } + : {}), + updatedAt: Date.parse(file.updatedAt), + type: Collections.Files, + data: file, + }) + ) + ); + } else { + documents.push({ + meilid: file.id, + id: file.id, + languages: [], + title: file.filename, + updatedAt: Date.parse(file.updatedAt), + type: Collections.Files, + data: file, + }); + } + } + + for (const id of allIds.chronologyEvents.ids) { + const chronologyEvent = (await payload.getChronologyEventByID(id)).data; + documents.push( + ...chronologyEvent.events.flatMap((event, index) => + event.translations.map( + ({ language, description, title, notes }) => ({ + meilid: `${chronologyEvent.id}_${index}_${language}`, + id: `${chronologyEvent.id}_${index}`, + languages: event.translations.map(({ language }) => language), + ...(title ? { title } : {}), + ...(description || notes + ? { + content: `${ + description + ? formatRichTextContentToString(description) + : "" + }\n\n${notes ? formatRichTextContentToString(notes) : ""}`, + } + : {}), + type: Collections.ChronologyEvents, + data: { date: chronologyEvent.date, event }, + }) + ) + ) + ); + } + + console.log("Adding", documents.length, "documents"); + + await index.addDocuments(documents); +}; diff --git a/src/tokenCache.ts b/src/tokenCache.ts new file mode 100644 index 0000000..9eb589d --- /dev/null +++ b/src/tokenCache.ts @@ -0,0 +1,26 @@ +export class TokenCache { + private token: string | undefined; + private expiration: number | undefined; + + get() { + if (!this.token) return undefined; + if (!this.expiration || this.expiration < Date.now()) { + console.log("[PayloadSDK] No token to be retrieved or the token expired"); + return undefined; + } + return this.token; + } + + set(newToken: string, newExpiration: number) { + this.token = newToken; + this.expiration = newExpiration * 1000; + const diffInMinutes = Math.floor( + (this.expiration - Date.now()) / 1000 / 60 + ); + console.log( + "[PayloadSDK] New token set. TTL is", + diffInMinutes, + "minutes." + ); + } + } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1a9fa34 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,58 @@ +{ + "compilerOptions": { + // Enable top-level await, and other modern ESM features. + "target": "ESNext", + "module": "ESNext", + // Enable module resolution without file extensions on relative paths, for things like npm package imports. + "moduleResolution": "Bundler", + // Allow importing TypeScript files using their native extension (.ts(x)). + "allowImportingTsExtensions": true, + // Enable JSON imports. + "resolveJsonModule": true, + // Enforce the usage of type-only imports when needed, which helps avoiding bundling issues. + "verbatimModuleSyntax": true, + // Ensure that each file can be transpiled without relying on other imports. + // This is redundant with the previous option, however it ensures that it's on even if someone disable `verbatimModuleSyntax` + "isolatedModules": true, + // Astro directly run TypeScript code, no transpilation needed. + "noEmit": true, + // Report an error when importing a file using a casing different from another import of the same file. + "forceConsistentCasingInFileNames": true, + // Properly support importing CJS modules in ESM + "esModuleInterop": true, + // Skip typechecking libraries and .d.ts files + "skipLibCheck": true, + // Allow JavaScript files to be imported + "allowJs": true, + // Allow JSX files (or files that are internally considered JSX, like Astro files) to be imported inside `.js` and `.ts` files. + "jsx": "preserve", + + // Enable strict mode. This enables a few options at a time, see https://www.typescriptlang.org/tsconfig#strict for a list. + "strict": true, + + // Report errors for fallthrough cases in switch statements + "noFallthroughCasesInSwitch": true, + // Force functions designed to override their parent class to be specified as `override`. + "noImplicitOverride": true, + // Force functions to specify that they can return `undefined` if a possible code path does not return a value. + "noImplicitReturns": true, + // Report an error when a variable is declared but never used. + "noUnusedLocals": true, + // Report an error when a parameter is declared but never used. + "noUnusedParameters": true, + // Force the usage of the indexed syntax to access fields declared using an index signature. + "noUncheckedIndexedAccess": true, + // Report an error when the value `undefined` is given to an optional property that doesn't specify `undefined` as a valid value. + "exactOptionalPropertyTypes": true, + // Report an error for unreachable code instead of just a warning. + "allowUnreachableCode": false, + // Report an error for unused labels instead of just a warning. + "allowUnusedLabels": false, + + "baseUrl": ".", + "paths": { + "pages/*": ["src/pages/*"], + "components/*": ["src/components/*"] + } + } +}