diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 9da9859f..1ae0daac 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -11,9 +11,11 @@ on: branches: [main] types: [opened, synchronize, reopened] +# TODO: Shard tests across a matrix to speed up CI. +# See: https://playwright.dev/docs/test-sharding#github-actions-example jobs: test: - timeout-minutes: 10 + timeout-minutes: 20 runs-on: ubuntu-latest steps: - name: Harden Runner diff --git a/src/components/FrameworkLinks.astro b/src/components/FrameworkLinks.astro new file mode 100644 index 00000000..c475469a --- /dev/null +++ b/src/components/FrameworkLinks.astro @@ -0,0 +1,23 @@ +--- +/** + * FrameworkLinks — Astro wrapper + * + * On SDK-scoped routes (`/sdk/:sdk/...`), renders nothing — the SDK switcher + * in the table of contents already provides navigation between SDK variants. + * + * On legacy (unscoped) routes, delegates to the React `FrameworkLinksReact` + * component with `client:load` so the existing `?f=` link grid stays the same. + */ +import FrameworkLinksReact from "@/components/FrameworkLinksReact"; +import { sdkFromPathname } from "@/lib/sdk"; + +const sdkKey = sdkFromPathname(Astro.url.pathname); +--- + +{ + sdkKey ? null : ( + + + + ) +} diff --git a/src/components/FrameworkLinks.tsx b/src/components/FrameworkLinksReact.tsx similarity index 100% rename from src/components/FrameworkLinks.tsx rename to src/components/FrameworkLinksReact.tsx diff --git a/src/components/SdkReferenceLinkByFramework.astro b/src/components/SdkReferenceLinkByFramework.astro index a5c6b87a..b1f99836 100644 --- a/src/components/SdkReferenceLinkByFramework.astro +++ b/src/components/SdkReferenceLinkByFramework.astro @@ -1,9 +1,9 @@ --- -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import { Link } from "@/components/link"; --- - + + ) : ( +
+ +
+ ) + ) : ( + + {Astro.slots.has("default") && ( + + )} + {Astro.slots.has("astro") && ( + + )} + {Astro.slots.has("bun") && ( + + )} + {Astro.slots.has("bun-hono") && ( + + )} + {Astro.slots.has("deno") && ( + + )} + {Astro.slots.has("fastify") && ( + + )} + {Astro.slots.has("nest-js") && ( + + )} + {Astro.slots.has("next-js") && ( + + )} + {Astro.slots.has("node-js") && ( + + )} + {Astro.slots.has("node-js-express") && ( + + )} + {Astro.slots.has("node-js-hono") && ( + + )} + {Astro.slots.has("nuxt") && ( + + )} + {Astro.slots.has("python-fastapi") && ( + + )} + {Astro.slots.has("python-flask") && ( + + )} + {Astro.slots.has("react-router") && ( + + )} + {Astro.slots.has("remix") && ( + + )} + {Astro.slots.has("sveltekit") && ( + + )} + + ) +} diff --git a/src/components/SlotByFramework.tsx b/src/components/SlotByFrameworkReact.tsx similarity index 100% rename from src/components/SlotByFramework.tsx rename to src/components/SlotByFrameworkReact.tsx diff --git a/src/components/TextByFramework.astro b/src/components/TextByFramework.astro new file mode 100644 index 00000000..cecefacb --- /dev/null +++ b/src/components/TextByFramework.astro @@ -0,0 +1,49 @@ +--- +/** + * TextByFramework — Astro wrapper + * + * On SDK-scoped routes (`/sdk/:sdk/...`), renders the matching text prop at + * build time with zero client JavaScript. + * + * On legacy (unscoped) routes, delegates to the React `TextByFrameworkReact` + * component with `client:load` so the existing client-side framework switching + * continues to work. + */ +import type { FrameworkKey } from "@/lib/prefs"; +import TextByFrameworkReact from "@/components/TextByFrameworkReact"; +import { sdkFromPathname, legacyKeyFromPathname } from "@/lib/sdk"; +import { kebabToCamel } from "@/lib/utils"; + +type Props = { [key in FrameworkKey]?: string } & { + /** Fallback text when no framework-specific prop matches. */ + default?: string; +}; + +const props = Astro.props as Props; +const sdkKey = sdkFromPathname(Astro.url.pathname); + +let resolvedText: string | undefined; +if (sdkKey) { + const legacyKey = legacyKeyFromPathname(Astro.url.pathname); + if (legacyKey) { + const camelKey = kebabToCamel(legacyKey) as FrameworkKey; + if (props[legacyKey] !== undefined) { + resolvedText = props[legacyKey]; + } else if (props[camelKey] !== undefined) { + resolvedText = props[camelKey]; + } else { + resolvedText = props["default"]; + } + } +} +--- + +{ + sdkKey && resolvedText !== undefined ? ( + + ) : ( + + + + ) +} diff --git a/src/components/TextByFramework.tsx b/src/components/TextByFrameworkReact.tsx similarity index 100% rename from src/components/TextByFramework.tsx rename to src/components/TextByFrameworkReact.tsx diff --git a/src/components/TitleByFramework.tsx b/src/components/TitleByFramework.tsx index 4a77c9fb..1af0ca44 100644 --- a/src/components/TitleByFramework.tsx +++ b/src/components/TitleByFramework.tsx @@ -1,5 +1,5 @@ -import type { Props as TextByFrameworkProps } from "@/components/TextByFramework"; -import TextByFramework from "@/components/TextByFramework"; +import type { Props as TextByFrameworkProps } from "@/components/TextByFrameworkReact"; +import TextByFramework from "@/components/TextByFrameworkReact"; import type { FrameworkKey } from "@/lib/prefs"; import type { ForwardedRef, PropsWithChildren } from "react"; import { forwardRef, useCallback, useEffect, useState } from "react"; diff --git a/src/content/docs/bot-protection/quick-start.mdx b/src/content/docs/bot-protection/quick-start.mdx index 37432dec..2e34c440 100644 --- a/src/content/docs/bot-protection/quick-start.mdx +++ b/src/content/docs/bot-protection/quick-start.mdx @@ -52,10 +52,10 @@ import { CardGrid } from "@astrojs/starlight/components"; import { Link } from "@/components/link"; import { frameworks } from "@/lib/prefs"; import WhatIsArcjet from "/src/components/WhatIsArcjet.astro"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import FrameworkName from "@/components/FrameworkName"; import FAQs from "/src/components/FAQs.astro"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import Comments from "/src/components/Comments.astro"; import SdkReferenceLinkByFramework from "/src/components/SdkReferenceLinkByFramework.astro"; @@ -109,7 +109,6 @@ Arcjet bot detection allows you to manage traffic by automated clients and bots. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -125,7 +124,7 @@ application from bots and automated clients. In your project root, run the following command to install the SDK: - + @@ -142,7 +141,7 @@ In your project root, run the following command to install the SDK: [Create a free Arcjet account](https://app.arcjet.com) then follow the instructions to add a site and get a key. - + @@ -156,7 +155,7 @@ instructions to add a site and get a key. ### 3. Add bot protection - + @@ -168,7 +167,7 @@ instructions to add a site and get a key. - + diff --git a/src/content/docs/bot-protection/reference.mdx b/src/content/docs/bot-protection/reference.mdx index 8adff610..2fea82f4 100644 --- a/src/content/docs/bot-protection/reference.mdx +++ b/src/content/docs/bot-protection/reference.mdx @@ -90,9 +90,9 @@ import Business from "@/components/badges/Business.astro"; import Enterprise from "@/components/badges/Enterprise.astro"; import Comments from "@/components/Comments.astro"; import { Link } from "@/components/link"; -import SlotByFramework from "@/components/SlotByFramework"; -import TextByFramework from "@/components/TextByFramework"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import TextByFramework from "@/components/TextByFramework.astro"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import { frameworks } from "@/lib/prefs"; import BunAllowingBots from "@/snippets/bot-protection/reference/bun/AllowingBots.mdx"; @@ -154,7 +154,6 @@ import SvelteKitPerRouteVsHooks from "@/snippets/bot-protection/reference/svelte Arcjet bot detection allows you to manage traffic by automated clients and bots. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -208,7 +207,7 @@ This behavior is configured with an `allow` list from our [full list of bots](https://arcjet.com/bot-list) and/or bot categories. - + @@ -228,7 +227,7 @@ This behavior is configured with a `deny` list from our [full list of bots](https://arcjet.com/bot-list) and/or bot categories. - + @@ -238,7 +237,7 @@ bots](https://arcjet.com/bot-list) and/or - + @@ -255,7 +254,7 @@ Arcjet provides a single `protect` function that is used to execute your protection rules. This requires a `request` argument which is the request context as passed to the request handler. - + @@ -288,7 +287,7 @@ for (const result of decision.results) { } ``` - + @@ -306,7 +305,7 @@ request. A request may be identified as zero, one, or more bots/categories-all of which will be available on the `decision.allowed` and `decision.denied` properties. - + @@ -339,7 +338,7 @@ header. See an example of how to do this. ::: - + @@ -355,7 +354,7 @@ All categories are also provided as enumerations, which allows for programmatic access. For example, you may want to allow most of `CATEGORY:GOOGLE` except their "advertising quality" bot. - + @@ -497,7 +496,7 @@ Arcjet can also be triggered based using a sample of your traffic. See the Testing section of the docs for details. - + diff --git a/src/content/docs/email-validation/quick-start.mdx b/src/content/docs/email-validation/quick-start.mdx index 01516034..ee12d132 100644 --- a/src/content/docs/email-validation/quick-start.mdx +++ b/src/content/docs/email-validation/quick-start.mdx @@ -44,8 +44,8 @@ import { Link } from "@/components/link"; import { CardGrid } from "@astrojs/starlight/components"; import SdkReferenceLinkByFramework from "/src/components/SdkReferenceLinkByFramework.astro"; import WhatIsArcjet from "/src/components/WhatIsArcjet.astro"; -import FrameworkLinks from "@/components/FrameworkLinks"; -import SlotByFramework from "@/components/SlotByFramework"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import FrameworkName from "@/components/FrameworkName"; import { frameworks } from "@/lib/prefs"; import Step1Bun from "@/snippets/email-validation/quick-start/bun/Step1.mdx"; @@ -78,7 +78,6 @@ reduce the amount of spam or fraudulent accounts. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -94,7 +93,7 @@ your app. In your project root, run the following command to install the SDK: - + @@ -109,7 +108,7 @@ In your project root, run the following command to install the SDK: instructions to add a site and get a key. Add it to a `.env.local` file in your project root. - + @@ -124,7 +123,7 @@ The example below shows how to use Arcjet to check an email address. If the email address is invalid or if no MX records are configured, Arcjet will return a deny decision. - + @@ -133,7 +132,7 @@ a deny decision. - + diff --git a/src/content/docs/email-validation/reference.mdx b/src/content/docs/email-validation/reference.mdx index 989c3ba8..9aa38e7e 100644 --- a/src/content/docs/email-validation/reference.mdx +++ b/src/content/docs/email-validation/reference.mdx @@ -24,9 +24,9 @@ ajToc: import { Link } from "@/components/link"; import { Aside, Badge } from "@astrojs/starlight/components"; -import SlotByFramework from "@/components/SlotByFramework"; -import TextByFramework from "@/components/TextByFramework"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import TextByFramework from "@/components/TextByFramework.astro"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import DisplayType from "@/components/DisplayType.astro"; import { frameworks } from "@/lib/prefs"; @@ -58,7 +58,6 @@ preventing users from signing up with fake email addresses and can significantly reduce the amount of spam or fraudulent accounts. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -188,7 +187,7 @@ to allow certain types of email addresses, you can modify the options: literals. Defaults to `false`. Changing to `true` means that `foo@[123.456.789.0]` would be allowed. - + @@ -199,7 +198,7 @@ protection rules. This requires a `request` argument which is the request context as passed to the request handler. When configured with a `validateEmail` rule it also requires an additional `email` prop. - + @@ -234,7 +233,7 @@ for (const result of decision.results) { This example will log the full result as well as the email validation rule: - + @@ -248,7 +247,7 @@ This example will log the full result as well as the email validation rule: In addition to being able to deny specific email types, you can also configure Arcjet to only allow specific email types and all other types will be blocked. - + @@ -306,7 +305,7 @@ error result for more information. If all other rules that were run returned an `ALLOW` result, then the final Arcjet conclusion will be `ERROR`. - + diff --git a/src/content/docs/filters/quick-start.mdx b/src/content/docs/filters/quick-start.mdx index 80c149bc..a3c739c6 100644 --- a/src/content/docs/filters/quick-start.mdx +++ b/src/content/docs/filters/quick-start.mdx @@ -56,8 +56,8 @@ import Comments from "/src/components/Comments.astro"; import Faqs from "/src/components/FAQs.astro"; import SdkReferenceLinkByFramework from "/src/components/SdkReferenceLinkByFramework.astro"; import WhatIsArcjet from "/src/components/WhatIsArcjet.astro"; -import SlotByFramework from "@/components/SlotByFramework"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import FrameworkName from "@/components/FrameworkName"; import { frameworks } from "@/lib/prefs"; import { Link } from "@/components/link"; @@ -112,7 +112,6 @@ allows you to quickly enforce rules like allow/deny by country, network, or !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -128,7 +127,7 @@ filters. Run the following command to install the SDK in your project: - + @@ -146,7 +145,7 @@ Run the following command to install the SDK in your project: [Create a free Arcjet account](https://app.arcjet.com) and follow the instructions to add a site and get a key. - + @@ -161,7 +160,7 @@ instructions to add a site and get a key. ### 3. Add filters - + @@ -176,7 +175,7 @@ instructions to add a site and get a key. {/* Note: Step 4 has its heading inside it as it is dynamic. Make sure that the table of contents (in frontmatter) reflects that dynamic heading correctly. */} - + @@ -193,7 +192,7 @@ instructions to add a site and get a key. Make a `curl` request from your terminal to your app: - + ```sh diff --git a/src/content/docs/filters/reference.mdx b/src/content/docs/filters/reference.mdx index 836b29c4..7bcbd2da 100644 --- a/src/content/docs/filters/reference.mdx +++ b/src/content/docs/filters/reference.mdx @@ -38,9 +38,9 @@ ajToc: import { Link } from "@/components/link"; import { Badge } from "@astrojs/starlight/components"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import DisplayType from "@/components/DisplayType.astro"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import { frameworks } from "@/lib/prefs"; import BunAllow from "@/snippets/filters/reference/bun/Allow.mdx"; import DenoAllow from "@/snippets/filters/reference/deno/Allow.mdx"; @@ -58,7 +58,6 @@ allows you to quickly enforce rules like allow/deny by country, network, or `user-agent`. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -93,7 +92,7 @@ See [decision](#decision) below for details of examining the execution results. In this example, the expression matches non-VPN GET requests from the US. Requests matching the expression are allowed and all others are denied. - + diff --git a/src/content/docs/get-started.mdx b/src/content/docs/get-started.mdx index eae2e67a..20259334 100644 --- a/src/content/docs/get-started.mdx +++ b/src/content/docs/get-started.mdx @@ -58,8 +58,8 @@ ajToc: --- import { YouTube } from "astro-embed"; -import SlotByFramework from "@/components/SlotByFramework"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import { Link } from "@/components/link"; import { LinkButton, CardGrid } from "@astrojs/starlight/components"; import FAQs from "/src/components/FAQs.astro"; @@ -168,17 +168,17 @@ protection. Data redaction. A developer-first approach to security. This guide will show you how to set up a simple API server protected by Arcjet. - + - + ## 1. Install Arcjet In your project root, run the following: - + @@ -199,7 +199,7 @@ In your project root, run the following: ### Requirements - + @@ -223,7 +223,7 @@ In your project root, run the following: [Create a free Arcjet account](https://app.arcjet.com) then follow the instructions to add a site and get a key. - + @@ -247,7 +247,7 @@ instructions to add a site and get a key. This configures Arcjet rules to protect your app from attacks, apply a rate limit, and prevent bots from accessing your app. - + @@ -266,7 +266,7 @@ limit, and prevent bots from accessing your app. - + diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx index 83b63d3f..e9b23522 100644 --- a/src/content/docs/index.mdx +++ b/src/content/docs/index.mdx @@ -14,14 +14,13 @@ hero: --- import { YouTube } from "astro-embed"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import Launch from "@/components/Launch"; ## Learn more diff --git a/src/content/docs/nosecone/quick-start.mdx b/src/content/docs/nosecone/quick-start.mdx index 317c5af7..1a0c5103 100644 --- a/src/content/docs/nosecone/quick-start.mdx +++ b/src/content/docs/nosecone/quick-start.mdx @@ -39,8 +39,8 @@ ajToc: import WhatAreArcjetUtilities from "@/components/WhatAreArcjetUtilities.astro"; import FrameworkName from "@/components/FrameworkName"; import NpmSdkVersion from "@/components/NpmSdkVersion.astro"; -import FrameworkLinks from "@/components/FrameworkLinks"; -import SlotByFramework from "@/components/SlotByFramework"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import { frameworks } from "@/lib/prefs"; import { CardGrid } from "@astrojs/starlight/components"; import { Link } from "@/components/link"; @@ -103,7 +103,6 @@ See the reference guide for full details on each option. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -126,7 +125,7 @@ default security headers. In your project root, run the following command to install the Arcjet Nosecone library for your framework: - + @@ -136,7 +135,7 @@ library for your framework: ### 2. Configure your application - + @@ -146,7 +145,7 @@ library for your framework: ### 3. Run your application - + @@ -162,7 +161,7 @@ application, but may break things (particularly the CSP header). We recommend you test your application thoroughly and tweak the settings to ensure it continues to work as expected. - + diff --git a/src/content/docs/rate-limiting/quick-start.mdx b/src/content/docs/rate-limiting/quick-start.mdx index 5ffdc244..e49eb816 100644 --- a/src/content/docs/rate-limiting/quick-start.mdx +++ b/src/content/docs/rate-limiting/quick-start.mdx @@ -46,9 +46,9 @@ ajToc: import { Link } from "@/components/link"; import { CardGrid } from "@astrojs/starlight/components"; import WhatIsArcjet from "@/components/WhatIsArcjet.astro"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import FrameworkName from "@/components/FrameworkName"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import FAQs from "@/components/FAQs.astro"; import Comments from "@/components/Comments.astro"; import { frameworks } from "@/lib/prefs"; @@ -91,14 +91,13 @@ requests a client can make over a period of time. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} title="Choose a framework" /> - + @@ -110,7 +109,7 @@ This guide will show you how to add a simple rate limit to your + @@ -124,7 +123,7 @@ In your project root, run the following command to install the SDK: [Create a free Arcjet account](https://app.arcjet.com) then follow the instructions to add a site and get a key. - + @@ -140,7 +139,7 @@ identify the user based on their ID e.g. if they are logged in. The bucket is configured with a maximum capacity of 10 tokens and refills by 5 tokens every 10 seconds. Each request consumes 5 tokens. - + @@ -149,7 +148,7 @@ configured with a maximum capacity of 10 tokens and refills by 5 tokens every - + diff --git a/src/content/docs/rate-limiting/reference.mdx b/src/content/docs/rate-limiting/reference.mdx index c8a51322..a05abfed 100644 --- a/src/content/docs/rate-limiting/reference.mdx +++ b/src/content/docs/rate-limiting/reference.mdx @@ -96,9 +96,9 @@ ajToc: import { Badge, Aside } from "@astrojs/starlight/components"; import { Link } from "@/components/link"; -import SlotByFramework from "@/components/SlotByFramework"; -import TextByFramework from "@/components/TextByFramework"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import TextByFramework from "@/components/TextByFramework.astro"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import { frameworks } from "@/lib/prefs"; import Comments from "/src/components/Comments.astro"; @@ -168,7 +168,6 @@ Arcjet rate limiting allows you to define rules which limit the number of requests a client can make over a period of time. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -206,7 +205,7 @@ type FixedWindowRateLimitOptions = { #### Fixed window example - + @@ -241,7 +240,7 @@ type SlidingWindowRateLimitOptions = { #### Sliding window example - + @@ -287,7 +286,7 @@ tokens it wishes to withdraw from the bucket. This is done by passing a See the [token bucket request example](#token-bucket-request) for how to specify the number of tokens to request. - + @@ -326,7 +325,7 @@ The custom characteristic is `userId` with the value passed as a prop on the `protect` function. You can use any string for the characteristic name and any `string`, `number` or `boolean` for the value. - + @@ -340,7 +339,7 @@ users and a user ID for logged in users, you can use `withRule` to create augmented clients that use different characteristics. See the example in the custom characteristics section. - + @@ -354,7 +353,7 @@ Arcjet provides a single `protect` function that is used to execute your protection rules. This requires a `RequestEvent` property which is the event context as passed to the request handler. - + @@ -388,7 +387,7 @@ for (const result of decision.results) { This example will log the full result as well as each rate limit rule: - + @@ -403,7 +402,7 @@ When using a token bucket rule, an additional `requested` prop (positive integer) should be passed to the `protect` function. This is the number of tokens the client is requesting to withdraw from the bucket. - + @@ -433,7 +432,7 @@ We provide the [@arcjet/decorate package](https://github.com/arcjet/arcjet-js/tree/main/decorate) for decorating your responses with appropriate `RateLimit` headers based on a decision. - + @@ -467,7 +466,7 @@ error result for more information. If all other rules that were run returned an `ALLOW` result, then the final Arcjet conclusion will be `ERROR`. - + @@ -488,7 +487,7 @@ Arcjet can also be triggered based using a sample of your traffic. See the Testing section of the docs for details. - + diff --git a/src/content/docs/sdk/bun/plus/hono/get-started.mdx b/src/content/docs/sdk/bun/plus/hono/get-started.mdx new file mode 100644 index 00000000..36eb36b4 --- /dev/null +++ b/src/content/docs/sdk/bun/plus/hono/get-started.mdx @@ -0,0 +1,10 @@ +--- +title: "Get started with Bun + Hono" +description: "Getting started with Arcjet and Bun + Hono." +prev: false +next: false +--- + +import Guide from "@/content/docs/get-started.mdx"; + + diff --git a/src/content/docs/sdk/node/plus/express/get-started.mdx b/src/content/docs/sdk/node/plus/express/get-started.mdx new file mode 100644 index 00000000..7f7a934a --- /dev/null +++ b/src/content/docs/sdk/node/plus/express/get-started.mdx @@ -0,0 +1,10 @@ +--- +title: "Get started with Node.js + Express" +description: "Getting started with Arcjet and Node.js + Express." +prev: false +next: false +--- + +import Guide from "@/content/docs/get-started.mdx"; + + diff --git a/src/content/docs/sdk/node/plus/hono/get-started.mdx b/src/content/docs/sdk/node/plus/hono/get-started.mdx new file mode 100644 index 00000000..d0920bec --- /dev/null +++ b/src/content/docs/sdk/node/plus/hono/get-started.mdx @@ -0,0 +1,10 @@ +--- +title: "Get started with Node.js + Hono" +description: "Getting started with Arcjet and Node.js + Hono." +prev: false +next: false +--- + +import Guide from "@/content/docs/get-started.mdx"; + + diff --git a/src/content/docs/sdk/python/plus/fastapi/get-started.mdx b/src/content/docs/sdk/python/plus/fastapi/get-started.mdx new file mode 100644 index 00000000..68473c1e --- /dev/null +++ b/src/content/docs/sdk/python/plus/fastapi/get-started.mdx @@ -0,0 +1,10 @@ +--- +title: "Get started with Python + FastAPI" +description: "Getting started with Arcjet and Python + FastAPI." +prev: false +next: false +--- + +import Guide from "@/content/docs/get-started.mdx"; + + diff --git a/src/content/docs/sdk/python/plus/flask/get-started.mdx b/src/content/docs/sdk/python/plus/flask/get-started.mdx new file mode 100644 index 00000000..83fc588e --- /dev/null +++ b/src/content/docs/sdk/python/plus/flask/get-started.mdx @@ -0,0 +1,10 @@ +--- +title: "Get started with Python + Flask" +description: "Getting started with Arcjet and Python + Flask." +prev: false +next: false +--- + +import Guide from "@/content/docs/get-started.mdx"; + + diff --git a/src/content/docs/sensitive-info/quick-start.mdx b/src/content/docs/sensitive-info/quick-start.mdx index e889df49..ecd45c7f 100644 --- a/src/content/docs/sensitive-info/quick-start.mdx +++ b/src/content/docs/sensitive-info/quick-start.mdx @@ -42,8 +42,8 @@ ajToc: import { CardGrid } from "@astrojs/starlight/components"; import { Link } from "@/components/link"; import WhatIsArcjet from "/src/components/WhatIsArcjet.astro"; -import SlotByFramework from "@/components/SlotByFramework"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import FrameworkName from "@/components/FrameworkName"; import { frameworks } from "@/lib/prefs"; import FAQs from "/src/components/FAQs.astro"; @@ -82,7 +82,6 @@ you do not wish to handle. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -98,7 +97,7 @@ app. In your project root, run the following command to install the SDK: - + @@ -113,7 +112,7 @@ In your project root, run the following command to install the SDK: instructions to add a site and get a key. Add it to a `.env.local` file in your project root. - + @@ -129,7 +128,7 @@ credit/debit card numbers, IP addresses, phone numbers, and/or implement a custom detection function. See the reference for details. - + @@ -143,7 +142,7 @@ custom detection function. See the Start your app and try making a request with an email address in the body of the request: - + diff --git a/src/content/docs/sensitive-info/reference.mdx b/src/content/docs/sensitive-info/reference.mdx index a38fc2a8..c245848e 100644 --- a/src/content/docs/sensitive-info/reference.mdx +++ b/src/content/docs/sensitive-info/reference.mdx @@ -62,9 +62,9 @@ ajToc: import { Badge } from "@astrojs/starlight/components"; import { Link } from "@/components/link"; -import SlotByFramework from "@/components/SlotByFramework"; -import TextByFramework from "@/components/TextByFramework"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import TextByFramework from "@/components/TextByFramework.astro"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import DisplayType from "@/components/DisplayType.astro"; import { frameworks } from "@/lib/prefs"; @@ -100,7 +100,6 @@ Arcjet Sensitive Information Detection protects against clients sending you sensitive information such as PII that you do not wish to handle. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -152,7 +151,7 @@ execution ordering is automatically optimized for performance. See [decision](#decision) below for details of examining the execution results. ::: - + @@ -164,7 +163,7 @@ execution ordering is automatically optimized for performance. See Arcjet provides a single `protect` function that is used to execute your protection rules. - + @@ -198,7 +197,7 @@ for (const result of decision.results) { This example will log the full result as well as the sensitive info rule: - + @@ -268,7 +267,7 @@ to the function is controlled by the `contextWindowSize` option, which defaults to 1. If you need additional context to perform detections then you can increase this value. - + @@ -293,7 +292,7 @@ error result for more information. If all other rules that were run returned an `ALLOW` result, then the final Arcjet conclusion will be `ERROR`. - + diff --git a/src/content/docs/shield/quick-start.mdx b/src/content/docs/shield/quick-start.mdx index bb4ef608..53beb607 100644 --- a/src/content/docs/shield/quick-start.mdx +++ b/src/content/docs/shield/quick-start.mdx @@ -43,8 +43,8 @@ ajToc: --- import FrameworkName from "@/components/FrameworkName"; -import SlotByFramework from "@/components/SlotByFramework"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import { frameworks } from "@/lib/prefs"; import { Link } from "@/components/link"; import { CardGrid } from "@astrojs/starlight/components"; @@ -86,7 +86,6 @@ the [OWASP Top 10](https://owasp.org/www-project-top-ten/). !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -102,7 +101,7 @@ application from common attacks. In your project root, run the following command to install the SDK: - + @@ -117,7 +116,7 @@ In your project root, run the following command to install the SDK: instructions to add a site and get a key. Add it to a `.env.local` file in your project root. - + @@ -128,7 +127,7 @@ project root. ### 3. Protect a route - + @@ -137,7 +136,7 @@ project root. - + @@ -153,7 +152,7 @@ To see Arcjet Shield WAF in action, try making a request with the special header triggered and will block the request. This simulates the threshold being reached and is a constant, so you can use it as part of your tests. - + diff --git a/src/content/docs/shield/reference.mdx b/src/content/docs/shield/reference.mdx index d7af5d7e..8d3282b6 100644 --- a/src/content/docs/shield/reference.mdx +++ b/src/content/docs/shield/reference.mdx @@ -61,9 +61,9 @@ ajToc: import { Badge } from "@astrojs/starlight/components"; import { Link } from "@/components/link"; -import SlotByFramework from "@/components/SlotByFramework"; -import TextByFramework from "@/components/TextByFramework"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import TextByFramework from "@/components/TextByFramework.astro"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import DisplayType from "@/components/DisplayType.astro"; import { frameworks } from "@/lib/prefs"; @@ -91,7 +91,6 @@ Arcjet Shield WAF protects your application against common attacks, including the [OWASP Top 10](https://owasp.org/www-project-top-ten/). !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -115,7 +114,7 @@ execution ordering is automatically optimized for performance. See [decision](#decision) below for details of examining the execution results. ::: - + @@ -129,7 +128,7 @@ Arcjet provides a single `protect` function that is used to execute your protection rules. This requires a `RequestEvent` property which is the event context as passed to the request handler. - + @@ -163,7 +162,7 @@ for (const result of decision.results) { This example will log the full result as well as the shield rule: - + @@ -186,7 +185,7 @@ error result for more information. If all other rules that were run returned an `ALLOW` result, then the final Arcjet conclusion will be `ERROR`. - + diff --git a/src/content/docs/signup-protection/quick-start.mdx b/src/content/docs/signup-protection/quick-start.mdx index c55e41a9..b6411741 100644 --- a/src/content/docs/signup-protection/quick-start.mdx +++ b/src/content/docs/signup-protection/quick-start.mdx @@ -42,9 +42,9 @@ ajToc: import { CardGrid } from "@astrojs/starlight/components"; import WhatIsArcjet from "/src/components/WhatIsArcjet.astro"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import { Link } from "@/components/link"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import FrameworkName from "@/components/FrameworkName"; import { frameworks } from "@/lib/prefs"; import SdkReferenceLinkByFramework from "/src/components/SdkReferenceLinkByFramework.astro"; @@ -77,7 +77,6 @@ Arcjet signup form protection combines rate limiting, bot protection, and email !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -92,7 +91,7 @@ This guide will show you how to protect your signu In your project root, run the following command to install the SDK: - + @@ -106,7 +105,7 @@ In your project root, run the following command to install the SDK: [Create a free Arcjet account](https://app.arcjet.com) then follow the instructions to add a site and get a key. Add it to a `.env.local` file in your project root. - + @@ -126,7 +125,7 @@ primitives. These are configured using our recommended rules. The example below is a simple email form. You could adapt this as part of a signup form. - + @@ -135,7 +134,7 @@ signup form. - + diff --git a/src/content/docs/signup-protection/reference.mdx b/src/content/docs/signup-protection/reference.mdx index 65b1e9e6..557c0d74 100644 --- a/src/content/docs/signup-protection/reference.mdx +++ b/src/content/docs/signup-protection/reference.mdx @@ -30,10 +30,10 @@ ajToc: --- import { Badge } from "@astrojs/starlight/components"; -import SlotByFramework from "@/components/SlotByFramework"; -import TextByFramework from "@/components/TextByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; +import TextByFramework from "@/components/TextByFramework.astro"; import { Link } from "@/components/link"; -import FrameworkLinks from "@/components/FrameworkLinks"; +import FrameworkLinks from "@/components/FrameworkLinks.astro"; import { frameworks } from "@/lib/prefs"; import Comments from "/src/components/Comments.astro"; @@ -65,7 +65,6 @@ Arcjet signup form protection combines rate limiting, bot protection, and email validation to protect your signup forms from abuse. !frontmatter.frameworks.includes(d.key)) .map((d) => d.key)} @@ -105,7 +104,7 @@ Our recommended configuration for most signup forms is: This can be configured as follows: - + @@ -126,7 +125,7 @@ Even in dry run mode each rule will still be evaluated, so you can still [check the rule results](#checking-rule-results) to see if the email address is valid or not, or log them to your database. - + @@ -137,7 +136,7 @@ protection rules. This requires a `request` argument which is the request context as passed to the request handler. When configured with a `protectSignup` rule it also requires an additional `email` prop. - + @@ -189,7 +188,7 @@ own verification logic. For example, you could decide to manually verify user signups that come from IP addresses associated with proxies or Tor, and any users who sign up with a free email address. - + @@ -212,7 +211,7 @@ error result for more information. If all other rules that were run returned an `ALLOW` result, then the final Arcjet conclusion will be `ERROR`. - + diff --git a/src/lib/sdk.ts b/src/lib/sdk.ts index b7250383..ed390b42 100644 --- a/src/lib/sdk.ts +++ b/src/lib/sdk.ts @@ -20,6 +20,64 @@ export type ArcjetSdkKey = | "remix" | "sveltekit"; +/** + * A sub-variant of an SDK that uses the same Arcjet SDK package but + * pairs it with a different framework (e.g. Bun + Hono, Node.js + Express). + */ +export type ArcjetSdkVariant = { + /** URL-safe key used in `/sdk/:sdk/plus/:variant/` paths */ + readonly key: string; + /** Human readable label */ + readonly label: string; + /** Maps to a legacy FrameworkKey for slot resolution */ + readonly legacyFrameworkKey: FrameworkKey; +}; + +/** + * Sub-variants for SDKs that support multiple framework pairings. + */ +const SDK_VARIANTS: Partial> = + { + bun: [{ key: "hono", label: "Hono", legacyFrameworkKey: "bun-hono" }], + node: [ + { + key: "express", + label: "Express", + legacyFrameworkKey: "node-js-express", + }, + { key: "hono", label: "Hono", legacyFrameworkKey: "node-js-hono" }, + ], + python: [ + { + key: "fastapi", + label: "FastAPI", + legacyFrameworkKey: "python-fastapi", + }, + { key: "flask", label: "Flask", legacyFrameworkKey: "python-flask" }, + ], + } as const; + +/** + * Returns the sub-variants for a given SDK, or an empty array if none. + */ +export function sdkVariants(sdkKey: ArcjetSdkKey): readonly ArcjetSdkVariant[] { + return SDK_VARIANTS[sdkKey] ?? []; +} + +/** + * Returns all SDKs that have sub-variants. + */ +export function sdksWithVariants(): [ + ArcjetSdkKey, + readonly ArcjetSdkVariant[], +][] { + // Object.entries widens keys to `string`; narrow back to ArcjetSdkKey. + return Object.entries(SDK_VARIANTS) as [ + ArcjetSdkKey, + readonly ArcjetSdkVariant[], + ][]; +} + /** * Documentation configuration object for an Arcjet SDK */ @@ -132,6 +190,47 @@ export function isSdkKey(value: string): value is ArcjetSdkKey { } const SDK_PATH_REGEX = /^\/sdk\/([a-z-]+)/; +const SDK_PLUS_PATH_REGEX = /^\/sdk\/([a-z-]+)\/plus\/([a-z-]+)/; + +/** + * Extracts an Arcjet SDK variant key from a `/sdk/:sdk/plus/:variant/` pathname. + * Returns `undefined` if the path is not a plus-variant route. + */ +export function sdkVariantFromPathname( + pathname: string, +): ArcjetSdkVariant | undefined { + if (typeof pathname !== "string") return undefined; + + const match = pathname.match(SDK_PLUS_PATH_REGEX); + if (!match) return undefined; + + const sdkKey = match[1]; + const variantKey = match[2]; + + if (!isSdkKey(sdkKey)) return undefined; + + const variants = SDK_VARIANTS[sdkKey]; + return variants?.find((v) => v.key === variantKey); +} + +/** + * Resolves the legacy FrameworkKey for the current SDK-scoped pathname. + * + * For plus-variant paths like `/sdk/bun/plus/hono/...`, returns the variant's + * legacy key (e.g. `"bun-hono"`). For plain SDK paths like `/sdk/next/...`, + * returns the SDK's legacy key (e.g. `"next-js"`). + */ +export function legacyKeyFromPathname( + pathname: string, +): FrameworkKey | undefined { + const variant = sdkVariantFromPathname(pathname); + if (variant) return variant.legacyFrameworkKey; + + const sdkKey = sdkFromPathname(pathname); + if (!sdkKey) return undefined; + + return ARCJET_SDKS[sdkKey].legacyFrameworkKey ?? undefined; +} /** * Extracts an Arcjet SDK key from a given pathname, if possible. @@ -160,8 +259,15 @@ export function sdkFromPathname(pathname: string): ArcjetSdkKey | undefined { /** * Returns a pathname scoped to the given SDK. + * + * If the current path is a plus-variant route (e.g. `/sdk/bun/plus/hono/foo`), + * the variant segment is stripped when switching to a different SDK because + * variants are SDK-specific. */ -export function pathnameForSdk(pathname: string, sdk: ArcjetSdkKey): string { +export function pathnameForSdk( + pathname: string, + targetSdk: ArcjetSdkKey, +): string { const previousSdk = sdkFromPathname(pathname); if (!previousSdk) { @@ -170,7 +276,48 @@ export function pathnameForSdk(pathname: string, sdk: ArcjetSdkKey): string { ); } - return pathname.replace(`/sdk/${previousSdk}`, `/sdk/${sdk}`); + // Strip any /plus/:variant/ segment since variants are SDK-specific + const plusVariant = sdkVariantFromPathname(pathname); + let cleanPathname = pathname; + if (plusVariant) { + cleanPathname = pathname.replace(`/plus/${plusVariant.key}`, ""); + } + + return cleanPathname.replace(`/sdk/${previousSdk}`, `/sdk/${targetSdk}`); +} + +/** + * Returns a pathname scoped to a specific SDK variant. + * + * @example + * pathnameForSdkVariant("/sdk/bun/get-started", "bun", "hono") + * // => "/sdk/bun/plus/hono/get-started" + */ +export function pathnameForSdkVariant( + pathname: string, + sdkKey: ArcjetSdkKey, + variantKey: string, +): string { + const previousSdk = sdkFromPathname(pathname); + + if (!previousSdk) { + throw new Error( + `@/lib/sdk:pathnameForSdkVariant only supports SDK scoped pathnames.`, + ); + } + + // Strip any existing /plus/:variant/ segment + const existingVariant = sdkVariantFromPathname(pathname); + let cleanPathname = pathname; + if (existingVariant) { + cleanPathname = pathname.replace(`/plus/${existingVariant.key}`, ""); + } + + // Replace SDK and inject variant + return cleanPathname.replace( + `/sdk/${previousSdk}`, + `/sdk/${sdkKey}/plus/${variantKey}`, + ); } /** diff --git a/src/snippets/bot-protection/reference/nextjs/PerRouteVsMiddleware.mdx b/src/snippets/bot-protection/reference/nextjs/PerRouteVsMiddleware.mdx index a3a8a20e..cff61d56 100644 --- a/src/snippets/bot-protection/reference/nextjs/PerRouteVsMiddleware.mdx +++ b/src/snippets/bot-protection/reference/nextjs/PerRouteVsMiddleware.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import MiddlewareNextJs from "./Middleware.mdx"; import PerRouteNextJs from "./PerRoute.mdx"; @@ -21,12 +21,12 @@ Bot protection rules can be configured in two ways: This configures bot protection on a single route. - + ### Middleware - + diff --git a/src/snippets/bot-protection/reference/remix/LoaderVsAction.mdx b/src/snippets/bot-protection/reference/remix/LoaderVsAction.mdx index 157c8b34..9b3cf8ba 100644 --- a/src/snippets/bot-protection/reference/remix/LoaderVsAction.mdx +++ b/src/snippets/bot-protection/reference/remix/LoaderVsAction.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import { Code } from "@astrojs/starlight/components"; import ActionTS from "./Action.ts?raw"; import ActionJS from "./Action.js?raw"; diff --git a/src/snippets/bot-protection/reference/sveltekit/PerRouteVsHooks.mdx b/src/snippets/bot-protection/reference/sveltekit/PerRouteVsHooks.mdx index d2acfd9d..9079568d 100644 --- a/src/snippets/bot-protection/reference/sveltekit/PerRouteVsHooks.mdx +++ b/src/snippets/bot-protection/reference/sveltekit/PerRouteVsHooks.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import Hooks from "./Hooks.mdx"; import PerRoute from "./PerRoute.mdx"; import { Code } from "@astrojs/starlight/components"; diff --git a/src/snippets/rate-limiting/reference/nextjs/PerRouteVsMiddleware.mdx b/src/snippets/rate-limiting/reference/nextjs/PerRouteVsMiddleware.mdx index 6959783d..9dfd348a 100644 --- a/src/snippets/rate-limiting/reference/nextjs/PerRouteVsMiddleware.mdx +++ b/src/snippets/rate-limiting/reference/nextjs/PerRouteVsMiddleware.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import MiddlewareMatchingPaths from "./MiddlewareMatchingPaths.mdx"; import MiddlewareAllRoutes from "./MiddlewareAllRoutes.mdx"; import MiddlewareMatcher from "./MiddlewareMatcher.mdx"; @@ -35,13 +35,13 @@ the middleware for, or use `request.nextUrl.pathname.startsWith`. You can use conditionals in your Next.js middleware to match multiple paths. - + #### Middleware - + @@ -56,6 +56,6 @@ For example, if you already have a rate limit defined in the API route at `/api/hello`, you can exclude it from the middleware by specifying a matcher in `/proxy.ts`: - + diff --git a/src/snippets/rate-limiting/reference/remix/LoaderVsAction.mdx b/src/snippets/rate-limiting/reference/remix/LoaderVsAction.mdx index d4258ec9..bbefba3a 100644 --- a/src/snippets/rate-limiting/reference/remix/LoaderVsAction.mdx +++ b/src/snippets/rate-limiting/reference/remix/LoaderVsAction.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import { Code } from "@astrojs/starlight/components"; import ActionTS from "./Action.ts?raw"; import ActionJS from "./Action.js?raw"; diff --git a/src/snippets/rate-limiting/reference/sveltekit/PerRouteVsHooks.mdx b/src/snippets/rate-limiting/reference/sveltekit/PerRouteVsHooks.mdx index 840004d6..8320000e 100644 --- a/src/snippets/rate-limiting/reference/sveltekit/PerRouteVsHooks.mdx +++ b/src/snippets/rate-limiting/reference/sveltekit/PerRouteVsHooks.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import HookMatchingPaths from "./HookMatchingPaths.mdx"; import HookAllRoutes from "./HookAllRoutes.mdx"; import HookMatcher from "./HookMatcher.mdx"; diff --git a/src/snippets/sensitive-info/reference/nextjs/PerRouteVsMiddleware.mdx b/src/snippets/sensitive-info/reference/nextjs/PerRouteVsMiddleware.mdx index a3af8e29..69b3f889 100644 --- a/src/snippets/sensitive-info/reference/nextjs/PerRouteVsMiddleware.mdx +++ b/src/snippets/sensitive-info/reference/nextjs/PerRouteVsMiddleware.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import MiddlewareNextJs from "./Middleware.mdx"; import PerRouteNextJs from "./PerRoute.mdx"; @@ -19,12 +19,12 @@ Bot protection rules can be configured in two ways: This configures bot protection on a single route. - + ### Middleware - + diff --git a/src/snippets/sensitive-info/reference/sveltekit/PerRouteVsHooks.mdx b/src/snippets/sensitive-info/reference/sveltekit/PerRouteVsHooks.mdx index 94fac243..fc4315aa 100644 --- a/src/snippets/sensitive-info/reference/sveltekit/PerRouteVsHooks.mdx +++ b/src/snippets/sensitive-info/reference/sveltekit/PerRouteVsHooks.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import Hooks from "./Hooks.mdx"; import PerRoute from "./PerRoute.mdx"; import { Code } from "@astrojs/starlight/components"; diff --git a/src/snippets/shield/reference/nextjs/PerRouteVsMiddleware.mdx b/src/snippets/shield/reference/nextjs/PerRouteVsMiddleware.mdx index e58d5308..bf11a58d 100644 --- a/src/snippets/shield/reference/nextjs/PerRouteVsMiddleware.mdx +++ b/src/snippets/shield/reference/nextjs/PerRouteVsMiddleware.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import MiddlewareNextJs from "./Middleware.mdx"; import PerRouteNextJs from "./PerRoute.mdx"; diff --git a/src/snippets/shield/reference/remix/LoaderVsAction.mdx b/src/snippets/shield/reference/remix/LoaderVsAction.mdx index f236a341..e5761888 100644 --- a/src/snippets/shield/reference/remix/LoaderVsAction.mdx +++ b/src/snippets/shield/reference/remix/LoaderVsAction.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import { Code } from "@astrojs/starlight/components"; import ActionTS from "./Action.ts?raw"; import ActionJS from "./Action.js?raw"; diff --git a/src/snippets/shield/reference/sveltekit/PerRouteVsHooks.mdx b/src/snippets/shield/reference/sveltekit/PerRouteVsHooks.mdx index d2a92ace..f13f866c 100644 --- a/src/snippets/shield/reference/sveltekit/PerRouteVsHooks.mdx +++ b/src/snippets/shield/reference/sveltekit/PerRouteVsHooks.mdx @@ -1,5 +1,5 @@ import SelectableContent from "@/components/SelectableContent"; -import SlotByFramework from "@/components/SlotByFramework"; +import SlotByFramework from "@/components/SlotByFramework.astro"; import Hooks from "./Hooks.mdx"; import PerRoute from "./PerRoute.mdx"; import { Code } from "@astrojs/starlight/components"; diff --git a/tests/sdk-routes.test.ts b/tests/sdk-routes.test.ts new file mode 100644 index 00000000..35bf16e1 --- /dev/null +++ b/tests/sdk-routes.test.ts @@ -0,0 +1,257 @@ +import { expect, test, type Page } from "@playwright/test"; +import { sdks, sdkVariants } from "@/lib/sdk"; + +/** + * Validates that per-SDK route pages (`/sdk/:sdk/...`) render the same main + * content as the legacy `?f=` pages. + * + * The right sidebar (TOC / SDK switcher) will differ, so we only screenshot + * the `
` element. + */ + +// These pages are heavy — give each test plenty of time. +test.setTimeout(60_000); + +interface SdkRouteEntry { + /** Legacy `?f=` framework key */ + legacyKey: string; + /** New SDK-scoped route prefix, e.g. "/sdk/next" or "/sdk/bun/plus/hono" */ + sdkPrefix: string; +} + +const SDK_ROUTE_ENTRIES: SdkRouteEntry[] = []; +for (const sdk of sdks()) { + if (sdk.legacyFrameworkKey) { + SDK_ROUTE_ENTRIES.push({ + legacyKey: sdk.legacyFrameworkKey, + sdkPrefix: `/sdk/${sdk.key}`, + }); + } + for (const variant of sdkVariants(sdk.key)) { + SDK_ROUTE_ENTRIES.push({ + legacyKey: variant.legacyFrameworkKey, + sdkPrefix: `/sdk/${sdk.key}/plus/${variant.key}`, + }); + } +} + +interface PageSpec { + /** Path without leading `/sdk/…` prefix, e.g. "/get-started" */ + path: string; + /** + * Subset of legacy framework keys this page supports. + * When omitted, all entries from SDK_ROUTE_ENTRIES are tested. + */ + frameworks?: readonly string[]; +} + +const PAGES: readonly PageSpec[] = [ + { + path: "/get-started", + frameworks: [ + "astro", + "bun", + "bun-hono", + "deno", + "fastify", + "nest-js", + "next-js", + "node-js", + "node-js-express", + "node-js-hono", + "nuxt", + "python-fastapi", + "python-flask", + "react-router", + "remix", + "sveltekit", + ], + }, + { + path: "/bot-protection/quick-start", + frameworks: [ + "astro", + "bun", + "deno", + "nest-js", + "next-js", + "node-js", + "nuxt", + "remix", + "sveltekit", + ], + }, + { + path: "/bot-protection/reference", + frameworks: [ + "bun", + "deno", + "nest-js", + "next-js", + "node-js", + "remix", + "sveltekit", + ], + }, + { + path: "/email-validation/quick-start", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, + { + path: "/email-validation/reference", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, + { + path: "/filters/quick-start", + frameworks: [ + "astro", + "bun", + "deno", + "fastify", + "nest-js", + "next-js", + "node-js", + "react-router", + "remix", + "sveltekit", + ], + }, + { + path: "/filters/reference", + frameworks: [ + "bun", + "deno", + "nest-js", + "next-js", + "node-js", + "remix", + "sveltekit", + ], + }, + { + path: "/nosecone/quick-start", + frameworks: ["bun", "deno", "next-js", "node-js", "sveltekit"], + }, + { + path: "/rate-limiting/quick-start", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, + { + path: "/rate-limiting/reference", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, + { + path: "/sensitive-info/quick-start", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, + { + path: "/sensitive-info/reference", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, + { + path: "/shield/quick-start", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, + { + path: "/shield/reference", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, + { + path: "/signup-protection/quick-start", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, + { + path: "/signup-protection/reference", + frameworks: ["bun", "nest-js", "next-js", "node-js", "remix", "sveltekit"], + }, +]; + +/** Remove elements that cause non-deterministic rendering. */ +async function sanitizePage(page: Page) { + // Hide rather than remove — works even with JS disabled. + const selectors = ["astro-dev-toolbar", "lite-youtube", "div.giscus"]; + + for (const sel of selectors) { + for (const el of await page.locator(sel).all()) { + await el.evaluate((node) => (node.style.display = "none")); + } + } +} + +/** + * Screenshot the `
` element after sanitisation. + * + * Returns the screenshot buffer so the caller can compare two of them. + */ +async function screenshotMain(page: Page): Promise { + await sanitizePage(page); + + const main = page.locator("main"); + await main.waitFor({ state: "visible" }); + + return (await main.screenshot()) as Buffer; +} + +/** + * Wait for Astro islands to hydrate. + * + * On legacy pages `SlotByFrameworkReact` renders a `.Skeleton` placeholder + * until hydration. On *both* legacy and SDK pages, `SelectableContent` + * islands need to hydrate before their tabbed content becomes visible. + * + * We wait for all `astro-island` elements inside `
` to drop their + * `ssr` attribute, which Astro removes once an island has hydrated. + */ +async function waitForHydration(page: Page) { + await page + .locator("main astro-island[ssr]") + .first() + .waitFor({ state: "detached", timeout: 15_000 }) + .catch(() => { + // No un-hydrated islands — that's fine. + }); + + // Give a short extra beat for any re-renders to settle. + await page.waitForTimeout(500); +} + +for (const spec of PAGES) { + const entries = spec.frameworks + ? SDK_ROUTE_ENTRIES.filter((e) => spec.frameworks!.includes(e.legacyKey)) + : SDK_ROUTE_ENTRIES; + + test.describe(`Main-content parity: ${spec.path}`, () => { + for (const { legacyKey, sdkPrefix } of entries) { + const legacyUrl = `${spec.path}?f=${legacyKey}`; + const sdkUrl = `${sdkPrefix}${spec.path}`; + const safeName = `${spec.path.slice(1).replaceAll("/", "-")}-${legacyKey}`; + + test(`${legacyUrl} vs ${sdkUrl}`, async ({ page }) => { + const legacyRes = await page.goto(legacyUrl, { + waitUntil: "networkidle", + }); + expect(legacyRes?.ok(), `Legacy page ${legacyUrl} failed`).toBeTruthy(); + await waitForHydration(page); + + const legacyShot = await screenshotMain(page); + + const sdkRes = await page.goto(sdkUrl, { + waitUntil: "networkidle", + }); + expect(sdkRes?.ok(), `SDK page ${sdkUrl} failed`).toBeTruthy(); + await waitForHydration(page); + + const sdkShot = await screenshotMain(page); + + expect(sdkShot).toMatchSnapshot(`sdk-parity-${safeName}.png`, { + maxDiffPixels: 200, + threshold: 0.15, + }); + expect(legacyShot).toMatchSnapshot(`sdk-parity-${safeName}.png`, { + maxDiffPixels: 200, + threshold: 0.15, + }); + }); + } + }); +} diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-astro-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-astro-chromium-linux.png new file mode 100644 index 00000000..44a6a2cf Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-astro-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-bun-chromium-linux.png new file mode 100644 index 00000000..3e6bd517 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-deno-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-deno-chromium-linux.png new file mode 100644 index 00000000..0b6e3989 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-deno-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-nest-js-chromium-linux.png new file mode 100644 index 00000000..48538aed Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-next-js-chromium-linux.png new file mode 100644 index 00000000..5fe2f830 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-node-js-chromium-linux.png new file mode 100644 index 00000000..3caaeed9 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-nuxt-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-nuxt-chromium-linux.png new file mode 100644 index 00000000..581d7254 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-nuxt-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-remix-chromium-linux.png new file mode 100644 index 00000000..57253d15 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-sveltekit-chromium-linux.png new file mode 100644 index 00000000..3668fc46 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-quick-start-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-bun-chromium-linux.png new file mode 100644 index 00000000..6a45b893 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-deno-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-deno-chromium-linux.png new file mode 100644 index 00000000..8733ca72 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-deno-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-nest-js-chromium-linux.png new file mode 100644 index 00000000..c6e8798f Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-next-js-chromium-linux.png new file mode 100644 index 00000000..211b8ea5 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-node-js-chromium-linux.png new file mode 100644 index 00000000..e524b16a Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-remix-chromium-linux.png new file mode 100644 index 00000000..d28c7017 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-sveltekit-chromium-linux.png new file mode 100644 index 00000000..0d449403 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-bot-protection-reference-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-bun-chromium-linux.png new file mode 100644 index 00000000..d378ba2a Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-nest-js-chromium-linux.png new file mode 100644 index 00000000..0448225d Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-next-js-chromium-linux.png new file mode 100644 index 00000000..e76b6eac Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-node-js-chromium-linux.png new file mode 100644 index 00000000..11231c78 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-remix-chromium-linux.png new file mode 100644 index 00000000..c5dfe545 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-sveltekit-chromium-linux.png new file mode 100644 index 00000000..180cd163 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-quick-start-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-bun-chromium-linux.png new file mode 100644 index 00000000..6cee0b7d Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-nest-js-chromium-linux.png new file mode 100644 index 00000000..b32129f1 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-next-js-chromium-linux.png new file mode 100644 index 00000000..7683f43f Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-node-js-chromium-linux.png new file mode 100644 index 00000000..527e7f1d Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-remix-chromium-linux.png new file mode 100644 index 00000000..9d54804b Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-sveltekit-chromium-linux.png new file mode 100644 index 00000000..68d8fa45 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-email-validation-reference-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-astro-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-astro-chromium-linux.png new file mode 100644 index 00000000..8c911a8b Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-astro-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-bun-chromium-linux.png new file mode 100644 index 00000000..103f2d9b Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-deno-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-deno-chromium-linux.png new file mode 100644 index 00000000..23aa3bc2 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-deno-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-fastify-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-fastify-chromium-linux.png new file mode 100644 index 00000000..1e52c904 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-fastify-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-nest-js-chromium-linux.png new file mode 100644 index 00000000..f8c68f19 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-next-js-chromium-linux.png new file mode 100644 index 00000000..2066d811 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-node-js-chromium-linux.png new file mode 100644 index 00000000..e2e85a58 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-react-router-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-react-router-chromium-linux.png new file mode 100644 index 00000000..06998812 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-react-router-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-remix-chromium-linux.png new file mode 100644 index 00000000..d79078f7 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-sveltekit-chromium-linux.png new file mode 100644 index 00000000..2b03468e Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-quick-start-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-bun-chromium-linux.png new file mode 100644 index 00000000..fe114e8c Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-deno-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-deno-chromium-linux.png new file mode 100644 index 00000000..442e63b8 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-deno-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-nest-js-chromium-linux.png new file mode 100644 index 00000000..536caf43 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-next-js-chromium-linux.png new file mode 100644 index 00000000..312abc1f Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-node-js-chromium-linux.png new file mode 100644 index 00000000..19e06ec7 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-remix-chromium-linux.png new file mode 100644 index 00000000..c40e3c3e Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-sveltekit-chromium-linux.png new file mode 100644 index 00000000..e3e83d2d Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-filters-reference-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-astro-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-astro-chromium-linux.png new file mode 100644 index 00000000..0e3a5680 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-astro-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-bun-chromium-linux.png new file mode 100644 index 00000000..2d9e635c Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-bun-hono-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-bun-hono-chromium-linux.png new file mode 100644 index 00000000..bb18e2e6 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-bun-hono-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-deno-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-deno-chromium-linux.png new file mode 100644 index 00000000..2734c35c Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-deno-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-fastify-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-fastify-chromium-linux.png new file mode 100644 index 00000000..2692b5b4 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-fastify-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-nest-js-chromium-linux.png new file mode 100644 index 00000000..72c1e18e Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-next-js-chromium-linux.png new file mode 100644 index 00000000..c6f644a3 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-node-js-chromium-linux.png new file mode 100644 index 00000000..ade053e7 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-node-js-express-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-node-js-express-chromium-linux.png new file mode 100644 index 00000000..a6853aa2 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-node-js-express-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-node-js-hono-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-node-js-hono-chromium-linux.png new file mode 100644 index 00000000..60c9e756 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-node-js-hono-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-nuxt-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-nuxt-chromium-linux.png new file mode 100644 index 00000000..15944fae Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-nuxt-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-python-fastapi-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-python-fastapi-chromium-linux.png new file mode 100644 index 00000000..8fe08e38 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-python-fastapi-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-python-flask-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-python-flask-chromium-linux.png new file mode 100644 index 00000000..66082a90 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-python-flask-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-react-router-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-react-router-chromium-linux.png new file mode 100644 index 00000000..f7624101 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-react-router-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-remix-chromium-linux.png new file mode 100644 index 00000000..a1dfef98 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-sveltekit-chromium-linux.png new file mode 100644 index 00000000..0d57da00 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-get-started-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-bun-chromium-linux.png new file mode 100644 index 00000000..1cfd064d Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-deno-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-deno-chromium-linux.png new file mode 100644 index 00000000..2169b2d7 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-deno-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-next-js-chromium-linux.png new file mode 100644 index 00000000..0b5c2aa3 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-node-js-chromium-linux.png new file mode 100644 index 00000000..0540a49f Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-sveltekit-chromium-linux.png new file mode 100644 index 00000000..e5826a10 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-nosecone-quick-start-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-bun-chromium-linux.png new file mode 100644 index 00000000..80072bc9 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-nest-js-chromium-linux.png new file mode 100644 index 00000000..d273ec3d Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-next-js-chromium-linux.png new file mode 100644 index 00000000..4b0ec5b1 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-node-js-chromium-linux.png new file mode 100644 index 00000000..6306eeff Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-remix-chromium-linux.png new file mode 100644 index 00000000..3bae37f6 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-sveltekit-chromium-linux.png new file mode 100644 index 00000000..d03d6383 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-quick-start-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-bun-chromium-linux.png new file mode 100644 index 00000000..cb2e0f8c Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-nest-js-chromium-linux.png new file mode 100644 index 00000000..f4958d4b Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-next-js-chromium-linux.png new file mode 100644 index 00000000..1c793eb5 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-node-js-chromium-linux.png new file mode 100644 index 00000000..b380d5c3 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-remix-chromium-linux.png new file mode 100644 index 00000000..8fc68ec4 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-sveltekit-chromium-linux.png new file mode 100644 index 00000000..38c337a6 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-rate-limiting-reference-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-bun-chromium-linux.png new file mode 100644 index 00000000..b82bd865 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-nest-js-chromium-linux.png new file mode 100644 index 00000000..7303383d Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-next-js-chromium-linux.png new file mode 100644 index 00000000..13988a0c Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-node-js-chromium-linux.png new file mode 100644 index 00000000..9e87cfa4 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-remix-chromium-linux.png new file mode 100644 index 00000000..70ffb031 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-sveltekit-chromium-linux.png new file mode 100644 index 00000000..6e3f1574 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-quick-start-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-bun-chromium-linux.png new file mode 100644 index 00000000..3660fd28 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-nest-js-chromium-linux.png new file mode 100644 index 00000000..c5c82dbd Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-next-js-chromium-linux.png new file mode 100644 index 00000000..6d169e75 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-node-js-chromium-linux.png new file mode 100644 index 00000000..7d795059 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-remix-chromium-linux.png new file mode 100644 index 00000000..1f3a7fc0 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-sveltekit-chromium-linux.png new file mode 100644 index 00000000..9b298fd4 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-sensitive-info-reference-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-bun-chromium-linux.png new file mode 100644 index 00000000..bb61c878 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-nest-js-chromium-linux.png new file mode 100644 index 00000000..c55d7c25 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-next-js-chromium-linux.png new file mode 100644 index 00000000..b4cfccaf Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-node-js-chromium-linux.png new file mode 100644 index 00000000..fe303d7e Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-remix-chromium-linux.png new file mode 100644 index 00000000..af699749 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-sveltekit-chromium-linux.png new file mode 100644 index 00000000..892e1bf5 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-quick-start-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-bun-chromium-linux.png new file mode 100644 index 00000000..8c8abb2a Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-nest-js-chromium-linux.png new file mode 100644 index 00000000..a141db78 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-next-js-chromium-linux.png new file mode 100644 index 00000000..618cdb6e Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-node-js-chromium-linux.png new file mode 100644 index 00000000..3cad954b Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-remix-chromium-linux.png new file mode 100644 index 00000000..7ae8c73f Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-sveltekit-chromium-linux.png new file mode 100644 index 00000000..a3b7f815 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-shield-reference-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-bun-chromium-linux.png new file mode 100644 index 00000000..cccebf4b Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-nest-js-chromium-linux.png new file mode 100644 index 00000000..969836f2 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-next-js-chromium-linux.png new file mode 100644 index 00000000..fba63e83 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-node-js-chromium-linux.png new file mode 100644 index 00000000..eba2092f Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-remix-chromium-linux.png new file mode 100644 index 00000000..ed3934ba Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-sveltekit-chromium-linux.png new file mode 100644 index 00000000..f3c507a0 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-quick-start-sveltekit-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-bun-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-bun-chromium-linux.png new file mode 100644 index 00000000..f37722f1 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-bun-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-nest-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-nest-js-chromium-linux.png new file mode 100644 index 00000000..8262a56f Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-nest-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-next-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-next-js-chromium-linux.png new file mode 100644 index 00000000..5d1c7291 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-next-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-node-js-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-node-js-chromium-linux.png new file mode 100644 index 00000000..02efd54c Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-node-js-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-remix-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-remix-chromium-linux.png new file mode 100644 index 00000000..259871d6 Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-remix-chromium-linux.png differ diff --git a/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-sveltekit-chromium-linux.png b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-sveltekit-chromium-linux.png new file mode 100644 index 00000000..397ae6bd Binary files /dev/null and b/tests/sdk-routes.test.ts-snapshots/sdk-parity-signup-protection-reference-sveltekit-chromium-linux.png differ