diff --git a/package.json b/package.json index a270e82a..6d155b2e 100644 --- a/package.json +++ b/package.json @@ -21,10 +21,11 @@ "build-geo": "node scripts/build-geo.js", "build-db-schema": "dotenv prisma introspect", "build-db-client": "dotenv prisma generate", - "build-mysql-schema": "dotenv prisma introspect -- --schema=./prisma/schema.mysql.prisma", + "build-mysql-schema": "dotenv prisma db pull -- --schema=./prisma/schema.mysql.prisma", "build-mysql-client": "dotenv prisma generate -- --schema=./prisma/schema.mysql.prisma", - "build-postgresql-schema": "dotenv prisma introspect -- --schema=./prisma/schema.postgresql.prisma", + "build-postgresql-schema": "dotenv prisma db pull -- --schema=./prisma/schema.postgresql.prisma", "build-postgresql-client": "dotenv prisma generate -- --schema=./prisma/schema.postgresql.prisma", + "postbuild": "node scripts/telemetry.js", "copy-db-schema": "node scripts/copy-db-schema.js", "generate-lang": "npm-run-all extract-lang merge-lang", "extract-lang": "formatjs extract \"{pages,components}/**/*.js\" --out-file build/messages.json", @@ -54,6 +55,7 @@ "dependencies": { "@fontsource/inter": "4.5.4", "@prisma/client": "3.10.0", + "async-retry": "^1.3.3", "bcryptjs": "^2.4.3", "chalk": "^4.1.1", "chart.js": "^2.9.4", @@ -65,14 +67,18 @@ "detect-browser": "^5.2.0", "dotenv": "^10.0.0", "formik": "^2.2.9", + "fs-extra": "^10.0.1", "immer": "^9.0.12", "ipaddr.js": "^2.0.1", + "is-ci": "^3.0.1", + "is-docker": "^3.0.0", "is-localhost-ip": "^1.4.0", "isbot": "^3.4.5", "jose": "2.0.5", "maxmind": "^4.3.2", "moment-timezone": "^0.5.33", "next": "12.1.0", + "node-fetch": "^3.2.3", "prompts": "2.4.2", "prop-types": "^15.7.2", "react": "^17.0.2", diff --git a/scripts/download-country-names.js b/scripts/download-country-names.js index 4ee90cd4..11075b22 100644 --- a/scripts/download-country-names.js +++ b/scripts/download-country-names.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const fs = require('fs-extra'); const path = require('path'); const https = require('https'); const chalk = require('chalk'); @@ -16,11 +16,9 @@ const asyncForEach = async (array, callback) => { } }; -if (!fs.existsSync(dest)) { - fs.mkdirSync(dest); -} - const download = async files => { + await fs.ensureDir(dest); + await asyncForEach(files, async file => { const locale = file.replace('-', '_').replace('.json', ''); diff --git a/scripts/download-language-names.js b/scripts/download-language-names.js index fe42af56..5b8901a9 100644 --- a/scripts/download-language-names.js +++ b/scripts/download-language-names.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const fs = require('fs-extra'); const path = require('path'); const https = require('https'); const chalk = require('chalk'); @@ -16,11 +16,9 @@ const asyncForEach = async (array, callback) => { } }; -if (!fs.existsSync(dest)) { - fs.mkdirSync(dest); -} - const download = async files => { + await fs.ensureDir(dest); + await asyncForEach(files, async file => { const locale = file.replace('-', '_').replace('.json', ''); diff --git a/scripts/format-lang.js b/scripts/format-lang.js index f5766ced..5d1adb01 100644 --- a/scripts/format-lang.js +++ b/scripts/format-lang.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const fs = require('fs-extra'); const path = require('path'); const del = require('del'); const prettier = require('prettier'); @@ -14,22 +14,24 @@ if (removed.length) { console.log(removed.map(n => `${n} ${chalk.redBright('✗')}`).join('\n')); } -if (!fs.existsSync(dest)) { - fs.mkdirSync(dest); +async function run() { + await fs.ensureDir(dest); + + files.forEach(file => { + const lang = require(`../lang/${file}`); + const keys = Object.keys(lang).sort(); + + const formatted = keys.reduce((obj, key) => { + obj[key] = { defaultMessage: lang[key] }; + return obj; + }, {}); + + const json = prettier.format(JSON.stringify(formatted), { parser: 'json' }); + + fs.writeFileSync(path.resolve(dest, file), json); + + console.log(path.resolve(src, file), chalk.greenBright('->'), path.resolve(dest, file)); + }); } -files.forEach(file => { - const lang = require(`../lang/${file}`); - const keys = Object.keys(lang).sort(); - - const formatted = keys.reduce((obj, key) => { - obj[key] = { defaultMessage: lang[key] }; - return obj; - }, {}); - - const json = prettier.format(JSON.stringify(formatted), { parser: 'json' }); - - fs.writeFileSync(path.resolve(dest, file), json); - - console.log(path.resolve(src, file), chalk.greenBright('->'), path.resolve(dest, file)); -}); +run(); diff --git a/scripts/telemetry.js b/scripts/telemetry.js new file mode 100644 index 00000000..4971b759 --- /dev/null +++ b/scripts/telemetry.js @@ -0,0 +1,59 @@ +require('dotenv').config(); +const fs = require('fs-extra'); +const path = require('path'); +const os = require('os'); +const retry = require('async-retry'); +const isCI = require('is-ci'); +const pkg = require('../package.json'); + +const dest = path.resolve(__dirname, '../.next/cache/umami.json'); +const url = 'https://telemetry.umami.is/api/collect'; + +async function run() { + await fs.ensureFile(dest); + + let json = {}; + + try { + json = await fs.readJSON(dest); + } catch { + // Ignore + } + + if (json.version !== pkg.version) { + const { default: isDocker } = await import('is-docker'); + const { default: fetch } = await import('node-fetch'); + + await fs.writeJSON(dest, { version: pkg.version }); + + const payload = { + umami: pkg.version, + node: process.version, + platform: os.platform(), + arch: os.arch(), + os: os.version(), + isDocker: isDocker(), + isCI, + }; + + await retry( + async () => { + const res = await fetch(url, { + method: 'post', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + console.log(res); + }, + { minTimeout: 500, retries: 1, factor: 1 }, + ).catch(() => {}); + } +} + +if (!process.env.TELEMETRY_DISABLED) { + run(); +} diff --git a/yarn.lock b/yarn.lock index 6620c13f..910c925e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2072,6 +2072,13 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + at-least-node@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" @@ -2303,6 +2310,11 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== +ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + classnames@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" @@ -2633,6 +2645,11 @@ damerau-levenshtein@^1.0.7: resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== +data-uri-to-buffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b" + integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA== + date-fns-tz@^1.1.4: version "1.3.0" resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.3.0.tgz#6c83d4bdf20d54060cf176d96a3ca45043b36a84" @@ -3238,6 +3255,14 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.1.4.tgz#e8c6567f80ad7fc22fd302e7dcb72bafde9c1717" + integrity sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -3293,6 +3318,13 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + formik@^2.2.9: version "2.2.9" resolved "https://registry.yarnpkg.com/formik/-/formik-2.2.9.tgz#8594ba9c5e2e5cf1f42c5704128e119fc46232d0" @@ -3311,7 +3343,7 @@ fraction.js@^4.1.2: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== -fs-extra@10: +fs-extra@10, fs-extra@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8" integrity sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag== @@ -3680,6 +3712,13 @@ is-callable@^1.1.4, is-callable@^1.2.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== +is-ci@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" + integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== + dependencies: + ci-info "^3.2.0" + is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.0, is-core-module@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" @@ -3694,6 +3733,11 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -4361,6 +4405,20 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + +node-fetch@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.3.tgz#a03c9cc2044d21d1a021566bd52f080f333719a6" + integrity sha512-AXP18u4pidSZ1xYXRDPY/8jdv3RAozIt/WLNR/MBGZAz+xjtlr90RvCnsvHQRiXyWliZF/CpytExp32UU67/SA== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + node-releases@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" @@ -5342,6 +5400,11 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -6161,6 +6224,11 @@ vue@^3.2.23: "@vue/server-renderer" "3.2.31" "@vue/shared" "3.2.31" +web-streams-polyfill@^3.0.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965" + integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA== + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"