diff --git a/.github/workflows/stage-build.yml b/.github/workflows/stage-build.yml index 5169210175ae..e46f50d29432 100644 --- a/.github/workflows/stage-build.yml +++ b/.github/workflows/stage-build.yml @@ -151,6 +151,13 @@ jobs: mv mdn/translated-content-de/files/de mdn/translated-content/files/ rm -rf mdn/translated-content-de + - name: Clean and commit de + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} + working-directory: mdn/translated-content + run: | + git add files/de + git -c user.name='MDN' -c user.email='mdn-dev@mozilla.com' commit -m 'de' + - uses: actions/checkout@v4 if: ${{ ! vars.SKIP_BUILD }} with: @@ -168,7 +175,8 @@ jobs: if: ${{ ! vars.SKIP_BUILD }} run: yarn --frozen-lockfile env: - # https://github.com/microsoft/vscode-ripgrep#github-api-limit-note + # Use a GITHUB_TOKEN to bypass rate limiting for ripgrep and rari. + # See https://github.com/microsoft/vscode-ripgrep#github-api-limit-note GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Install Python @@ -214,6 +222,13 @@ jobs: CURRICULUM_ROOT: ${{ github.workspace }}/mdn/curriculum BASE_URL: "https://developer.allizom.org" + # rari + BUILD_OUT_ROOT: "client/build" + GENERIC_CONTENT_ROOT: "copy" + LIVE_SAMPLES_BASE_URL: https://live.mdnyalp.dev + INTERACTIVE_EXAMPLES_BASE_URL: https://interactive-examples.mdn.allizom.net + ADDITIONAL_LOCALES_FOR_GENERICS_AND_SPAS: de + # The default for this environment variable is geared for writers # (aka. local development). Usually defaults are supposed to be for # secure production but this is an exception and default @@ -290,31 +305,14 @@ jobs: echo "BLOG_ROOT=$BLOG_ROOT" # Build the ServiceWorker first yarn build:sw - yarn build:prepare - - yarn tool sync-translated-content es fr ja ko pt-br ru zh-cn zh-tw - - # Build using one process per locale. - # Note: We have 4 cores, but 9 processes is a reasonable number. - for locale in en-us de es fr ja ko pt-br ru zh-cn zh-tw; do - yarn build:docs --locale $locale 2>&1 | sed "s/^/[$locale] /" & - pids+=($!) - done - - for pid in "${pids[@]}"; do - wait $pid - done - - du -sh client/build - - # Build the blog - yarn build:blog + yarn build:client + yarn build:ssr + yarn tool build-robots-txt - # Build the curriculum - yarn build:curriculum + yarn rari content sync-translated-content + yarn rari git-history - # Generate sitemap index file - yarn build --sitemap-index + yarn rari build --issues client/build/issues.json --templ-stats # SSR all pages yarn render:html diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 95d986565212..21fe49f08a9f 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -72,6 +72,26 @@ jobs: # See matching warning for mdn/content checkout step fetch-depth: 0 + - name: Checkout (translated-content-de) + uses: actions/checkout@v4 + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} + with: + repository: mdn/translated-content-de + path: mdn/translated-content-de + + - name: Move de into translated-content + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} + run: | + mv mdn/translated-content-de/files/de mdn/translated-content/files/ + rm -rf mdn/translated-content-de + + - name: Clean and commit de + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} + working-directory: mdn/translated-content + run: | + git add files/de + git -c user.name='MDN' -c user.email='mdn-dev@mozilla.com' commit -m 'de' + - uses: actions/checkout@v4 if: ${{ ! vars.SKIP_BUILD }} with: @@ -89,7 +109,8 @@ jobs: if: ${{ ! vars.SKIP_BUILD }} run: yarn --frozen-lockfile env: - # https://github.com/microsoft/vscode-ripgrep#github-api-limit-note + # Use a GITHUB_TOKEN to bypass rate limiting for ripgrep and rari. + # See https://github.com/microsoft/vscode-ripgrep#github-api-limit-note GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Print information about build @@ -111,6 +132,13 @@ jobs: CURRICULUM_ROOT: ${{ github.workspace }}/mdn/curriculum BASE_URL: "https://test.developer.allizom.org" + # rari + BUILD_OUT_ROOT: "client/build" + GENERIC_CONTENT_ROOT: "copy" + LIVE_SAMPLES_BASE_URL: https://live.test.mdnyalp.dev + INTERACTIVE_EXAMPLES_BASE_URL: https://interactive-examples.mdn.allizom.net + ADDITIONAL_LOCALES_FOR_GENERICS_AND_SPAS: de + # The default for this environment variable is geared for writers # (aka. local development). Usually defaults are supposed to be for # secure production but this is an exception and default @@ -155,7 +183,7 @@ jobs: REACT_APP_PLACEMENT_ENABLED: true # Playground - REACT_APP_PLAYGROUND_BASE_HOST: play.test.mdn.allizom.net + REACT_APP_PLAYGROUND_BASE_HOST: test.mdnyalp.dev # Observatory REACT_APP_OBSERVATORY_API_URL: https://observatory-api.mdn.allizom.net @@ -168,31 +196,14 @@ jobs: echo "BLOG_ROOT=$BLOG_ROOT" # Build the ServiceWorker first yarn build:sw - yarn build:prepare - - #yarn tool sync-translated-content - - # Build using one process per locale. - # Note: We have 4 cores, but 9 processes is a reasonable number. - for locale in en-us fr; do - yarn build:docs --locale $locale 2>&1 | sed "s/^/[$locale] /" & - pids+=($!) - done - - for pid in "${pids[@]}"; do - wait $pid - done - - du -sh client/build - - # Build the blog - yarn build:blog + yarn build:client + yarn build:ssr + yarn tool build-robots-txt - # Build the curriculum - yarn build:curriculum + yarn rari content sync-translated-content + yarn rari git-history - # Generate sitemap index file - yarn build --sitemap-index + yarn rari build --issues client/build/issues.json --templ-stats # SSR all pages yarn render:html @@ -241,6 +252,7 @@ jobs: run: | npm ci npm run build-redirects + npm run build-canonicals - name: Deploy Function if: ${{ ! vars.SKIP_FUNCTION }} diff --git a/Procfile.rari b/Procfile.rari new file mode 100644 index 000000000000..a39285dfe174 --- /dev/null +++ b/Procfile.rari @@ -0,0 +1,2 @@ +server: yarn start:rari-server +web: yarn start:client diff --git a/README.md b/README.md index fab120f41c62..248cb0c20aaa 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,14 @@ this, you can pick any unused port (e.g., 6000) and run the following: echo SERVER_PORT=6000 >> .env +### Problems running with rari on Windows + +Download and install: + +Microsoft Visual C++ Redistributable for Visual Studio 2019 ( +[x86](https://aka.ms/vs/16/release/VC_redist.x86.exe), +[ARM64](https://aka.ms/vs/16/release/VC_redist.arm64.exe) ) + ### Yarn install errors If you get errors while installing dependencies via yarn on a Mac, you may need diff --git a/client/src/document/toolbar/flaws.tsx b/client/src/document/toolbar/flaws.tsx index 191760550773..ea5698f7eb75 100644 --- a/client/src/document/toolbar/flaws.tsx +++ b/client/src/document/toolbar/flaws.tsx @@ -331,7 +331,7 @@ function Flaws({ /> ); default: - throw new Error(`Unknown flaw check '${flaw.name}'`); + return ; } })} @@ -531,6 +531,20 @@ function BrokenLinks({ ); } +function Unknown({ flaws }: { flaws: GenericFlaw[] }) { + return ( +
+

