diff --git a/astro.config.ts b/astro.config.ts index 9972119136db60..5b9d3887cd2be5 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -160,6 +160,7 @@ export default defineConfig({ markdown: { headingLinks: false, }, + routeMiddleware: "./src/plugins/starlight/route-data.ts", }), liveCode({}), icon(), diff --git a/src/components/TagsUsage.astro b/src/components/TagsUsage.astro index da5e31b0ba2bc5..90fb598b2f045b 100644 --- a/src/components/TagsUsage.astro +++ b/src/components/TagsUsage.astro @@ -1,5 +1,7 @@ --- import { getCollection } from "astro:content"; +import { tags as allowedTags } from "~/schemas/tags"; + import AnchorHeading from "./AnchorHeading.astro"; import Details from "./Details.astro"; @@ -13,28 +15,57 @@ for (const entry of entries) { byTag[tag].push(entry.id); } } + +const flattened = Object.values(allowedTags).flat(); --- { Object.entries(byTag) .sort() - .map(([tag, pages]) => ( - <> - -

- {tag} is used on {pages.length} pages. -

-
-
- - )) + )} +

+ Used on {pages.length}{" "} + pages. +

+
+ +
+ + ); + }) } diff --git a/src/content/docs/kv/examples/cache-data-with-workers-kv.mdx b/src/content/docs/kv/examples/cache-data-with-workers-kv.mdx index 4334eea7426fbc..48f201646437a9 100644 --- a/src/content/docs/kv/examples/cache-data-with-workers-kv.mdx +++ b/src/content/docs/kv/examples/cache-data-with-workers-kv.mdx @@ -1,8 +1,6 @@ --- type: example summary: Cache data or API responses in Workers KV to improve application performance -tags: - - KV pcx_content_type: configuration title: Cache data with Workers KV sidebar: diff --git a/src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx b/src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx index 27bf6d07291237..845d036b60d278 100644 --- a/src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx +++ b/src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx @@ -1,8 +1,6 @@ --- type: example summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application -tags: - - KV pcx_content_type: configuration title: Build a distributed configuration store sidebar: @@ -19,7 +17,7 @@ In this example, application configuration data is used to personalize the Worke ## Write your configuration from your external application to Workers KV In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV. -If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. +If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. The following external Node.js application demonstrates a simple scripts that reads user data from a database and writes it to Workers KV using the REST API library. @@ -31,8 +29,8 @@ const { Cloudflare } = require('cloudflare'); const { backOff } = require('exponential-backoff'); if(!process.env.DATABASE_CONNECTION_STRING || !process.env.CLOUDFLARE_EMAIL || !process.env.CLOUDFLARE_API_KEY || !process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID || !process.env.CLOUDFLARE_ACCOUNT_ID) { - console.error('Missing required environment variables.'); - process.exit(1); +console.error('Missing required environment variables.'); +process.exit(1); } // Setup Postgres connection @@ -40,54 +38,56 @@ const sql = postgres(process.env.DATABASE_CONNECTION_STRING); // Setup Cloudflare REST API client const client = new Cloudflare({ - apiEmail: process.env.CLOUDFLARE_EMAIL, - apiKey: process.env.CLOUDFLARE_API_KEY, +apiEmail: process.env.CLOUDFLARE_EMAIL, +apiKey: process.env.CLOUDFLARE_API_KEY, }); // Function to sync Postgres data to Workers KV async function syncPreviewStatus() { - console.log('Starting sync of user preview status...'); - - try { - // Get all users and their preview status - const users = await sql`SELECT id, preview_features_enabled FROM users`; - - console.log(users); - - // Create the bulk update body - const bulkUpdateBody = users.map(user => ({ - key: user.id, - value: JSON.stringify({ - preview_features_enabled: user.preview_features_enabled - }) - })); - - const response = await backOff(async () => { - console.log("trying to update") - try{ - const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, { - account_id: process.env.CLOUDFLARE_ACCOUNT_ID, - body: bulkUpdateBody - }); - } - catch(e){ - // Implement your error handling and logging here - console.log(e); - throw e; // Rethrow the error to retry - } - }); - - console.log(`Sync complete. Updated ${users.length} users.`); - } catch (error) { - console.error('Error syncing preview status:', error); - } +console.log('Starting sync of user preview status...'); + + try { + // Get all users and their preview status + const users = await sql`SELECT id, preview_features_enabled FROM users`; + + console.log(users); + + // Create the bulk update body + const bulkUpdateBody = users.map(user => ({ + key: user.id, + value: JSON.stringify({ + preview_features_enabled: user.preview_features_enabled + }) + })); + + const response = await backOff(async () => { + console.log("trying to update") + try{ + const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, { + account_id: process.env.CLOUDFLARE_ACCOUNT_ID, + body: bulkUpdateBody + }); + } + catch(e){ + // Implement your error handling and logging here + console.log(e); + throw e; // Rethrow the error to retry + } + }); + + console.log(`Sync complete. Updated ${users.length} users.`); + } catch (error) { + console.error('Error syncing preview status:', error); + } + } // Run the sync function syncPreviewStatus() - .catch(console.error) - .finally(() => process.exit(0)); -``` +.catch(console.error) +.finally(() => process.exit(0)); + +```` ```md title=".env" @@ -225,7 +225,7 @@ This code will use the path within the URL and find the file associated to the p ## Optimize performance for configuration -To optimize performance, you may opt to consolidate values in fewer key-value pairs. By doing so, you may benefit from higher caching efficiency and lower latency. +To optimize performance, you may opt to consolidate values in fewer key-value pairs. By doing so, you may benefit from higher caching efficiency and lower latency. For example, instead of storing each user's configuration in a separate key-value pair, you may store all users' configurations in a single key-value pair. This approach may be suitable for use-cases where the configuration data is small and can be easily managed in a single key-value pair (the [size limit for a Workers KV value is 25 MiB](/kv/platform/limits/)). diff --git a/src/content/docs/kv/examples/implement-ab-testing-with-workers-kv.mdx b/src/content/docs/kv/examples/implement-ab-testing-with-workers-kv.mdx index 29fcaf903f8df8..24574e77d53ad7 100644 --- a/src/content/docs/kv/examples/implement-ab-testing-with-workers-kv.mdx +++ b/src/content/docs/kv/examples/implement-ab-testing-with-workers-kv.mdx @@ -1,11 +1,9 @@ --- type: example summary: Use Workers KV to store A/B testing configuration data and analyze the performance of different versions of your website -tags: - - KV pcx_content_type: configuration title: A/B testing with Workers KV external_link: /reference-architecture/diagrams/serverless/a-b-testing-using-workers/ sidebar: order: 6 ---- \ No newline at end of file +--- diff --git a/src/content/docs/kv/examples/routing-with-workers-kv.mdx b/src/content/docs/kv/examples/routing-with-workers-kv.mdx index b386908a23bd10..ba4598135d690b 100644 --- a/src/content/docs/kv/examples/routing-with-workers-kv.mdx +++ b/src/content/docs/kv/examples/routing-with-workers-kv.mdx @@ -1,8 +1,6 @@ --- type: example summary: Store routing data in Workers KV to route requests across various web servers with Workers -tags: - - KV pcx_content_type: configuration title: Route requests across various web servers sidebar: @@ -16,7 +14,6 @@ Using Workers KV to store routing data to route requests across various web serv Routing can be helpful to route requests coming into a single Cloudflare Worker application to different web servers based on the request's path, hostname, or other request attributes. - In single-tenant applications, this can be used to route requests to various origin servers based on the business domain (for example, requests to `/admin` routed to administration server, `/store` routed to storefront server, `/api` routed to the API server). In multi-tenant applications, requests can be routed to the tenant's respective origin resources (for example, requests to `tenantA.your-worker-hostname.com` routed to server for Tenant A, `tenantB.your-worker-hostname.com` routed to server for Tenant B). @@ -142,7 +139,6 @@ In this example, the Cloudflare Worker receives a request and extracts the store The storefront ID is used to look up the origin server URL from Workers KV using the `get()` method. The request is then forwarded to the origin server, and the response is modified to include custom headers before being returned to the client. - ## Related resources - [Rust support in Workers](/workers/languages/rust/). diff --git a/src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx b/src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx index 293d300879fa59..8d329c9d38f29e 100644 --- a/src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx +++ b/src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx @@ -1,8 +1,6 @@ --- type: example summary: Store static assets in Workers KV and serve them from a Worker application with low-latency and high-throughput -tags: - - KV pcx_content_type: configuration title: Store and retrieve static assets sidebar: diff --git a/src/content/docs/style-guide/frontmatter/tags.mdx b/src/content/docs/style-guide/frontmatter/tags.mdx index 6dd5ce4fe3d3ea..c0c657c28dc29b 100644 --- a/src/content/docs/style-guide/frontmatter/tags.mdx +++ b/src/content/docs/style-guide/frontmatter/tags.mdx @@ -6,7 +6,7 @@ import { TagsUsage } from "~/components"; Tags are currently used to filter content in the [`ExternalResources`](/style-guide/components/external-resources/), [`ProductsByTag`](/style-guide/components/products-by-tag/) and the [`ResourcesBySelector`](/style-guide/components/resources-by-selector/) components. -## Examples +## Example ```mdx --- @@ -17,6 +17,15 @@ tags: --- ``` -## Tags +## Allowed tags and where they are being used - \ No newline at end of file +Tags are validated against an allowlist in [`/src/schemas/tags.ts`](https://github.com/cloudflare/cloudflare-docs/blob/production/src/schemas/tags.ts) which defines the user-facing representation (`label`) and any associated variants. + +The matching is case-insensitive. For example, all of the following values are accepted in the `tags` frontmatter array and will be transformed into `Node.js`: + +- `node.js` +- `NoDe.JS` +- `node` +- `nodejs` + + diff --git a/src/plugins/starlight/route-data.ts b/src/plugins/starlight/route-data.ts new file mode 100644 index 00000000000000..5264b712052574 --- /dev/null +++ b/src/plugins/starlight/route-data.ts @@ -0,0 +1,29 @@ +import { defineRouteMiddleware } from "@astrojs/starlight/route-data"; +import { tags as allowedTags } from "~/schemas/tags"; + +export const onRequest = defineRouteMiddleware(({ locals }) => { + const { entry } = locals.starlightRoute; + const { tags } = entry.data; + + if (tags) { + const transformed = tags.map((tag) => { + const values = Object.values(allowedTags).flat(); + + const match = values.find( + (val) => + val.label.toLowerCase() === tag.toLowerCase() || + val.variants?.find((v) => v.toLowerCase() === tag.toLowerCase()), + ); + + if (!match) { + throw new Error( + `Invalid tag on ${entry.id}: ${tag}, please refer to the style guide: https://developers.cloudflare.com/style-guide/frontmatter/tags/`, + ); + } + + return match.label; + }); + + entry.data.tags = transformed; + } +}); diff --git a/src/schemas/tags.ts b/src/schemas/tags.ts index 6ea693d0b2b5aa..268e660ad3320e 100644 --- a/src/schemas/tags.ts +++ b/src/schemas/tags.ts @@ -3,14 +3,16 @@ in our page frontmatter. Refer to https://developers.cloudflare.com/style-guide/ and https://developers.cloudflare.com/style-guide/frontmatter/tags/ for more details. */ -const data_structures: Array = [ +type Tag = { label: string; variants?: string[] }; + +const data_structures: Array = [ { label: "JSON" }, { label: "TOML" }, { label: "XML" }, { label: "YAML" }, ]; -const frameworks: Array = [ +const frameworks: Array = [ { label: "Angular" }, { label: "Astro" }, { label: "Hono" }, @@ -24,7 +26,7 @@ const frameworks: Array = [ { label: "Vue.js", variants: ["vue", "vuejs"] }, ]; -const integrations: Array = [ +const integrations: Array = [ { label: "Azure", variants: ["Microsoft Azure", "MS Azure"] }, { label: "AWS", variants: ["Amazon Web Services"] }, { label: "GCP", variants: ["Google Cloud", "Google Cloud Platform"] }, @@ -36,7 +38,8 @@ const integrations: Array = [ variants: ["AzureAD", "Azure Active Directory", "MS Entra ID", "Entra ID"], }, { label: "Microsoft" }, - { label: "Postgres", variants: ["PostgresSQL"] }, + { label: "MotherDuck" }, + { label: "Postgres", variants: ["PostgreSQL"] }, { label: "S3" }, { label: "Sentry" }, { label: "Stripe" }, @@ -45,7 +48,7 @@ const integrations: Array = [ { label: "WordPress" }, ]; -const languages: Array = [ +const languages: Array = [ { label: "Go" }, { label: "GraphQL" }, { label: "JavaScript", variants: ["js"] }, @@ -60,7 +63,7 @@ const languages: Array = [ { label: "WebAssembly", variants: ["Web Assembly", "wasm"] }, ]; -const operating_systems: Array = [ +const operating_systems: Array = [ { label: "Android", variants: ["ChromeOS"] }, { label: "iOS" }, { label: "Linux" }, @@ -68,14 +71,14 @@ const operating_systems: Array = [ { label: "Windows", variants: ["ms windows"] }, ]; -const presentation: Array = [{ label: "Video" }]; +const presentation: Array = [{ label: "Video" }]; -const product_features: Array = [ +const product_features: Array = [ { label: "Web Crypto", variants: ["webcrypto"] }, { label: "RPC" }, ]; -const protocols: Array = [ +const protocols: Array = [ { label: "FTP", variants: ["file transfer protocol", "ftps"] }, { label: "ICMP" }, { label: "IPsec" }, @@ -100,7 +103,7 @@ const protocols: Array = [ { label: "Wireguard" }, ]; -const use_cases: Array = [ +const use_cases: Array = [ { label: "AI" }, { label: "Authentication", variants: ["auth"] }, { label: "A/B testing", variants: ["ab test"] }, @@ -110,6 +113,7 @@ const use_cases: Array = [ { label: "CORS" }, { label: "Debugging", variants: ["debug", "troubleshooting"] }, { label: "Forms" }, + { label: "Full stack", variants: ["full-stack"] }, { label: "Geolocation" }, { label: "Headers", variants: ["header"] }, { label: "Localization" }, @@ -122,6 +126,8 @@ const use_cases: Array = [ { label: "Response modification", variants: ["response"] }, { label: "RPC" }, { label: "Security" }, + { label: "SPA" }, + { label: "SSG" }, { label: "URL rewrite", variants: ["rewrite"] }, ];