diff --git a/.gitignore b/.gitignore index 10aaae5..4f43501 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,6 @@ logs .history # Project +.private public/assets -TODO.md +package-lock.json diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..bf2e764 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +shamefully-hoist=true diff --git a/app/pages/blog.vue b/app/pages/blog.vue index 9fe125d..8f62b8b 100644 --- a/app/pages/blog.vue +++ b/app/pages/blog.vue @@ -1,9 +1,3 @@ - - - - - + diff --git a/app/pages/blog/[slug].vue b/app/pages/blog/[slug].vue index 9fe125d..cc2b31d 100644 --- a/app/pages/blog/[slug].vue +++ b/app/pages/blog/[slug].vue @@ -1,9 +1,92 @@ - - - + + + + + · + {{ new Date(post.date).toLocaleDateString('en', { year: 'numeric', month: 'short', day: 'numeric' }) }} + + + + + + + {{ author.name }} + + + + + + + + + + + + + + + + + + diff --git a/app/pages/blog/index.vue b/app/pages/blog/index.vue index 9fe125d..a392bd7 100644 --- a/app/pages/blog/index.vue +++ b/app/pages/blog/index.vue @@ -1,9 +1,51 @@ - - - + + + + + + + + + diff --git a/app/pages/index.vue b/app/pages/index.vue index dfd0d3d..daaa058 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -37,18 +37,7 @@ const batchTwo = computed(() => { return contributors.value.slice(mid) }) -const discordWidgetSrc = computed(() => { - const widgetId = page.value?.connect?.discordWidgetId - const color = useColorMode().value === 'dark' ? 'light' : 'dark' - - return widgetId ? `https://discord.com/widget?id=${widgetId}&theme=${color}` : undefined -}) - -const isClient = ref(false) - onMounted(async () => { - isClient.value = true - try { projects.value = dataStore.getProjects({ itemsToShow: page.value?.projects?.itemsToShow || 6, @@ -250,17 +239,35 @@ onMounted(async () => { - - + + + - + + + diff --git a/bun.lock b/bun.lock index 9fb5396..8b2cf64 100644 --- a/bun.lock +++ b/bun.lock @@ -4,7 +4,7 @@ "": { "name": "projectm-visualizer.org", "dependencies": { - "@iconify-json/lucide": "^1.2.47", + "@iconify-json/lucide": "^1.2.49", "@iconify-json/simple-icons": "^1.2.38", "@nuxt/content": "^3.5.1", "@nuxt/image": "^1.10.0", @@ -32,6 +32,7 @@ "eslint": "^9.28.0", "libsodium-wrappers": "^0.7.15", "lint-staged": "^16.1.1", + "node-gyp": "^11.2.0", "octokit": "^5.0.3", "semantic-release": "^24.2.5", "simple-git-hooks": "^2.13.0", @@ -266,7 +267,7 @@ "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], - "@iconify-json/lucide": ["@iconify-json/lucide@1.2.48", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-jDVqOHEF7XUwHJzx7fhwVXnx638lL89wOfmBob5UJofSGGIYV544zktmHr4CzKePslDBgl3MPKEpmFU/RfzppQ=="], + "@iconify-json/lucide": ["@iconify-json/lucide@1.2.49", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-Z6j8QKE7dcM3jDlstxTONpsw7GSJwzeVcre2xXqCmg+QvLoqmJJEugQ3PcGqpp6dtBIcBOtE6+LUeY5OlXmCuA=="], "@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.38", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-mvMeFQgVjoHanQE9Q7ihmriEXAorjLZW+crUgQspDjFpzWuQp2RZMTppl1MN6TQztMVTsNFgF6LDKsp+v1RYRg=="], @@ -336,6 +337,10 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@3.0.1", "", { "dependencies": { "@nodelib/fs.scandir": "4.0.1", "fastq": "^1.15.0" } }, "sha512-nIh/M6Kh3ZtOmlY00DaUYB4xeeV6F3/ts1l29iwl3/cfyY/OuCfUx+v08zgx8TKPTifXRcjjqVQ4KB2zOYSbyw=="], + "@npmcli/agent": ["@npmcli/agent@3.0.0", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q=="], + + "@npmcli/fs": ["@npmcli/fs@4.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q=="], + "@nuxt/cli": ["@nuxt/cli@3.25.1", "", { "dependencies": { "c12": "^3.0.3", "chokidar": "^4.0.3", "citty": "^0.1.6", "clipboardy": "^4.0.0", "consola": "^3.4.2", "defu": "^6.1.4", "fuse.js": "^7.1.0", "giget": "^2.0.0", "h3": "^1.15.3", "httpxy": "^0.1.7", "jiti": "^2.4.2", "listhen": "^1.9.0", "nypm": "^0.6.0", "ofetch": "^1.4.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.1.0", "scule": "^1.3.0", "semver": "^7.7.1", "std-env": "^3.9.0", "tinyexec": "^1.0.1", "ufo": "^1.6.1", "youch": "^4.1.0-beta.7" }, "bin": { "nuxi": "bin/nuxi.mjs", "nuxi-ng": "bin/nuxi.mjs", "nuxt": "bin/nuxi.mjs", "nuxt-cli": "bin/nuxi.mjs" } }, "sha512-7+Ut7IvAD4b5piikJFSgIqSPbHKFT5gq05JvCsEHRM0MPA5QR9QHkicklyMqSj0D/oEkDohen8qRgdxRie3oUA=="], "@nuxt/content": ["@nuxt/content@3.6.0", "", { "dependencies": { "@nuxt/kit": "^3.17.5", "@nuxtjs/mdc": "0.17.0", "@shikijs/langs": "^3.6.0", "@sqlite.org/sqlite-wasm": "3.50.1-build1", "@webcontainer/env": "^1.1.1", "c12": "^3.0.4", "chokidar": "^4.0.3", "consola": "^3.4.2", "db0": "^0.3.2", "defu": "^6.1.4", "destr": "^2.0.5", "git-url-parse": "^16.1.0", "jiti": "^2.4.2", "json-schema-to-typescript": "^15.0.4", "knitwork": "^1.2.0", "listhen": "^1.9.0", "mdast-util-to-hast": "^13.2.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.2", "micromark-util-character": "^2.1.1", "micromark-util-chunked": "^2.0.1", "micromark-util-resolve-all": "^2.0.1", "micromark-util-sanitize-uri": "^2.0.1", "micromatch": "^4.0.8", "minimark": "^0.2.0", "minimatch": "^10.0.1", "nuxt-component-meta": "^0.11.0", "nypm": "^0.6.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.1.0", "remark-mdc": "^3.6.0", "scule": "^1.3.0", "shiki": "^3.6.0", "slugify": "^1.6.6", "socket.io-client": "^4.8.1", "tar": "^7.4.3", "tinyglobby": "^0.2.14", "ufo": "^1.6.1", "unified": "^11.0.5", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "ws": "^8.18.2", "zod": "^3.25.58", "zod-to-json-schema": "^3.24.5" }, "peerDependencies": { "@electric-sql/pglite": "*", "@libsql/client": "*", "better-sqlite3": "11.10.0", "sqlite3": "*" }, "optionalPeers": ["@electric-sql/pglite", "@libsql/client", "better-sqlite3", "sqlite3"] }, "sha512-iqkcWf8M00fq7ZqF2qaHgcoKzRVOTMUp7dLkPCBrARmAKvV4kHdYyKjcf94kiNeKzIeqa73l3c1P8YMno/GgRQ=="], @@ -1002,6 +1007,8 @@ "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + "cacache": ["cacache@19.0.1", "", { "dependencies": { "@npmcli/fs": "^4.0.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^12.0.0", "tar": "^7.4.3", "unique-filename": "^4.0.0" } }, "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ=="], + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], @@ -1304,6 +1311,8 @@ "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="], + "end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="], "engine.io-client": ["engine.io-client@6.6.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", "ws": "~8.17.1", "xmlhttprequest-ssl": "~2.1.1" } }, "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w=="], @@ -1320,6 +1329,8 @@ "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], + "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="], + "error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="], "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], @@ -1398,6 +1409,8 @@ "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], + "exponential-backoff": ["exponential-backoff@3.1.2", "", {}, "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA=="], + "exsolve": ["exsolve@1.0.5", "", {}, "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg=="], "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], @@ -1476,6 +1489,8 @@ "fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="], + "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], @@ -1600,6 +1615,8 @@ "html-whitespace-sensitive-tag-names": ["html-whitespace-sensitive-tag-names@3.0.1", "", {}, "sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA=="], + "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], + "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], @@ -1612,6 +1629,8 @@ "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -1642,6 +1661,8 @@ "ioredis": ["ioredis@5.6.1", "", { "dependencies": { "@ioredis/commands": "^1.1.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA=="], + "ip-address": ["ip-address@9.0.5", "", { "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" } }, "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g=="], + "ipx": ["ipx@2.1.0", "", { "dependencies": { "@fastify/accept-negotiator": "^1.1.0", "citty": "^0.1.5", "consola": "^3.2.3", "defu": "^6.1.4", "destr": "^2.0.2", "etag": "^1.8.1", "h3": "^1.10.0", "image-meta": "^0.2.0", "listhen": "^1.5.6", "ofetch": "^1.3.3", "pathe": "^1.1.2", "sharp": "^0.32.6", "svgo": "^3.2.0", "ufo": "^1.3.2", "unstorage": "^1.10.1", "xss": "^1.0.14" }, "bin": { "ipx": "bin/ipx.mjs" } }, "sha512-AVnPGXJ8L41vjd11Z4akIF2yd14636Klxul3tBySxHA6PKfCOQPxBDkCFK5zcWh0z/keR6toh1eg8qzdBVUgdA=="], "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="], @@ -1710,7 +1731,7 @@ "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], "issue-parser": ["issue-parser@7.0.1", "", { "dependencies": { "lodash.capitalize": "^4.2.1", "lodash.escaperegexp": "^4.1.2", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.uniqby": "^4.7.0" } }, "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg=="], @@ -1724,6 +1745,8 @@ "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], + "jsbn": ["jsbn@1.1.0", "", {}, "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="], + "jsdoc-type-pratt-parser": ["jsdoc-type-pratt-parser@4.1.0", "", {}, "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg=="], "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], @@ -1880,6 +1903,8 @@ "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], + "make-fetch-happen": ["make-fetch-happen@14.0.3", "", { "dependencies": { "@npmcli/agent": "^3.0.0", "cacache": "^19.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^4.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^5.0.0", "promise-retry": "^2.0.1", "ssri": "^12.0.0" } }, "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ=="], + "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], "marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], @@ -2008,6 +2033,16 @@ "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], + + "minipass-fetch": ["minipass-fetch@4.0.1", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^3.0.1" }, "optionalDependencies": { "encoding": "^0.1.13" } }, "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ=="], + + "minipass-flush": ["minipass-flush@1.0.5", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw=="], + + "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], + + "minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="], + "minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="], "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], @@ -2046,6 +2081,8 @@ "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], "nerf-dart": ["nerf-dart@1.0.0", "", {}, "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g=="], @@ -2068,6 +2105,8 @@ "node-forge": ["node-forge@1.3.1", "", {}, "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="], + "node-gyp": ["node-gyp@11.2.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "make-fetch-happen": "^14.0.3", "nopt": "^8.0.0", "proc-log": "^5.0.0", "semver": "^7.3.5", "tar": "^7.4.3", "tinyglobby": "^0.2.12", "which": "^5.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-T0S1zqskVUSxcsSTkAsLc7xCycrRYmtDHadDinzocrThjyQCn5kMlEBSj6H4qDbgsIOSLmmlRIeb0lZXj+UArA=="], + "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], "node-mock-http": ["node-mock-http@1.0.0", "", {}, "sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ=="], @@ -2300,10 +2339,14 @@ "pretty-ms": ["pretty-ms@9.2.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg=="], + "proc-log": ["proc-log@5.0.0", "", {}, "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ=="], + "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="], + "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], @@ -2410,6 +2453,8 @@ "restructure": ["restructure@3.0.2", "", {}, "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw=="], + "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], @@ -2426,6 +2471,8 @@ "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "satori": ["satori@0.13.2", "", { "dependencies": { "@shuding/opentype.js": "1.4.0-beta.0", "css-background-parser": "^0.1.0", "css-box-shadow": "1.0.0-3", "css-gradient-parser": "^0.0.16", "css-to-react-native": "^3.0.0", "emoji-regex-xs": "^2.0.1", "escape-html": "^1.0.3", "linebreak": "^1.1.0", "parse-css-color": "^0.2.1", "postcss-value-parser": "^4.2.0", "yoga-wasm-web": "^0.3.3" } }, "sha512-BPoExgKlkZPY1j4I2vSovo9OJALOw5siU37cm1aNcq/XWCojpFM3FHXHxby9tQ2R5ajV2fRQgouWoonQ83z+Hg=="], "satori-html": ["satori-html@0.3.2", "", { "dependencies": { "ultrahtml": "^1.2.0" } }, "sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA=="], @@ -2500,12 +2547,18 @@ "slugify": ["slugify@1.6.6", "", {}, "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw=="], + "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + "smob": ["smob@1.5.0", "", {}, "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig=="], "socket.io-client": ["socket.io-client@4.8.1", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ=="], "socket.io-parser": ["socket.io-parser@4.2.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" } }, "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew=="], + "socks": ["socks@2.8.5", "", { "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" } }, "sha512-iF+tNDQla22geJdTyJB1wM/qrX9DMRwWrciEPwWLPRWAUEM8sQiyxgckLxWT1f7+9VabJS0jTGGr4QgBuvi6Ww=="], + + "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], + "source-map": ["source-map@0.7.4", "", {}, "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -2528,6 +2581,10 @@ "split2": ["split2@1.0.0", "", { "dependencies": { "through2": "~2.0.0" } }, "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg=="], + "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], + + "ssri": ["ssri@12.0.0", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ=="], + "stable-hash-x": ["stable-hash-x@0.1.1", "", {}, "sha512-l0x1D6vhnsNUGPFVDx45eif0y6eedVC8nm5uACTrVFJFtl2mLRW17aWtVyxFCpn5t94VUPkjU8vSLwIuwwqtJQ=="], "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], @@ -2702,6 +2759,10 @@ "unimport": ["unimport@5.0.1", "", { "dependencies": { "acorn": "^8.14.1", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", "local-pkg": "^1.1.1", "magic-string": "^0.30.17", "mlly": "^1.7.4", "pathe": "^2.0.3", "picomatch": "^4.0.2", "pkg-types": "^2.1.0", "scule": "^1.3.0", "strip-literal": "^3.0.0", "tinyglobby": "^0.2.13", "unplugin": "^2.3.2", "unplugin-utils": "^0.2.4" } }, "sha512-1YWzPj6wYhtwHE+9LxRlyqP4DiRrhGfJxdtH475im8ktyZXO3jHj/3PZ97zDdvkYoovFdi0K4SKl3a7l92v3sQ=="], + "unique-filename": ["unique-filename@4.0.0", "", { "dependencies": { "unique-slug": "^5.0.0" } }, "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ=="], + + "unique-slug": ["unique-slug@5.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg=="], + "unique-string": ["unique-string@3.0.0", "", { "dependencies": { "crypto-random-string": "^4.0.0" } }, "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ=="], "unist-builder": ["unist-builder@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-wmRFnH+BLpZnTKpc5L7O67Kac89s9HMrtELpnNaE6TAobq5DTZZs5YaTQfAZBA9bFPECx2uVAPO31c+GVug8mg=="], @@ -2824,7 +2885,7 @@ "wheel-gestures": ["wheel-gestures@2.2.48", "", {}, "sha512-f+Gy33Oa5Z14XY9679Zze+7VFhbsQfBFXodnU2x589l4kxGM9L5Y8zETTmcMR5pWOPQyRv4Z0lNax6xCO0NSlA=="], - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], "winston": ["winston@3.17.0", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.9.0" } }, "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw=="], @@ -2944,8 +3005,6 @@ "@nuxt/devtools/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], - "@nuxt/devtools/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], - "@nuxt/devtools-kit/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], "@nuxt/devtools-wizard/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], @@ -3060,6 +3119,8 @@ "crc32-stream/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "crypto-random-string/type-fest": ["type-fest@1.4.0", "", {}, "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA=="], "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], @@ -3146,6 +3207,12 @@ "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], "netlify/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], @@ -3744,8 +3811,6 @@ "@nuxt/devtools/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], - "@nuxt/devtools/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], - "@nuxt/fonts/css-tree/mdn-data": ["mdn-data@2.12.2", "", {}, "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA=="], "@nuxtjs/color-mode/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], @@ -3812,6 +3877,8 @@ "crc32-stream/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], "env-ci/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], @@ -3846,6 +3913,12 @@ "log-update/slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.0.0", "", { "dependencies": { "get-east-asian-width": "^1.0.0" } }, "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA=="], + "minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "minipass-sized/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], "nitropack/rollup-plugin-visualizer/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="], diff --git a/content.config.ts b/content.config.ts index 4babc56..f884dde 100644 --- a/content.config.ts +++ b/content.config.ts @@ -119,7 +119,8 @@ const collections = { reverse: z.boolean().optional(), orientation: z.enum(orientationEnum).optional(), icon: z.string().optional(), - discordWidgetId: z.string().optional() + image: createImageSchema().optional(), + button: createButtonSchema().optional() }).optional() }) }), @@ -155,8 +156,25 @@ const collections = { }), blog: defineCollection({ type: 'page', - source: '4.blog/**/*', + source: '4.blog.yml', schema: z.object({}) + }), + posts: defineCollection({ + type: 'page', + source: '4.blog/**/*', + schema: z.object({ + icon: z.string().optional(), + image: z.object({ src: z.string().nonempty().editor({ input: 'media' }) }), + authors: z.array( + z.object({ + name: z.string().nonempty(), + to: z.string().nonempty(), + avatar: z.object({ src: z.string().nonempty().editor({ input: 'media' }) }) + }) + ), + date: z.date(), + badge: z.object({ label: z.string().nonempty() }) + }) }) } diff --git a/content/0.index.yml b/content/0.index.yml index f4ce325..c812967 100644 --- a/content/0.index.yml +++ b/content/0.index.yml @@ -65,4 +65,11 @@ connect: icon: i-lucide-spline title: Connect With Us description: Have questions or feedback? We'd love to hear from you! - discordWidgetId: "737206408482914387" + image: + src: /assets/images/connect-cover.jpg + alt: Discord Community + button: + label: Join our Discord + icon: i-simple-icons-discord + to: https://discord.gg/mMrxAqaa3W + target: _blank diff --git a/content/2.download.yml b/content/2.download.yml index d1f74b7..7b3dfa8 100644 --- a/content/2.download.yml +++ b/content/2.download.yml @@ -12,7 +12,7 @@ download: title: Download description: Find the latest releases of our software and tools. items: - - icon: i-simple-icons:windows + - icon: i-simple-icons-windows title: Windows description: Download the latest version for Windows. items: @@ -22,7 +22,7 @@ download: - icon: i-lucide-download label: Library repoName: projectm - - icon: i-simple-icons:linux + - icon: i-simple-icons-linux title: Linux description: Download the latest version for Linux. items: @@ -32,7 +32,7 @@ download: - icon: i-lucide-download label: Library repoName: projectm - - icon: i-simple-icons:apple + - icon: i-simple-icons-apple title: macOS description: Download the latest version for macOS. items: diff --git a/content/4.blog.yml b/content/4.blog.yml new file mode 100644 index 0000000..5ab0122 --- /dev/null +++ b/content/4.blog.yml @@ -0,0 +1,4 @@ +icon: i-lucide-newspaper +title: Blog +description: Latest articles and updates +navigation.icon: i-lucide-newspaper diff --git a/content/4.blog/.navigation.yml b/content/4.blog/.navigation.yml deleted file mode 100644 index ab36760..0000000 --- a/content/4.blog/.navigation.yml +++ /dev/null @@ -1 +0,0 @@ -navigation.icon: i-lucide-pen diff --git a/content/4.blog/1.getting-started.md b/content/4.blog/1.getting-started.md new file mode 100644 index 0000000..c88695a --- /dev/null +++ b/content/4.blog/1.getting-started.md @@ -0,0 +1,60 @@ +--- +title: Our New Website +description: "We are excited to announce the launch of our new website, designed to enhance your experience and provide better access to our resources." +image: + src: /assets/images/blog/website-example.png +date: 2025-06-15 +badge: + label: New +--- + +## Welcome to Our New Website + +We’re thrilled to officially unveil our brand-new website—a central hub built with purpose, clarity, and accessibility in mind. Whether you're discovering our work for the first time or you've been with us from the beginning, this site was designed to provide a better experience for everyone. + +## Why a New Site? + +Over time, our projects and resources have grown significantly. From open-source tools and creative experiments to research and documentation, it became clear that we needed a unified platform to: + +- Organize our growing body of work +- Share updates and announcements more efficiently +- Offer easy access to downloads, source code, and documentation +- Support contributors and collaborators + +This new website brings all of that into one cohesive space. + +## What’s Inside + +Here’s a quick overview of what you’ll find: + +### 🚀 Projects + +A curated showcase of our active and past projects, with direct links to GitHub repositories, live demos, and changelogs. + +### 📚 Resources + +Useful guides, API references, and helpful links for developers, designers, and contributors. We aim to make it easier than ever to get started. + +### 📰 Blog + +You’re reading it! This blog is where we’ll post updates, behind-the-scenes insights, release notes, and other content to keep you informed. + +### 🤝 Get Involved + +We’ve made it easier to contribute—whether it’s reporting bugs, submitting pull requests, or helping with documentation. Our new site includes clear contribution guidelines and collaboration tips. + +## What’s Next? + +This launch is just the beginning. We have plans to roll out: + +- A searchable archive of past releases 🗂️ +- Deeper integration with our GitHub activity 📦 + +## Feedback Welcome + +We’d love to hear what you think! If you encounter any bugs or have suggestions for improvement, feel free to open an issue or contact us directly. + +Thank you for being part of this journey—we’re excited for what’s ahead! + +--- +Stay connected, stay curious. diff --git a/content/app.yml b/content/app.yml index 8b43ecf..d2900f0 100644 --- a/content/app.yml +++ b/content/app.yml @@ -25,7 +25,7 @@ links: - label: Blog icon: i-lucide-pencil to: /blog - disabled: true + disabled: false - label: GitHub icon: i-simple-icons-github to: https://github.com/projectm-visualizer diff --git a/nuxt.config.ts b/nuxt.config.ts index c8f816d..9a1e845 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -56,9 +56,50 @@ export default defineNuxtConfig({ braceStyle: '1tbs' } } - } + }, // image: { // domains: ['projectm-visualizer.org'] - // } + // }, + + icon: { + provider: 'none', + serverBundle: false, + clientBundle: { + scan: true, + icons: [ + 'lucide:menu', + 'lucide:chevron-down', + 'lucide:arrow-up-right', + 'lucide:arrow-right', + 'lucide:x', + 'lucide:hash', + 'lucide:sun', + 'lucide:moon', + 'lucide:book', + 'lucide:book-open', + 'lucide:book-text', + 'lucide:code-xml', + 'lucide:credit-card', + 'lucide:download', + 'lucide:equal-approximately', + 'lucide:folder-root', + 'lucide:git-fork', + 'lucide:newspaper', + 'lucide:pencil', + 'lucide:spline', + 'lucide:star', + 'simple-icons:apple', + 'simple-icons:codesandbox', + 'simple-icons:discord', + 'simple-icons:github', + 'simple-icons:linux', + 'simple-icons:mastodon', + 'simple-icons:stackblitz', + 'simple-icons:windows', + 'simple-icons:x', + 'simple-icons:youtube' + ] + } + } }) diff --git a/package.json b/package.json index 46fdc3d..4ea4ab0 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "push-secrets": "bun run ./scripts/push-secrets.ts" }, "dependencies": { - "@iconify-json/lucide": "^1.2.47", + "@iconify-json/lucide": "^1.2.49", "@iconify-json/simple-icons": "^1.2.38", "@nuxt/content": "^3.5.1", "@nuxt/image": "^1.10.0", @@ -52,6 +52,7 @@ "eslint": "^9.28.0", "libsodium-wrappers": "^0.7.15", "lint-staged": "^16.1.1", + "node-gyp": "^11.2.0", "octokit": "^5.0.3", "semantic-release": "^24.2.5", "simple-git-hooks": "^2.13.0", diff --git a/scripts/extract-icons.ts b/scripts/extract-icons.ts new file mode 100644 index 0000000..12b3f87 --- /dev/null +++ b/scripts/extract-icons.ts @@ -0,0 +1,129 @@ +// extract-icons.ts +// Extract icons from the project and add to nuxt.config.ts icons +// - arguments: +// - options: +// - "--dirs, -d" (comma-separated directories to scan, default: './app,./content,./shared') +// - "--write, -w" (write changes to nuxt.config.ts, default: false) + +import { join, extname } from 'node:path' +import { readdirSync, statSync } from 'node:fs' + +// ---------- Config & Constants ---------- + +// const NUXT_CONFIG_FILE = 'nuxt.config.ts' +// Match only icons that start with "i-" and follow the pattern: i-[namespace]-[icon-name] +const ICON_REGEX = /\bi-([\w]+-[\w-]+)\b/g +const VALID_EXTENSIONS = ['.yml', '.yaml', '.json', '.md', '.vue', '.ts'] +const DIRS = ['./app', './content', './shared'] + +// ---------- Arg Parser ---------- + +function getArgValue(args: string[], long: string, short: string, fallback?: string): string | undefined { + const index = args.indexOf(long) !== -1 ? args.indexOf(long) : args.indexOf(short) + return index !== -1 && args[index + 1] && !args[index + 1]?.startsWith('-') + ? args[index + 1] + : fallback +} + +function parseArgs() { + const args = Bun.argv.slice(2) + const dirs = getArgValue(args, '--dirs', '-d', DIRS.join(',')) + ?.split(',') + .map(dir => dir.trim()) + .filter(Boolean) || DIRS + const write = args.includes('--write') || args.includes('-w') + + if (dirs.length === 0) { + console.error('❌ No directories provided. Use --dirs or -d to specify directories.') + process.exit(1) + } + + return { + dirs, + write + } +} + +// ---------- Icon Extraction ---------- + +async function extractIconsFromFile(filePath: string, icons: Set) { + const content = await Bun.file(filePath).text() + let match: RegExpExecArray | null + while ((match = ICON_REGEX.exec(content))) { + if (match[1]) { + icons.add(match[1]) + } + } +} + +async function scanDirRecursively(dir: string, icons: Set) { + for (const entry of readdirSync(dir)) { + const fullPath = join(dir, entry) + const stats = statSync(fullPath) + + if (stats.isDirectory()) { + await scanDirRecursively(fullPath, icons) + } else if (stats.isFile() && VALID_EXTENSIONS.includes(extname(fullPath))) { + await extractIconsFromFile(fullPath, icons) + } + } +} + +// ---------- Nuxt Config Update ---------- + +// TODO: Implement this function to update the Nuxt config file with the extracted icons +// without overwriting existing icons. +// async function updateNuxtConfig(icons: string[]) { +// const nuxtConfigPath = join(process.cwd(), NUXT_CONFIG_FILE) +// const config = await Bun.file(nuxtConfigPath).text() + +// const mergedIcons = new Set([ +// ...(config.icon?.clientBundle?.icons || []), +// ...icons +// ]) + +// config.icon.clientBundle.icons = mergedIcons + +// await Bun.write(nuxtConfigPath, config) +// console.log(`✅ Updated ${NUXT_CONFIG_FILE} with ${icons.length} icons.`) +// } + +// ---------- Format ---------- + +function cleanIcons(icons: Set): string[] { + return Array.from(icons) + .map(icon => icon.trim()) + .filter(icon => icon.length > 0 && !icon.includes(' ')) + .map(icon => icon.replace(/_/g, '-')) + .map((icon) => { + const lastDash = icon.lastIndexOf('-') + return lastDash !== -1 + ? icon.slice(0, lastDash) + ':' + icon.slice(lastDash + 1) + : icon + }) + .filter((icon, index, self) => self.indexOf(icon) === index) + .sort((a, b) => a.localeCompare(b)) +} +// ---------- Main ---------- + +async function main() { + const { dirs, write } = parseArgs() + const icons = new Set() + + for (const dir of dirs) { + await scanDirRecursively(dir, icons) + } + + const sortedIcons = cleanIcons(icons) + console.log(`🔍 Found ${sortedIcons.length} styled icons:`) + console.log(sortedIcons.map(i => ` '${i}'`).join(',\n')) + + if (write) { + // await updateNuxtConfig(sortedIcons) + } +} + +main().catch((err) => { + console.error('❌ Unexpected error:', err) + process.exit(1) +}) diff --git a/scripts/generate-reports.ts b/scripts/generate-reports.ts index c9a1737..2ae7697 100644 --- a/scripts/generate-reports.ts +++ b/scripts/generate-reports.ts @@ -4,7 +4,8 @@ // - options: // - "--encrypt, -e" (encrypt data before saving to files) // - "--encryptionKey, -k" (encryption key for data encryption) -// - "--output, -o" (output directory for reports, default: 'public/data') +// - "--outputData, -d" (output directory for reports, default: 'public/data') +// - "--outputAvatars, -a" (output directory for avatars, default: 'public/images/avatars') // - "--owner, -o" (GitHub owner name, default: 'projectm-visualizer') // - "--token, -t" (GitHub token for authentication) @@ -13,7 +14,8 @@ import Bun from 'bun' // ---------- Config & Constants ---------- const OWNER = 'projectm-visualizer' -const OUTPUT_DIR = 'public/assets/data' +const OUTPUT_DATA_DIR = 'public/assets/data' +const OUTPUT_AVATAR_DIR = 'public/assets/images/avatars' const GITHUB_TOKEN = process.env.GITHUB_TOKEN const ENCRYPTION_KEY = process.env.NUXT_PUBLIC_ASSET_KEY @@ -30,7 +32,8 @@ function parseArgs() { const args = Bun.argv.slice(2) const encrypt = args.includes('--encrypt') || args.includes('-e') const encryptionKey = getArgValue(args, '--encryptionKey', '-k', ENCRYPTION_KEY) - const outputDir = getArgValue(args, '--output', '-o', OUTPUT_DIR) + const outputDataDir = getArgValue(args, '--outputData', '-d', OUTPUT_DATA_DIR) + const outputAvatarDir = getArgValue(args, '--outputAvatars', '-a', OUTPUT_AVATAR_DIR) const owner = getArgValue(args, '--owner', '-n', OWNER) const token = getArgValue(args, '--token', '-t', GITHUB_TOKEN) @@ -47,7 +50,8 @@ function parseArgs() { return { encrypt, encryptionKey: encryptionKey as string, - output: outputDir as string, + outputDataDir: outputDataDir as string, + outputAvatarDir: outputAvatarDir as string, owner: owner as string, token } @@ -108,6 +112,76 @@ async function getAllContributors(owner: string, repoNames: string[], headers: R return Array.from(allContributors.values()) } +// ---------- Avatar Downloader ---------- + +async function downloadOwnerAvatar(owner: string, headers: Record, dir: string): Promise<{ login: string, avatar_url: string } | null | null> { + const response = await fetch(`https://api.github.com/users/${owner}`, { headers }) + if (!response.ok) { + console.warn(`⚠️ Failed to fetch owner avatar for ${owner}: ${response.statusText}`) + return null + } + + const user: Contributor = await response.json() + const filePath = `${dir}/owner.jpg` + const metaPath = filePath.replace('public', '') + + try { + const exists = await Bun.file(filePath).exists() + if (!exists) { + const res = await fetch(user.avatar_url) + if (!res.ok) throw new Error(`Failed to fetch owner avatar for ${user.login}`) + const buffer = await res.arrayBuffer() + await Bun.write(filePath, new Uint8Array(buffer), { createPath: true }) + console.log(`🖼️ Saved owner avatar: ${user.login} → ${filePath}`) + } else { + console.log(`🖼️ Owner avatar already exists: ${user.login} → ${filePath}`) + } + + return { login: user.login, avatar_url: metaPath } + } catch (err) { + console.warn(`⚠️ Failed to download owner avatar for ${user.login}: ${(err as Error).message}`) + return null + } +} + +async function downloadAvatars(contributors: Contributor[], dir: string): Promise { + const updatedContributors: Contributor[] = [] + + for (const contributor of contributors) { + const filePath = `${dir}/${contributor.id}.jpg` + const metaPath = filePath.replace('public', '') + + try { + const exists = await Bun.file(filePath).exists() + if (exists) { + updatedContributors.push({ + ...contributor, + avatar_url: metaPath + }) + + console.log(`🖼️ Avatar already exists: ${contributor.login} → ${filePath}`) + + continue + } + + const res = await fetch(contributor.avatar_url) + if (!res.ok) throw new Error(`Failed to fetch avatar for ${contributor.login}`) + + const buffer = await res.arrayBuffer() + await Bun.write(filePath, new Uint8Array(buffer), { createPath: true }) + updatedContributors.push({ + ...contributor, + avatar_url: metaPath + }) + console.log(`🖼️ Saved avatar: ${contributor.login} → ${filePath}`) + } catch (err) { + console.warn(`⚠️ Failed to download avatar for ${contributor.login}: ${(err as Error).message}`) + } + } + + return updatedContributors +} + // ---------- Projects ---------- type Repository = { @@ -258,7 +332,7 @@ async function encryptContent(encryptionKey: string, content: string): Promise repo.name) + console.log(`🔍 Collecting contributors from all repos...`) + const contributors = await getAllContributors(owner, repoNames, headers) + const contributorsWithAvatars = await downloadAvatars(contributors, outputAvatarDir) + const contributorsOutput = encrypt + ? await encryptContent(encryptionKey, JSON.stringify(contributorsWithAvatars, null, 2)) + : JSON.stringify(contributorsWithAvatars, null, 2) + const contributorsFile = encrypt ? `${outputDataDir}/contributors.json.aes` : `${outputDataDir}/contributors.json` + await Bun.write(contributorsFile, contributorsOutput, { createPath: true }) + console.log(`✅ Saved ${contributors.length} unique contributors → ${contributorsFile}`) + + console.log(`🖼️ Downloading owner avatar for ${owner}...`) + const ownerInfo = await downloadOwnerAvatar(owner, headers, outputAvatarDir) console.log(`🏷️ Enriching ${repos.length} repositories with topics...`) const enrichedRepos = await enrichWithTopics(owner, repos, headers) console.log(`🏷️ Enriching ${enrichedRepos.length} repositories with latest releases...`) const enrichedReleases = await enrichWithReleases(owner, enrichedRepos, headers) + if (ownerInfo) { + for (const repo of enrichedRepos) { + repo.owner = { + login: ownerInfo.login, + avatar_url: ownerInfo.avatar_url + } + } + } const projectsOutput = encrypt ? await encryptContent(encryptionKey, JSON.stringify(enrichedReleases, null, 2)) : JSON.stringify(enrichedRepos, null, 2) - const projectsFile = encrypt ? `${output}/projects.json.aes` : `${output}/projects.json` + const projectsFile = encrypt ? `${outputDataDir}/projects.json.aes` : `${outputDataDir}/projects.json` await Bun.write(projectsFile, projectsOutput, { createPath: true }) console.log(`✅ Saved ${enrichedRepos.length} repositories → ${projectsFile}`) - console.log(`🔍 Collecting contributors from all repos...`) - const contributors = await getAllContributors(owner, repoNames, headers) - const contributorsOutput = encrypt - ? await encryptContent(encryptionKey, JSON.stringify(contributors, null, 2)) - : JSON.stringify(contributors, null, 2) - const contributorsFile = encrypt ? `${output}/contributors.json.aes` : `${output}/contributors.json` - await Bun.write(contributorsFile, contributorsOutput, { createPath: true }) - console.log(`✅ Saved ${contributors.length} unique contributors → ${contributorsFile}`) - console.log(`🎉 Report generation completed successfully.`) }