{humanizeFlawName("unknown")}

+ +
+ ); +} function BadBCDQueries({ flaws }: { flaws: BadBCDQueryFlaw[] }) { return (
@@ -692,7 +706,9 @@ function Macros({

{humanizeFlawName("macros")}

{flaws.map((flaw) => { - const inPrerequisiteMacro = !flaw.filepath.includes(sourceFilePath); + const inPrerequisiteMacro = flaw.filepath + ? !flaw.filepath.includes(sourceFilePath) + : false; return (
{ popularities.set(url, value as number); } diff --git a/copy/community/community.md b/copy/community/community.md index 1f851e99e660..a0f35e196761 100644 --- a/copy/community/community.md +++ b/copy/community/community.md @@ -1,3 +1,7 @@ +--- +title: Contribute to MDN +--- + # MDN Community Where web enthusiasts learn, collaborate, and create diff --git a/copy/config.json b/copy/config.json new file mode 100644 index 000000000000..6438b35bbbc1 --- /dev/null +++ b/copy/config.json @@ -0,0 +1,29 @@ +{ + "pages": { + "community": { + "titleSuffix": "Contribute to MDN" + }, + "plus": { + "slugPrefix": "plus/docs", + "titleSuffix": "MDN Plus" + }, + "observatory": { + "slugPrefix": "observatory/docs", + "titleSuffix": "HTTP Observatory" + } + }, + "spas": { + "about": { + "slug": "about", + "pageTitle": "About MDN" + }, + "advertising": { + "slug": "advertising", + "pageTitle": "Advertise with us" + }, + "plus": { + "slug": "plus", + "pageTitle": "MDN Plus" + } + } +} diff --git a/deployer/src/deployer/search/__init__.py b/deployer/src/deployer/search/__init__.py index dfdb286dbe7b..972b7f7d2184 100644 --- a/deployer/src/deployer/search/__init__.py +++ b/deployer/src/deployer/search/__init__.py @@ -248,7 +248,7 @@ def to_search(file, _index=None): ) ), popularity=doc["popularity"], - summary=doc["summary"], + summary=doc.get("summary", ""), # Note! We're always lowercasing the 'slug'. This way we can search on it, # still as a `keyword` index, but filtering by prefix. # E.g. in kuma; ?slug_prefix=weB/Css diff --git a/libs/env/index.d.ts b/libs/env/index.d.ts index fec939592c93..f57b38a5ed1b 100644 --- a/libs/env/index.d.ts +++ b/libs/env/index.d.ts @@ -1,5 +1,6 @@ export const BUILD_OUT_ROOT: string; export const DEFAULT_FLAW_LEVELS: string; +export const RARI: boolean; export const BASE_URL: string; export const FILES: string; export const FOLDERSEARCH: string; @@ -27,6 +28,7 @@ export const STATIC_ROOT: string; export const PROXY_HOSTNAME: string; export const CONTENT_HOSTNAME: string; export const FAKE_V1_API: boolean; +export const EXTERNAL_DEV_SERVER: sting; export const SENTRY_DSN_BUILD: string; export const OPENAI_KEY: string; export const PG_URI: string; diff --git a/libs/env/index.js b/libs/env/index.js index 253b341d7999..7f9e65be1a13 100644 --- a/libs/env/index.js +++ b/libs/env/index.js @@ -28,6 +28,7 @@ dotenv.config({ // build // ----- +export const RARI = Boolean(parse(process.env.RARI || "false")); export const BASE_URL = process.env.BASE_URL || "https://developer.mozilla.org"; export const BUILD_OUT_ROOT = @@ -178,6 +179,8 @@ export const PROXY_HOSTNAME = export const CONTENT_HOSTNAME = process.env.SERVER_CONTENT_HOST; export const FAKE_V1_API = parse(process.env.SERVER_FAKE_V1_API || false); +export const EXTERNAL_DEV_SERVER = + process.env.EXTERNAL_DEV_SERVER || "http://localhost:8083"; // ---- // tool diff --git a/libs/types/document.ts b/libs/types/document.ts index 1ccedcc18412..bec2c34d4856 100644 --- a/libs/types/document.ts +++ b/libs/types/document.ts @@ -110,6 +110,7 @@ export type Flaws = Partial<{ heading_links: HeadingLinksFlaw[]; translation_differences: TranslationDifferenceFlaw[]; unsafe_html: UnsafeHTMLFlaw[]; + unknown: GenericFlaw[]; }>; export type Translation = { diff --git a/package.json b/package.json index 4e64897b3939..7d278fd304aa 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "author": "MDN Web Docs", "type": "module", "bin": { + "rari-server": "server/cli.js", "yari-build": "build/cli.js", "yari-build-blog": "build/build-blog.js", "yari-filecheck": "filecheck/cli.js", @@ -14,36 +15,39 @@ "yari-tool": "tool/cli.js" }, "scripts": { - "ai-help-macros": "cross-env NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node scripts/ai-help-macros.ts", + "ai-help-macros": "cross-env NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node scripts/ai-help-macros.ts", "analyze": "(test -f client/build/stats.json || cross-env ANALYZE_BUNDLE=true yarn build:client) && webpack-bundle-analyzer client/build/stats.json", - "build": "cross-env NODE_ENV=production NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node build/cli.ts", - "build:blog": "cross-env NODE_ENV=production NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node build/build-blog.ts", + "build": "cross-env NODE_ENV=production NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node build/cli.ts", + "build:blog": "cross-env NODE_ENV=production NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node build/build-blog.ts", "build:client": "cd client && cross-env NODE_ENV=production BABEL_ENV=production node scripts/build.js", - "build:curriculum": "cross-env NODE_ENV=production NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node build/build-curriculum.ts", + "build:curriculum": "cross-env NODE_ENV=production NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node build/build-curriculum.ts", "build:dist": "tsc -p tsconfig.dist.json", - "build:docs": "cross-env NODE_ENV=production NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node build/cli.ts -n", + "build:docs": "cross-env NODE_ENV=production NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node build/cli.ts -n", "build:glean": "cd client && cross-env VIRTUAL_ENV=venv glean translate src/telemetry/metrics.yaml src/telemetry/pings.yaml -f typescript -o src/telemetry/generated", "build:prepare": "yarn build:client && yarn build:ssr && yarn tool popularities && yarn tool spas && yarn tool gather-git-history && yarn tool build-robots-txt", - "build:ssr": "cross-env NODE_ENV=production NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node ssr/prepare.ts && webpack --mode=production --config=ssr/webpack.config.js", + "build:ssr": "cross-env NODE_ENV=production NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node ssr/prepare.ts && webpack --mode=production --config=ssr/webpack.config.js", "build:sw": "cd client/pwa && yarn && yarn build:prod", "build:sw-dev": "cd client/pwa && yarn && yarn build", "check:tsc": "find . -name 'tsconfig.json' ! -wholename '**/node_modules/**' -print0 | xargs -n1 -P 2 -0 sh -c 'cd `dirname $0` && echo \"🔄 $(pwd)\" && npx tsc --noEmit && echo \"☑️ $(pwd)\" || exit 255'", "dev": "yarn build:prepare && nf -j Procfile.dev start", "eslint": "eslint .", - "filecheck": "cross-env NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node filecheck/cli.ts", + "filecheck": "cross-env NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node filecheck/cli.ts", "install:all": "find . -mindepth 2 -name 'yarn.lock' ! -wholename '**/node_modules/**' -print0 | xargs -n1 -0 sh -cx 'yarn --cwd $(dirname $0) install'", "install:all:npm": "find . -mindepth 2 -name 'package-lock.json' ! -wholename '**/node_modules/**' -print0 | xargs -n1 -0 sh -cx 'npm --prefix $(dirname $0) install'", "jest": "node --experimental-vm-modules --expose-gc ./node_modules/.bin/jest --logHeapUsage", - "m2h": "cross-env NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node markdown/m2h/cli.ts", + "m2h": "cross-env NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node markdown/m2h/cli.ts", "prepack": "yarn render:html && yarn build:dist", "prepare": "(husky || true) && yarn install:all && yarn install:all:npm", "prettier-check": "prettier --check .", "prettier-format": "prettier --write .", - "render:html": "cross-env NODE_ENV=production NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node build/ssr-cli.ts", + "render:html": "cross-env NODE_ENV=production NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node build/ssr-cli.ts", "start": "(test -f client/build/asset-manifest.json || yarn build:client) && (test -f ssr/dist/main.js || yarn build:ssr) && (test -f popularities.json || yarn tool popularities) && (test -d client/build/en-us/_spas || yarn tool spas) && (test -d client/build/en-us/_spas/404.html || yarn render:html -s) && nf -j Procfile.start start", "start:client": "cd client && cross-env NODE_ENV=development BABEL_ENV=development PORT=3000 node scripts/start.js", + "start:rari": "(test -f client/build/asset-manifest.json || yarn build:client) && (test -f ssr/dist/main.js || yarn build:ssr) && cross-env RARI=true nf -j Procfile.rari start", + "start:rari-external": "(test -f client/build/asset-manifest.json || yarn build:client) && (test -f ssr/dist/main.js || yarn build:ssr) && cross-env RARI=true nf -j Procfile.start start", + "start:rari-server": "cross-env NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node server/cli.ts", "start:server": "node-dev --experimental-loader ts-node/esm server/index.ts", - "start:static-server": "cross-env NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node server/static.ts", + "start:static-server": "cross-env NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node server/static.ts", "stylelint": "stylelint \"**/*.scss\"", "test": "yarn prettier-check && yarn test:client && yarn test:kumascript && yarn test:libs && yarn test:content && yarn test:testing", "test:client": "cd client && tsc --noEmit && cross-env NODE_ENV=test BABEL_ENV=test node scripts/test.js --env=jsdom", @@ -54,7 +58,7 @@ "test:libs": "yarn jest --rootDir libs --env=node", "test:prepare": "yarn build:prepare && yarn build:docs && yarn render:html && yarn start:static-server", "test:testing": "yarn jest --rootDir testing", - "tool": "cross-env NODE_OPTIONS='--no-warnings=ExperimentalWarning --loader ts-node/esm' node ./tool/cli.ts", + "tool": "cross-env NODE_OPTIONS=\"--no-warnings=ExperimentalWarning --loader ts-node/esm\" node ./tool/cli.ts", "watch:ssr": "webpack --mode=production --watch --config=ssr/webpack.config.js" }, "resolutions": { @@ -74,6 +78,7 @@ "@lit/react": "^1.0.6", "@mdn/bcd-utils-api": "^0.0.7", "@mdn/browser-compat-data": "^5.6.19", + "@mdn/rari": "^0.0.25", "@mozilla/glean": "5.0.3", "@sentry/node": "^8.41.0", "@stripe/stripe-js": "^4.10.0", @@ -88,6 +93,7 @@ "codemirror": "^6.0.1", "compression": "^1.7.5", "compute-baseline": "^0.1.1", + "concurrently": "^9.0.1", "cookie": "^0.7.2", "cookie-parser": "^1.4.7", "css-tree": "^2.3.1", diff --git a/server/cli.ts b/server/cli.ts new file mode 100644 index 000000000000..799e0b04d1ab --- /dev/null +++ b/server/cli.ts @@ -0,0 +1,42 @@ +#!/usr/bin/env node +import { concurrently } from "concurrently"; +import { rariBin } from "@mdn/rari"; +import { filename } from "./filename.js"; + +const { commands, result } = concurrently( + [ + { + command: `node ${filename}`, + name: "server", + env: { + RARI: true, + }, + prefixColor: "red", + }, + { + command: `${rariBin} serve -vv`, + name: "rari", + prefixColor: "blue", + }, + ], + { + killOthers: ["failure", "success"], + restartTries: 0, + handleInput: true, + inputStream: process.stdin, + } +); + +const stop = new Promise((resolve, reject) => { + process.on("SIGINT", () => { + commands.forEach((cmd) => cmd.kill()); // Terminate all concurrently-run processes + reject(); + }); + result.finally(() => resolve(null)); +}); +try { + await stop; + console.log("All tasks completed successfully."); +} catch { + console.log("Killed ☠️"); +} diff --git a/server/filename.ts b/server/filename.ts new file mode 100644 index 000000000000..abc56988399e --- /dev/null +++ b/server/filename.ts @@ -0,0 +1,2 @@ +import { fileURLToPath } from "node:url"; +export const filename = fileURLToPath(import.meta.resolve("./index.js")); diff --git a/server/index.ts b/server/index.ts index f2e1535b9e2c..f9d94e6282a3 100644 --- a/server/index.ts +++ b/server/index.ts @@ -33,6 +33,8 @@ import { CONTENT_TRANSLATED_ROOT, BLOG_ROOT, CURRICULUM_ROOT, + EXTERNAL_DEV_SERVER, + RARI, } from "../libs/env/index.js"; import { PLAYGROUND_UNSAFE_CSP_VALUE } from "../libs/play/index.js"; @@ -55,28 +57,43 @@ import { import { findCurriculumPageBySlug } from "../build/curriculum.js"; import { handleRunner } from "../libs/play/index.js"; +async function fetch_from_rari(path: string) { + const external_url = `${EXTERNAL_DEV_SERVER}${path}`; + console.log(`using ${external_url}`); + // eslint-disable-next-line n/no-unsupported-features/node-builtins + return await (await fetch(external_url)).json(); +} + async function buildDocumentFromURL(url: string) { try { console.time(`buildDocumentFromURL(${url})`); - const document = Document.findByURL(url); - if (!document) { - return null; - } - const documentOptions = {}; - if (CONTENT_TRANSLATED_ROOT) { - // When you're running the dev server and build documents - // every time a URL is requested, you won't have had the chance to do - // the phase that happens when you do a regular `yarn build`. - document.translations = findTranslations( - document.metadata.slug, - document.metadata.locale - ); + let built; + if (!RARI) { + const document = Document.findByURL(url); + if (!document) { + return null; + } + const documentOptions = {}; + if (CONTENT_TRANSLATED_ROOT) { + // When you're running the dev server and build documents + // every time a URL is requested, you won't have had the chance to do + // the phase that happens when you do a regular `yarn build`. + document.translations = findTranslations( + document.metadata.slug, + document.metadata.locale + ); + } + built = await buildDocument(document, documentOptions); + if (built) { + return { doc: built?.doc, url }; + } + } else { + built = await fetch_from_rari(url); + if (built) { + return built; + } } - const built = await buildDocument(document, documentOptions); - - if (built) { - return { doc: built?.doc, url }; - } else if ( + if ( url.split("/")[1] && url.split("/")[1].toLowerCase() !== DEFAULT_LOCALE.toLowerCase() && !CONTENT_TRANSLATED_ROOT @@ -97,19 +114,29 @@ async function buildDocumentFromURL(url: string) { } } -function redirectOr404(res: express.Response, url, suffix = "") { +async function redirectOr404(res: express.Response, url, suffix = "") { const redirectURL = Redirect.resolve(url); if (redirectURL !== url) { // This was and is broken for redirects with anchors... return res.redirect(301, redirectURL + suffix); } - return send404(res); + return await send404(res); } -function send404(res: express.Response) { - return res - .status(404) - .sendFile(path.join(STATIC_ROOT, "en-us", "_spas", "404.html")); +async function send404(res: express.Response) { + if (!RARI) { + return res + .status(404) + .sendFile(path.join(STATIC_ROOT, "en-us", "_spas", "404.html")); + } else { + try { + const index = await fetch_from_rari("/en-US/404"); + res.header("Content-Security-Policy", CSP_VALUE); + return res.send(renderHTML(index)); + } catch (error) { + return res.status(500).json(JSON.stringify(error.toString())); + } + } } const app = express(); @@ -250,29 +277,55 @@ app.get("/_open", (req, res) => { res.status(200).send(`Tried to open ${spec} in ${process.env.EDITOR}`); }); -app.use("/:locale/search-index.json", searchIndexRoute); +if (!RARI) { + app.use("/:locale/search-index.json", searchIndexRoute); +} else { + app.use("/:locale/search-index.json", async (req, res) => { + const { locale } = req.params; + try { + const json = await fetch_from_rari(`/${locale}/search-index.json`); + res.setHeader("Access-Control-Allow-Origin", "*"); + return res.json(json); + } catch (error) { + return res.status(500).json(JSON.stringify(error.toString())); + } + }); +} app.get("/_flaws", flawsRoute); app.use("/_translations", translationsRouter); app.get("/*/contributors.txt", async (req, res) => { - const url = req.path.replace(/\/contributors\.txt$/, ""); - const document = Document.findByURL(url); - res.setHeader("content-type", "text/plain"); - if (!document) { - return res.status(404).send(`Document not found by URL (${url})`); - } - try { - const { doc: builtDocument } = await buildDocument(document); - res.send( - renderContributorsTxt( - document.metadata.contributors, - builtDocument.source.github_url.replace("/blob/", "/commits/") - ) - ); - } catch (error) { - return res.status(500).json(JSON.stringify(error.toString())); + if (!RARI) { + const url = req.path.replace(/\/contributors\.txt$/, ""); + const document = Document.findByURL(url); + res.setHeader("content-type", "text/plain"); + if (!document) { + return res.status(404).send(`Document not found by URL (${url})`); + } + try { + const { doc: builtDocument } = await buildDocument(document); + res.send( + renderContributorsTxt( + document.metadata.contributors, + builtDocument.source.github_url.replace("/blob/", "/commits/") + ) + ); + } catch (error) { + return res.status(500).json(JSON.stringify(error.toString())); + } + } else { + try { + const external_url = `${EXTERNAL_DEV_SERVER}${req.path}`; + console.log(`contributors.txt: using ${external_url}`); + // eslint-disable-next-line n/no-unsupported-features/node-builtins + const text = await (await fetch(external_url)).text(); + res.setHeader("content-type", "text/plain"); + return res.send(text); + } catch (error) { + return res.status(500).json(JSON.stringify(error.toString())); + } } }); @@ -287,8 +340,17 @@ if (CURRICULUM_ROOT) { "/:locale/curriculum/index.json", ], async (req, res) => { - const { slug = "" } = req.params; - const data = await findCurriculumPageBySlug(slug); + let data; + if (!RARI) { + const { slug = "" } = req.params; + data = await findCurriculumPageBySlug(slug); + } else { + try { + data = await fetch_from_rari(req.path); + } catch (error) { + return res.status(500).json(JSON.stringify(error.toString())); + } + } if (!data) { return res.status(404).send("Nothing here 🤷‍♂️"); } @@ -296,19 +358,28 @@ if (CURRICULUM_ROOT) { } ); } else { - app.get("/[^/]+/curriculum/*", (_, res) => { + app.get("/[^/]+/curriculum/*", async (_, res) => { console.warn("'CURRICULUM_ROOT' not set in .env file"); - return send404(res); + return await send404(res); }); } if (BLOG_ROOT) { - app.get("/:locale/blog/index.json", async (_, res) => { - const posts = await allPostFrontmatter( - { includeUnpublished: true }, - MEMOIZE_INVALIDATE - ); - return res.json({ hyData: { posts } }); + app.get("/:locale/blog/index.json", async (req, res) => { + if (!RARI) { + const posts = await allPostFrontmatter( + { includeUnpublished: true }, + MEMOIZE_INVALIDATE + ); + return res.json({ hyData: { posts } }); + } else { + try { + const index = await fetch_from_rari(req.path); + return res.json(index); + } catch (error) { + return res.status(500).json(JSON.stringify(error.toString())); + } + } }); app.get("/:locale/blog/author/:slug/:asset", async (req, res) => { const { slug, asset } = req.params; @@ -324,12 +395,21 @@ if (BLOG_ROOT) { ).pipe(res); }); app.get("/:locale/blog/:slug/index.json", async (req, res) => { - const { slug } = req.params; - const data = await findPostBySlug(slug); - if (!data) { - return res.status(404).send("Nothing here 🤷‍♂️"); + if (!RARI) { + const { slug } = req.params; + const data = await findPostBySlug(slug); + if (!data) { + return res.status(404).send("Nothing here 🤷‍♂️"); + } + return res.json(data); + } else { + try { + const index = await fetch_from_rari(req.path); + return res.json(index); + } catch (error) { + return res.status(500).json(JSON.stringify(error.toString())); + } } - return res.json(data); }); app.get("/:locale/blog/:slug/:asset", async (req, res) => { const { slug, asset } = req.params; @@ -343,9 +423,9 @@ if (BLOG_ROOT) { return res.status(404).send("Nothing here 🤷‍♂️"); }); } else { - app.get("/[^/]+/blog/*", (_, res) => { + app.get("/[^/]+/blog/*", async (_, res) => { console.warn("'BLOG_ROOT' not set in .env file"); - return send404(res); + return await send404(res); }); } @@ -370,7 +450,7 @@ if (contentProxy) { try { const doc = await buildDocumentFromURL(url); if (!doc) { - return redirectOr404(res, url, "/index.json"); + return await redirectOr404(res, url, "/index.json"); } return res.json(doc); } catch (error) { @@ -381,7 +461,7 @@ if (contentProxy) { const url = decodeURI(req.path.replace(/\/metadata.json$/, "")); const doc = await buildDocumentFromURL(url); if (!doc?.doc) { - return redirectOr404(res, url, "/metadata.json"); + return await redirectOr404(res, url, "/metadata.json"); } const docString = JSON.stringify(doc); @@ -410,7 +490,7 @@ if (contentProxy) { try { const doc = await buildDocumentFromURL(url); if (!doc) { - return redirectOr404(res, url); + return await redirectOr404(res, url); } res.header("Content-Security-Policy", CSP_VALUE); return res.send(renderHTML(doc)); @@ -420,9 +500,35 @@ if (contentProxy) { }); } +if (RARI) { + app.get( + [ + "/en-US/about", + "/en-US/about/index.json", + "/en-US/community", + "/en-US/community/index.json", + "/en-US/plus/docs/*", + "/en-US/observatory/docs/*", + "/:locale/", + ], + async (req, res) => { + try { + const index = await fetch_from_rari(req.path); + if (req.path.endsWith(".json")) { + return res.json(index); + } + res.header("Content-Security-Policy", CSP_VALUE); + return res.send(renderHTML(index)); + } catch (error) { + return res.status(500).json(JSON.stringify(error.toString())); + } + } + ); +} + app.use(staticMiddlewares); -app.get("/*", (_, res) => send404(res)); +app.get("/*", async (_, res) => await send404(res)); if (!fs.existsSync(path.resolve(CONTENT_ROOT))) { throw new Error(`${path.resolve(CONTENT_ROOT)} does not exist!`); diff --git a/tool/popularities.ts b/tool/popularities.ts index 87a010ac7514..2b020ba4defb 100644 --- a/tool/popularities.ts +++ b/tool/popularities.ts @@ -69,7 +69,14 @@ export async function runMakePopularitiesFile({ pageviews.slice(0, maxUris).forEach(([uri, popularity]) => { popularities[uri] = parseFloat(popularity.toFixed(5)); }); - fs.writeFileSync(outfile, JSON.stringify(popularities, null, 2)); + fs.writeFileSync( + outfile, + JSON.stringify( + { popularities: popularities, date: new Date().toISOString() }, + null, + 2 + ) + ); resolve({ rowCount, popularities, pageviews }); }); }); diff --git a/yarn.lock b/yarn.lock index edcc94452aef..6f88cd98234b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,6 +10,15 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" +"@apidevtools/json-schema-ref-parser@^11.5.5": + version "11.7.2" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz#cdf3e0aded21492364a70e193b45b7cf4177f031" + integrity sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA== + dependencies: + "@jsdevtools/ono" "^7.1.3" + "@types/json-schema" "^7.0.15" + js-yaml "^4.1.0" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" @@ -1815,6 +1824,13 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" +"@isaacs/fs-minipass@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" + integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== + dependencies: + minipass "^7.0.4" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -2079,6 +2095,11 @@ jsbi "^4.3.0" tslib "^2.4.1" +"@jsdevtools/ono@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" + integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== + "@jsonjoy.com/base64@^1.1.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-1.1.2.tgz#cf8ea9dcb849b81c95f14fc0aaa151c6b54d2578" @@ -2187,6 +2208,17 @@ resolved "https://registry.yarnpkg.com/@mdn/minimalist/-/minimalist-2.0.4.tgz#6488ab0cb65b059446dcd9bf542246b81febe241" integrity sha512-jocePw/fsGcBxO67D+iWQLZ0TQjwNVonaME2BFN98QIm/e1kTY1/k2s4fOqH5MMa3QYURxa098bI4sChn6s/7Q== +"@mdn/rari@^0.0.25": + version "0.0.25" + resolved "https://registry.yarnpkg.com/@mdn/rari/-/rari-0.0.25.tgz#719b6a72eb8239dca48b6bf090f1f38490380be7" + integrity sha512-5r1P9CAGLC93O6hZgc2fdO0Z4B/uI8PbAworRRlMthPlXUjyiyfIdzijwGCkr8JN5H6950oCLfjwJAEd4NGUPQ== + dependencies: + extract-zip "^2.0.1" + https-proxy-agent "^7.0.2" + json-schema-to-typescript "^15.0.0" + proxy-from-env "^1.1.0" + tar "^7.4.3" + "@mozilla/glean@5.0.3": version "5.0.3" resolved "https://registry.yarnpkg.com/@mozilla/glean/-/glean-5.0.3.tgz#eda7169f3e8f38a7d3019a1512b45778c4f05735" @@ -3342,7 +3374,7 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -3352,7 +3384,7 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/lodash@^4.14.149": +"@types/lodash@^4.14.149", "@types/lodash@^4.17.7": version "4.17.13" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb" integrity sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg== @@ -3642,6 +3674,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yauzl@^2.9.1": + version "2.10.3" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999" + integrity sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q== + dependencies: + "@types/node" "*" + "@typescript-eslint/eslint-plugin@8.16.0": version "8.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz#ac56825bcdf3b392fc76a94b1315d4a162f201a6" @@ -4991,6 +5030,11 @@ chokidar@^4.0.0: dependencies: readdirp "^4.0.1" +chownr@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" + integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== + chrome-trace-event@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" @@ -5260,6 +5304,19 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +concurrently@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.0.1.tgz#01e171bf6c7af0c022eb85daef95bff04d8185aa" + integrity sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg== + dependencies: + chalk "^4.1.2" + lodash "^4.17.21" + rxjs "^7.8.1" + shell-quote "^1.8.1" + supports-color "^8.1.1" + tree-kill "^1.2.2" + yargs "^17.7.2" + config-chain@^1.1.11: version "1.1.13" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" @@ -6989,6 +7046,17 @@ external-editor@^3.0.3, external-editor@^3.1.0: iconv-lite "^0.4.24" tmp "^0.0.33" +extract-zip@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -7515,6 +7583,13 @@ get-stream@^4.0.0: dependencies: pump "^3.0.0" +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -7582,7 +7657,7 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^10.0.0: +glob@^10.0.0, glob@^10.3.7: version "10.4.5" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== @@ -9597,6 +9672,21 @@ json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-schema-to-typescript@^15.0.0: + version "15.0.3" + resolved "https://registry.yarnpkg.com/json-schema-to-typescript/-/json-schema-to-typescript-15.0.3.tgz#a58bc3e00e4480e76a8ee79471c01233494913be" + integrity sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA== + dependencies: + "@apidevtools/json-schema-ref-parser" "^11.5.5" + "@types/json-schema" "^7.0.15" + "@types/lodash" "^4.17.7" + is-glob "^4.0.3" + js-yaml "^4.1.0" + lodash "^4.17.21" + minimist "^1.2.8" + prettier "^3.2.5" + tinyglobby "^0.2.9" + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -10730,16 +10820,24 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.2.0, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4, minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== +minizlib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.1.tgz#46d5329d1eb3c83924eff1d3b858ca0a31581012" + integrity sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg== + dependencies: + minipass "^7.0.4" + rimraf "^5.0.5" + mkdirp@^0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -10747,6 +10845,11 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.6" +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + module-details-from-path@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" @@ -12303,7 +12406,7 @@ prettier-plugin-packagejson@^2.5.6: sort-package-json "2.12.0" synckit "0.9.2" -prettier@^3.4.1: +prettier@^3.2.5, prettier@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.1.tgz#e211d451d6452db0a291672ca9154bc8c2579f7b" integrity sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg== @@ -13051,6 +13154,13 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +rimraf@^5.0.5: + version "5.0.10" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.10.tgz#23b9843d3dc92db71f96e1a2ce92e39fd2a8221c" + integrity sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ== + dependencies: + glob "^10.3.7" + rough-notation@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/rough-notation/-/rough-notation-0.5.1.tgz#32abbb16b973fb00fba83ab96b18704e98620e95" @@ -13085,6 +13195,13 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" +rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" @@ -14118,7 +14235,7 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0: +supports-color@^8.0.0, supports-color@^8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -14233,6 +14350,18 @@ tar-stream@^1.5.2: to-buffer "^1.1.1" xtend "^4.0.0" +tar@^7.4.3: + version "7.4.3" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" + integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== + dependencies: + "@isaacs/fs-minipass" "^4.0.0" + chownr "^3.0.0" + minipass "^7.1.2" + minizlib "^3.0.1" + mkdirp "^3.0.1" + yallist "^5.0.0" + temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" @@ -14440,6 +14569,11 @@ tree-dump@^1.0.1: resolved "https://registry.yarnpkg.com/tree-dump/-/tree-dump-1.0.2.tgz#c460d5921caeb197bde71d0e9a7b479848c5b8ac" integrity sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ== +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + trim-lines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" @@ -14549,6 +14683,11 @@ tslib@^2.0.0, tslib@^2.0.3, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.1, tslib@^2.6 resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== +tslib@^2.1.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.0.tgz#d124c86c3c05a40a91e6fdea4021bd31d377971b" + integrity sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -15545,6 +15684,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yallist@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" + integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== + yaml@^1.10.0: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" @@ -15565,7 +15709,7 @@ yargs-parser@^21.1.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.3.1: +yargs@^17.3.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== @@ -15578,7 +15722,7 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.1.1" -yauzl@^2.4.2, yauzl@^2.9.2: +yauzl@^2.10.0, yauzl@^2.4.2, yauzl@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==