diff --git a/content/actions/how-tos/manage-runners/larger-runners/use-custom-images.md b/content/actions/how-tos/manage-runners/larger-runners/use-custom-images.md index a04d1cc65e92..4c76c2127654 100644 --- a/content/actions/how-tos/manage-runners/larger-runners/use-custom-images.md +++ b/content/actions/how-tos/manage-runners/larger-runners/use-custom-images.md @@ -8,6 +8,8 @@ product: '{% data variables.actions.github_hosted_larger_runners %} are only ava --- +{% data reusables.actions.custom-images-public-preview-note %} + ## Custom images You can create a custom image to define the exact environment that your {% data variables.actions.github_hosted_larger_runners %} use. Custom images let you preinstall tools, dependencies, and configurations to speed up workflows and improve consistency across jobs. diff --git a/data/reusables/actions/custom-images-public-preview-note.md b/data/reusables/actions/custom-images-public-preview-note.md new file mode 100644 index 000000000000..803079d4a30d --- /dev/null +++ b/data/reusables/actions/custom-images-public-preview-note.md @@ -0,0 +1,2 @@ +> [!NOTE] +> Custom images are in {% data variables.release-phases.public_preview %} and subject to change. diff --git a/package-lock.json b/package-lock.json index 3aa77f836023..c1421bc290b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,7 +67,7 @@ "mdast-util-to-hast": "^13.2.1", "mdast-util-to-markdown": "2.1.2", "mdast-util-to-string": "^4.0.0", - "next": "^16.0.7", + "next": "^16.0.9", "ora": "^9.0.0", "parse5": "7.1.2", "quick-lru": "7.0.1", @@ -2528,15 +2528,15 @@ } }, "node_modules/@next/env": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.7.tgz", - "integrity": "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.9.tgz", + "integrity": "sha512-6284pl8c8n9PQidN63qjPVEu1uXXKjnmbmaLebOzIfTrSXdGiAPsIMRi4pk/+v/ezqweE1/B8bFqiAAfC6lMXg==", "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.7.tgz", - "integrity": "sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.9.tgz", + "integrity": "sha512-j06fWg/gPqiWjK+sEpCDsh5gX+Bdy9gnPYjFqMBvBEOIcCFy1/ecF6pY6XAce7WyCJAbBPVb+6GvpmUZKNq0oQ==", "cpu": [ "arm64" ], @@ -2550,9 +2550,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.7.tgz", - "integrity": "sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.9.tgz", + "integrity": "sha512-FRYYz5GSKUkfvDSjd5hgHME2LgYjfOLBmhRVltbs3oRNQQf9n5UTQMmIu/u5vpkjJFV4L2tqo8duGqDxdQOFwg==", "cpu": [ "x64" ], @@ -2566,9 +2566,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.7.tgz", - "integrity": "sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.9.tgz", + "integrity": "sha512-EI2klFVL8tOyEIX5J1gXXpm1YuChmDy4R+tHoNjkCHUmBJqXioYErX/O2go4pEhjxkAxHp2i8y5aJcRz2m5NqQ==", "cpu": [ "arm64" ], @@ -2582,9 +2582,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.7.tgz", - "integrity": "sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.9.tgz", + "integrity": "sha512-vq/5HeGvowhDPMrpp/KP4GjPVhIXnwNeDPF5D6XK6ta96UIt+C0HwJwuHYlwmn0SWyNANqx1Mp6qSVDXwbFKsw==", "cpu": [ "arm64" ], @@ -2598,9 +2598,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.7.tgz", - "integrity": "sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.9.tgz", + "integrity": "sha512-GlUdJwy2leA/HnyRYxJ1ZJLCJH+BxZfqV4E0iYLrJipDKxWejWpPtZUdccPmCfIEY9gNBO7bPfbG6IIgkt0qXg==", "cpu": [ "x64" ], @@ -2614,9 +2614,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.7.tgz", - "integrity": "sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.9.tgz", + "integrity": "sha512-UCtOVx4N8AHF434VPwg4L0KkFLAd7pgJShzlX/hhv9+FDrT7/xCuVdlBsCXH7l9yCA/wHl3OqhMbIkgUluriWA==", "cpu": [ "x64" ], @@ -2630,9 +2630,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.7.tgz", - "integrity": "sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.9.tgz", + "integrity": "sha512-tQjtDGtv63mV3n/cZ4TH8BgUvKTSFlrF06yT5DyRmgQuj5WEjBUDy0W3myIW5kTRYMPrLn42H3VfCNwBH6YYiA==", "cpu": [ "arm64" ], @@ -2646,9 +2646,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.7.tgz", - "integrity": "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.9.tgz", + "integrity": "sha512-y9AGACHTBwnWFLq5B5Fiv3FEbXBusdPb60pgoerB04CV/pwjY1xQNdoTNxAv7eUhU2k1CKnkN4XWVuiK07uOqA==", "cpu": [ "x64" ], @@ -12122,12 +12122,12 @@ } }, "node_modules/next": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/next/-/next-16.0.7.tgz", - "integrity": "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/next/-/next-16.0.9.tgz", + "integrity": "sha512-Xk5x/wEk6ADIAtQECLo1uyE5OagbQCiZ+gW4XEv24FjQ3O2PdSkvgsn22aaseSXC7xg84oONvQjFbSTX5YsMhQ==", "license": "MIT", "dependencies": { - "@next/env": "16.0.7", + "@next/env": "16.0.9", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", @@ -12140,14 +12140,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.0.7", - "@next/swc-darwin-x64": "16.0.7", - "@next/swc-linux-arm64-gnu": "16.0.7", - "@next/swc-linux-arm64-musl": "16.0.7", - "@next/swc-linux-x64-gnu": "16.0.7", - "@next/swc-linux-x64-musl": "16.0.7", - "@next/swc-win32-arm64-msvc": "16.0.7", - "@next/swc-win32-x64-msvc": "16.0.7", + "@next/swc-darwin-arm64": "16.0.9", + "@next/swc-darwin-x64": "16.0.9", + "@next/swc-linux-arm64-gnu": "16.0.9", + "@next/swc-linux-arm64-musl": "16.0.9", + "@next/swc-linux-x64-gnu": "16.0.9", + "@next/swc-linux-x64-musl": "16.0.9", + "@next/swc-win32-arm64-msvc": "16.0.9", + "@next/swc-win32-x64-msvc": "16.0.9", "sharp": "^0.34.4" }, "peerDependencies": { diff --git a/package.json b/package.json index 250be69b5fbf..2a90c7d1a623 100644 --- a/package.json +++ b/package.json @@ -213,7 +213,7 @@ "mdast-util-to-hast": "^13.2.1", "mdast-util-to-markdown": "2.1.2", "mdast-util-to-string": "^4.0.0", - "next": "^16.0.7", + "next": "^16.0.9", "ora": "^9.0.0", "parse5": "7.1.2", "quick-lru": "7.0.1", diff --git a/src/assets/README.md b/src/assets/README.md index 910b3b244541..d3170b0f63d9 100644 --- a/src/assets/README.md +++ b/src/assets/README.md @@ -1,3 +1,70 @@ # Assets -Assets are files such as images and CSV data that we serve statically to run the docs.github.com application. +This directory contains the logic for serving, processing, and validating static assets used in the GitHub Docs application. While the actual asset files (images, CSVs, etc.) reside in the root `assets/` directory, `src/assets` houses the code that manages how these assets are delivered to the user. + +## Purpose & Scope + +The primary responsibilities of this module are: +- **Dynamic Image Processing**: Converting PNGs to WebP on-the-fly and resizing images based on URL parameters. +- **Caching Strategy**: Setting appropriate cache headers and surrogate keys for assets, especially those with checksums in their URLs. +- **Validation & Maintenance**: Scripts to ensure assets are used correctly, identifying orphaned files, and validating image dimensions. + +## Architecture + +### Middleware + +The core logic resides in `src/assets/middleware`: + +- **`dynamic-assets.ts`**: Intercepts requests for `/assets/`. It handles: + - **WebP Conversion**: If a request ends in `.webp` but the source is a `.png`, it converts the image using `sharp`. + - **Resizing**: Supports virtual path segments like `/mw-1000/` to resize images to a maximum width (e.g., 1000px). + - **Security**: Validates requested widths against an allowed list (`VALID_MAX_WIDTHS`) to prevent DoS attacks. +- **`static-asset-caching.ts`**: Detects if an asset URL contains a checksum (e.g., `/assets/cb-12345/...`) and sets aggressive caching headers (`Surrogate-Key: manual-purge`) because the content is immutable. + +### Scripts + +Located in `src/assets/scripts`, these tools help maintain the asset library: +- `find-orphaned-assets.ts`: Identifies assets present in the disk but not referenced in the content or code. +- `validate-asset-images.ts`: Checks for issues like invalid file types or corruption. +- `list-image-sizes.ts`: Utility for analyzing image dimensions. + +### Library + +- `src/assets/lib/image-density.ts`: Utilities for handling high-density (Retina) images. + +## Setup & Usage + +### Adding New Assets + +Place static files (images, PDFs, etc.) in the root `assets/` directory. +- **Images**: `assets/images` +- **Data**: `assets/` (e.g., CSV files) + +### URL Structure + +The application (via `src/frame`) often rewrites asset URLs to include a checksum for cache busting. +- **Source**: `/assets/images/foo.png` +- **Served**: `/assets/cb-123456/images/foo.png` (The `cb-xxxxx` part is ignored by the file system lookup but used for caching). + +### Dynamic Transformations + +To request a WebP version of a PNG: +`GET /assets/images/foo.webp` (Server looks for `foo.png` and converts it). + +To request a resized version: +`GET /assets/mw-1000/images/foo.webp` (Resizes to max-width 1000px). + +## Dependencies + +- **`sharp`**: Used for high-performance image processing (resizing, format conversion). +- **`assets/` directory**: The source of truth for static files. + +## Ownership + +- **Team**: `@github/docs-engineering` +- **Escalation**: If image serving fails or performance degrades, check the `dynamic-assets` middleware and `sharp` processing. + +## Current State & Known Issues + +- **On-the-fly Processing**: We currently process images on request (cached by CDN). This avoids a massive build-time step but requires CPU resources on the server for uncached requests. +- **WebP**: We prefer WebP for performance but maintain PNGs as the source of truth. \ No newline at end of file diff --git a/src/color-schemes/README.md b/src/color-schemes/README.md index 11824222f55a..54a41ac2a914 100644 --- a/src/color-schemes/README.md +++ b/src/color-schemes/README.md @@ -1,5 +1,72 @@ -# Color schemes +# Color Schemes -Color schemes are user preferences regarding which type of colors they would like the site to use. Currently we support a number of mode, including light, dark, and several accessibility options. +This module manages the application of color themes (light, dark, high contrast, etc.) to the GitHub Docs site. It ensures that the documentation matches the user's preferred color scheme as configured on GitHub.com. -We chose the name "schemes" instead of modes or themes because that is what the HTML specification calls them. +## Purpose & Scope + +The primary goal is to read the user's color preference from a cookie and apply the correct theme context to the React application. This supports: +- **Modes**: Light, Dark, Auto (system preference). +- **Themes**: Specific variations like "Dark Dimmed" or "Dark High Contrast". +- **Compatibility**: Bridging the gap between raw CSS class names and Primer React component props. + +## Architecture + +The core logic is contained within `src/color-schemes/components/useTheme.ts`. + +### The `color_mode` Cookie + +The site relies on a cookie named `color_mode` to determine the user's preference. This cookie is typically set by the main GitHub application and shared with the docs subdomains. The cookie value is a JSON string containing: +- `color_mode`: The overall mode (`light`, `dark`, `auto`). +- `light_theme`: The specific theme to use when in light mode. +- `dark_theme`: The specific theme to use when in dark mode. + +### `useTheme` Hook + +The `useTheme` hook is the main entry point. It performs the following steps: +1. **Reads the Cookie**: Parses the `color_mode` cookie safely. +2. **Normalizes Data**: Validates the values against supported enums (`SupportedTheme`, `CssColorMode`). +3. **Formats for Consumers**: Returns two distinct theme objects: + - `css`: For applying global CSS classes (uses `light`/`dark`). + - `component`: For passing to Primer React's `ThemeProvider` (uses `day`/`night`). + +### Mapping Logic + +Primer React uses slightly different terminology than the underlying CSS or the cookie schema. The module handles this translation: +- CSS `light` -> Component `day` +- CSS `dark` -> Component `night` + +## Setup & Usage + +To access the current theme in a component: + +```typescript +import { useTheme } from '@/color-schemes/components/useTheme' + +const MyComponent = () => { + const { theme } = useTheme() + + // Access CSS-friendly values + console.log(theme.css.colorMode) + + // Access Primer-friendly values + console.log(theme.component.dayScheme) +} +``` + +This hook is primarily used at the root of the application (e.g., in `src/frame/components/Page.tsx` or `_app.tsx`) to wrap the content in a `ThemeProvider`. + +## Dependencies + +- **`js-cookie`**: Used via `src/frame/components/lib/cookies` to read the browser cookie. +- **Primer React**: The output format is specifically designed to satisfy Primer React's theming requirements. + +## Ownership + +- **Team**: `@github/docs-engineering` + +## Current State & Known Issues + +- **Hydration Mismatch / Flash of Unstyled Content**: Since the theme is read from a cookie on the client side (in `useEffect`), there can be a brief moment where the default theme is applied before the user's preference loads. +- **Race Condition Workaround**: There is a `setTimeout` hack in `useTheme.ts` to delay the theme application. This is necessary to prevent Primer React's internal logic from overriding the user's preference with `auto` on initial load. + - *Reference*: [Primer React Issue #2229](https://github.com/primer/react/issues/2229) +- **Future**: The long-term goal is to rely entirely on CSS variables, removing the need for complex JavaScript state management for theming. \ No newline at end of file