From 83637bf8789701472168e6709cebfb6f79f9f217 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 20 Feb 2026 23:38:29 +0000 Subject: [PATCH 1/2] added unofficial cursor plug-in for uniform.dev --- .cursor-plugin/marketplace.json | 25 ++ enterprise-toolkit/.cursor-plugin/plugin.json | 11 + enterprise-toolkit/.mcp.json | 9 + enterprise-toolkit/README.md | 22 ++ .../agents/compliance-checker.md | 15 ++ .../agents/security-reviewer.md | 17 ++ enterprise-toolkit/assets/logo.svg | 19 ++ .../commands/run-compliance-scan.md | 27 ++ enterprise-toolkit/hooks/hooks.json | 21 ++ enterprise-toolkit/rules/code-style.mdc | 13 + .../rules/security-standards.mdc | 16 ++ enterprise-toolkit/scripts/audit.sh | 4 + enterprise-toolkit/scripts/format-code.py | 11 + enterprise-toolkit/scripts/validate-shell.sh | 4 + .../skills/compliance-check/SKILL.md | 21 ++ .../skills/security-review/SKILL.md | 25 ++ uniform-rules/.cursor-plugin/plugin.json | 9 + uniform-rules/README.md | 16 ++ uniform-rules/rules/solution-architecture.mdc | 44 ++++ uniform-rules/rules/uniform-mesh.mdc | 31 +++ .../rules/uniform-next-app-router.mdc | 32 +++ .../rules/uniform-next-page-router.mdc | 25 ++ uniform-rules/rules/uniform-sdk.mdc | 107 ++++++++ uniform-rules/rules/uniform-sveltekit.mdc | 76 ++++++ uniform-rules/rules/uniform.mdc | 242 ++++++++++++++++++ 25 files changed, 842 insertions(+) create mode 100644 .cursor-plugin/marketplace.json create mode 100644 enterprise-toolkit/.cursor-plugin/plugin.json create mode 100644 enterprise-toolkit/.mcp.json create mode 100644 enterprise-toolkit/README.md create mode 100644 enterprise-toolkit/agents/compliance-checker.md create mode 100644 enterprise-toolkit/agents/security-reviewer.md create mode 100644 enterprise-toolkit/assets/logo.svg create mode 100644 enterprise-toolkit/commands/run-compliance-scan.md create mode 100644 enterprise-toolkit/hooks/hooks.json create mode 100644 enterprise-toolkit/rules/code-style.mdc create mode 100644 enterprise-toolkit/rules/security-standards.mdc create mode 100644 enterprise-toolkit/scripts/audit.sh create mode 100644 enterprise-toolkit/scripts/format-code.py create mode 100644 enterprise-toolkit/scripts/validate-shell.sh create mode 100644 enterprise-toolkit/skills/compliance-check/SKILL.md create mode 100644 enterprise-toolkit/skills/security-review/SKILL.md create mode 100644 uniform-rules/.cursor-plugin/plugin.json create mode 100644 uniform-rules/README.md create mode 100644 uniform-rules/rules/solution-architecture.mdc create mode 100644 uniform-rules/rules/uniform-mesh.mdc create mode 100644 uniform-rules/rules/uniform-next-app-router.mdc create mode 100644 uniform-rules/rules/uniform-next-page-router.mdc create mode 100644 uniform-rules/rules/uniform-sdk.mdc create mode 100644 uniform-rules/rules/uniform-sveltekit.mdc create mode 100644 uniform-rules/rules/uniform.mdc diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json new file mode 100644 index 0000000..b0f0792 --- /dev/null +++ b/.cursor-plugin/marketplace.json @@ -0,0 +1,25 @@ +{ + "name": "uniform.dev", + "owner": { + "name": "Uniform.dev", + "email": "plugins@example.com" + }, + "metadata": { + "description": "Uniform.dev", + "version": "1.0.0" + }, + "plugins": [ + { + "name": "uniform-rules", + "source": "uniform-rules", + "description": "Uniform CMS rules for AI-assisted development (compositions, components, patterns, SDK, mesh)", + "keywords": ["uniform", "cms", "headless", "canvas", "sveltekit", "next"] + }, + { + "name": "enterprise-toolkit", + "source": "enterprise-toolkit", + "description": "Enterprise development toolkit with security, compliance, and automation", + "keywords": ["enterprise", "security", "compliance", "code-review"] + } + ] +} diff --git a/enterprise-toolkit/.cursor-plugin/plugin.json b/enterprise-toolkit/.cursor-plugin/plugin.json new file mode 100644 index 0000000..803e063 --- /dev/null +++ b/enterprise-toolkit/.cursor-plugin/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "enterprise-toolkit", + "version": "1.0.0", + "description": "Enterprise development toolkit with security scanning, compliance checks, and automation", + "author": { + "name": "AI Rules", + "email": "plugins@example.com" + }, + "keywords": ["enterprise", "security", "compliance", "code-review"], + "logo": "assets/logo.svg" +} diff --git a/enterprise-toolkit/.mcp.json b/enterprise-toolkit/.mcp.json new file mode 100644 index 0000000..4c596b6 --- /dev/null +++ b/enterprise-toolkit/.mcp.json @@ -0,0 +1,9 @@ +{ + "mcpServers": { + "filesystem": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-filesystem", "."], + "env": {} + } + } +} diff --git a/enterprise-toolkit/README.md b/enterprise-toolkit/README.md new file mode 100644 index 0000000..5b82b89 --- /dev/null +++ b/enterprise-toolkit/README.md @@ -0,0 +1,22 @@ +# Enterprise Toolkit + +Cursor plugin with security standards, compliance checks, and automation for enterprise development. + +## Contents + +- **Rules**: `security-standards.mdc`, `code-style.mdc` +- **Skills**: `compliance-check`, `security-review` +- **Agents**: `security-reviewer`, `compliance-checker` +- **Commands**: `run-compliance-scan` +- **Hooks**: afterFileEdit (format), beforeShellExecution (validate), sessionEnd (audit) +- **MCP**: Optional filesystem server (configure path in `.mcp.json`) + +## Configuration + +- Edit `hooks/hooks.json` to enable or disable hooks and matchers. +- Edit `.mcp.json` to add or change MCP servers (e.g. database, APIs). +- Replace placeholder scripts in `scripts/` with your formatters and validators. + +## Usage + +Install this plugin via the Cursor marketplace or from this repo. Rules and skills apply when the plugin is active. Use agents and commands from the Cursor UI as needed. diff --git a/enterprise-toolkit/agents/compliance-checker.md b/enterprise-toolkit/agents/compliance-checker.md new file mode 100644 index 0000000..72e5d9e --- /dev/null +++ b/enterprise-toolkit/agents/compliance-checker.md @@ -0,0 +1,15 @@ +--- +name: compliance-checker +description: Runs compliance and policy checks on the codebase +--- + +# Compliance Checker + +You run compliance and policy checks. When asked: + +1. Summarize security-related findings (secrets, dependencies, obvious vulnerabilities) +2. Note licensing and policy documents (CONTRIBUTING, SECURITY, LICENSE) +3. Compare current state to any stated policies +4. Produce a short pass/warn/fail report with next steps + +Use the compliance-check skill when performing detailed audits. diff --git a/enterprise-toolkit/agents/security-reviewer.md b/enterprise-toolkit/agents/security-reviewer.md new file mode 100644 index 0000000..324d9f3 --- /dev/null +++ b/enterprise-toolkit/agents/security-reviewer.md @@ -0,0 +1,17 @@ +--- +name: security-reviewer +description: Security-focused code reviewer that checks for vulnerabilities and proven approaches +--- + +# Security Reviewer + +You are a security-focused code reviewer. When reviewing code: + +1. Check for injection vulnerabilities (SQL, XSS, command injection) +2. Verify proper authentication and authorization +3. Look for sensitive data exposure (API keys, passwords, PII) +4. Ensure secure cryptographic practices +5. Review dependency security and known vulnerabilities +6. Check for proper input validation and sanitization + +Report findings with severity and concrete remediation. Prefer safe defaults. diff --git a/enterprise-toolkit/assets/logo.svg b/enterprise-toolkit/assets/logo.svg new file mode 100644 index 0000000..252a7b4 --- /dev/null +++ b/enterprise-toolkit/assets/logo.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/enterprise-toolkit/commands/run-compliance-scan.md b/enterprise-toolkit/commands/run-compliance-scan.md new file mode 100644 index 0000000..0d91e5f --- /dev/null +++ b/enterprise-toolkit/commands/run-compliance-scan.md @@ -0,0 +1,27 @@ +--- +name: run-compliance-scan +description: Run a full compliance scan (security, licensing, policy) on the current project +--- + +# Run compliance scan + +Execute a compliance scan for the current project: + +1. **Security** + - Check for hardcoded secrets and unsafe patterns + - List dependency audit commands (e.g. `npm audit`, `pnpm audit`) and suggest running them + - Note any obvious injection or auth issues in the codebase + +2. **Licensing** + - Identify root and package license files + - Summarize license types; flag any that may need legal review + +3. **Policy** + - Look for CONTRIBUTING.md, SECURITY.md, CODE_OF_CONDUCT.md, or similar + - Summarize requirements and whether the repo state aligns + +4. **Report** + - Output a short summary with pass/warn/fail per area + - Recommend concrete next steps (e.g. run `npm audit`, add SECURITY.md) + +Do not modify code or run destructive commands unless the user asks. diff --git a/enterprise-toolkit/hooks/hooks.json b/enterprise-toolkit/hooks/hooks.json new file mode 100644 index 0000000..603426e --- /dev/null +++ b/enterprise-toolkit/hooks/hooks.json @@ -0,0 +1,21 @@ +{ + "hooks": { + "afterFileEdit": [ + { + "command": "./scripts/format-code.py", + "matcher": "**/*.py" + } + ], + "beforeShellExecution": [ + { + "command": "./scripts/validate-shell.sh", + "matcher": "rm\\s+-rf|curl\\s+.*\\|\\s*sh|wget\\s+.*\\|\\s*sh" + } + ], + "sessionEnd": [ + { + "command": "./scripts/audit.sh" + } + ] + } +} diff --git a/enterprise-toolkit/rules/code-style.mdc b/enterprise-toolkit/rules/code-style.mdc new file mode 100644 index 0000000..6e91751 --- /dev/null +++ b/enterprise-toolkit/rules/code-style.mdc @@ -0,0 +1,13 @@ +--- +description: Consistent code style and cleanup +alwaysApply: true +globs: +--- + +# Code style + +- Prefer `const` over `let` for variables that are never reassigned. +- Remove unused code and imports so linters and type checks pass. +- Use the project's existing style (indentation, quotes, semicolons). When in doubt, match surrounding code. +- Keep functions and files focused; avoid unnecessary abstraction. +- Add comments in English when non-obvious logic needs explanation. diff --git a/enterprise-toolkit/rules/security-standards.mdc b/enterprise-toolkit/rules/security-standards.mdc new file mode 100644 index 0000000..83d8b07 --- /dev/null +++ b/enterprise-toolkit/rules/security-standards.mdc @@ -0,0 +1,16 @@ +--- +description: Security standards for code - injection, auth, secrets, crypto +alwaysApply: false +globs: "**/*.{ts,tsx,js,jsx,py,go,java}" +--- + +# Security standards + +When writing or reviewing code, enforce these practices: + +1. **Injection**: Never concatenate user input into SQL, shell commands, or HTML. Use parameterized queries, safe APIs, and output encoding. +2. **Authentication and authorization**: Verify identity and permissions on every sensitive operation. Prefer established libraries (e.g. OAuth2, JWT validation). +3. **Secrets**: Never commit API keys, passwords, or tokens. Use environment variables or secret managers. Do not log or expose secrets in errors. +4. **Cryptography**: Use standard libraries and algorithms (e.g. bcrypt/argon2 for hashing, TLS for transport). Avoid custom crypto. +5. **Input validation**: Validate and sanitize all external input. Enforce allowlists and bounds where possible. +6. **Dependencies**: Keep dependencies updated. Check for known vulnerabilities (e.g. npm audit, dependabot). diff --git a/enterprise-toolkit/scripts/audit.sh b/enterprise-toolkit/scripts/audit.sh new file mode 100644 index 0000000..878a8c6 --- /dev/null +++ b/enterprise-toolkit/scripts/audit.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +# Optional session-end audit. Hook script for enterprise-toolkit. +# Placeholder: e.g. log session end, run lightweight checks. +exit 0 diff --git a/enterprise-toolkit/scripts/format-code.py b/enterprise-toolkit/scripts/format-code.py new file mode 100644 index 0000000..07d16cd --- /dev/null +++ b/enterprise-toolkit/scripts/format-code.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +""" +Format Python files after edit. Hook script for enterprise-toolkit. +Replace with actual formatter (e.g. black, ruff format) as needed. +""" +import sys + +# Placeholder: in production, run e.g. subprocess.run(["black", path]) +# This script is invoked by the afterFileEdit hook for **/*.py +if __name__ == "__main__": + sys.exit(0) diff --git a/enterprise-toolkit/scripts/validate-shell.sh b/enterprise-toolkit/scripts/validate-shell.sh new file mode 100644 index 0000000..47d1634 --- /dev/null +++ b/enterprise-toolkit/scripts/validate-shell.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +# Validates shell commands before execution. Hook script for enterprise-toolkit. +# Placeholder: in production, parse stdin and block dangerous patterns (e.g. rm -rf /, curl | sh). +exit 0 diff --git a/enterprise-toolkit/skills/compliance-check/SKILL.md b/enterprise-toolkit/skills/compliance-check/SKILL.md new file mode 100644 index 0000000..fe1a9fd --- /dev/null +++ b/enterprise-toolkit/skills/compliance-check/SKILL.md @@ -0,0 +1,21 @@ +--- +name: compliance-check +description: Run compliance checks for security, licensing, and policy. Use when auditing a codebase, before releases, or when asked about compliance or policy. +--- + +# Compliance Check Skill + +## When to use + +- Auditing a codebase for security or policy compliance +- Before releases or merge to main +- When the user asks about compliance, licensing, or policy + +## Instructions + +1. **Security**: Scan for hardcoded secrets, unsafe dependencies, and obvious injection or auth issues. Suggest fixes or follow-up tools (e.g. npm audit, secret scanning). +2. **Licensing**: Note any license files or package metadata. Flag incompatible or unclear licenses if the user cares about license compliance. +3. **Policy**: If the project has a CONTRIBUTING, SECURITY, or policy doc, summarize requirements and check whether the current change aligns. +4. **Reporting**: Summarize findings in a short report (pass/warn/fail per area). Recommend concrete next steps. + +Do not run destructive or invasive commands unless the user explicitly requests them. diff --git a/enterprise-toolkit/skills/security-review/SKILL.md b/enterprise-toolkit/skills/security-review/SKILL.md new file mode 100644 index 0000000..ebb41c4 --- /dev/null +++ b/enterprise-toolkit/skills/security-review/SKILL.md @@ -0,0 +1,25 @@ +--- +name: security-review +description: Security-focused code review. Use when reviewing PRs, auditing for vulnerabilities, or improving secure coding practices. +--- + +# Security Reviewer Skill + +## When to use + +- Reviewing pull requests or diffs for security issues +- Auditing code for vulnerabilities +- Improving secure coding practices + +## Instructions + +When performing a security review: + +1. **Injection**: Look for SQL, command, or XSS injection (untrusted input in queries, exec, or DOM). +2. **Auth and access control**: Check that sensitive operations require authentication and correct authorization. +3. **Secrets and PII**: Ensure no API keys, passwords, or PII are logged, committed, or exposed in errors. +4. **Crypto**: Verify hashing, encryption, and TLS usage follow best practices (no custom crypto, strong algorithms). +5. **Dependencies**: Note outdated or known-vulnerable packages; suggest updates or alternatives. +6. **Input validation**: Check that external input is validated and sanitized before use. + +Provide a concise list of findings with severity (high/medium/low) and concrete remediation steps. Prefer safe defaults and defense in depth. diff --git a/uniform-rules/.cursor-plugin/plugin.json b/uniform-rules/.cursor-plugin/plugin.json new file mode 100644 index 0000000..61e9d62 --- /dev/null +++ b/uniform-rules/.cursor-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "uniform-rules", + "version": "1.0.0", + "description": "Uniform CMS rules for AI-assisted development: compositions, components, patterns, SDK, and framework guides", + "author": { + "name": "AI Rules" + }, + "keywords": ["uniform", "cms", "headless", "canvas", "sveltekit", "next", "mesh"] +} diff --git a/uniform-rules/README.md b/uniform-rules/README.md new file mode 100644 index 0000000..294b0b3 --- /dev/null +++ b/uniform-rules/README.md @@ -0,0 +1,16 @@ +# Uniform Rules + +Cursor plugin that provides Uniform CMS rules for AI-assisted development. + +## Contents + +- **uniform.mdc** – Core concepts: compositions, components, patterns, entries, content types, assets, localization +- **uniform-sdk.mdc** – SDK: auth, routing, CLI, frontend integration +- **uniform-sveltekit.mdc** – SvelteKit: packages, component mapping, hooks, preview, edge personalization +- **uniform-next-app-router.mdc** – Next.js App Router +- **uniform-next-page-router.mdc** – Next.js Page Router +- **uniform-mesh.mdc** – Mesh integrations: manifest, locations, data connectors + +## Usage + +Install this plugin via the Cursor marketplace or from this repo. Use when building or maintaining projects that use Uniform CMS (Canvas, Context, Mesh). diff --git a/uniform-rules/rules/solution-architecture.mdc b/uniform-rules/rules/solution-architecture.mdc new file mode 100644 index 0000000..9f880c4 --- /dev/null +++ b/uniform-rules/rules/solution-architecture.mdc @@ -0,0 +1,44 @@ +--- +description: Optional coding standards and Uniform practices (React, Tailwind, slots, patterns) +globs: +alwaysApply: false +--- + +# Coding standards + +- Always generate clean code and remove unused code, so the linter and typescript checks pass automatically. IMPORTANT: do not ever run build of the application as a part of the validation as this breaks developer server and is causing issues. + +- Always use `pnpm` to install packages if you see `pnpm-lock.yaml` in the root folder, otherwise use `npm`. Never use `yarn`. + +- You are a senior React engineer, follow best practices of React at all times. +- Use TailwindCSS best practices when building CSS. Don't re-invent the wheel. +- You are a senior engineer, do not try to impress me with over-delivery. +- Do not create more components than I ask you to. Keep things to the minimum required. + +# Uniform practices + +1. CRITICAL: Always create a component pattern when pushing a new component to Uniform project and fill it with content using previous examples of this component usage if possible. If not, generate content for component pattern yourself. + +2. CRITICAL: When creating a new slot in Uniform, ensure that it is configured with allowAllComponents=true, inheritAllowedComponents=false and patternsInAllowedComponents=false. + +3. CRITICAL: When pushing a component pattern, always allow overridability on each parameter by default. + +4. CRITICAL: When registering components with Uniform and spotting repeated properties, always resort to modeling repeated set of properties as child components and create `` to render those. This will ensure reuse and avoid pollution with properties such as title1, description1, image1, title2, description2 and so on. + +# Environment variables + +1. Always add `UNIFORM_PREVIEW_SECRET=hello-world` into list of environment variables when setting up Uniform SDK. + +## Uniform SDK + +1. CRITICAL! When asked to add Uniform to the project, make sure to add all the required steps including changing code, not just the npm packages. + +2. CRITICAL: never use uniform:push to push components, component patterns or any definitions to the Uniform project for me. Instead, rely on the Uniform MCP tool to take care of that. + +3. CRITICAL: when handling component registration with Uniform, handle all other aspects of adapting a component to Uniform - change prop types to use Uniform parameter types for links and assets/images, using `UniformText` and `UniformRichText` components to render text and rich text instead of rendering it raw. + +# Next.js + +1. When creating a catch all page handler with Uniform (`[[...path]].tsx`), always place it at the root. Check if there is a conflicting page route definition, like `index.tsx` and disable it by renaming it to `.off` extension to avoid conflict. + +2. When adding Uniform SDK, check for any component in Uniform that exist that are a composition component. If so, automatically create a corresponding React component for it in the codebase, register it and define all the slots that exist on the component definition in Uniform project. diff --git a/uniform-rules/rules/uniform-mesh.mdc b/uniform-rules/rules/uniform-mesh.mdc new file mode 100644 index 0000000..c1b5ca3 --- /dev/null +++ b/uniform-rules/rules/uniform-mesh.mdc @@ -0,0 +1,31 @@ +--- +description: Uniform Mesh integrations - custom web apps extending the Uniform UI and data connectors +globs: +alwaysApply: true +--- + +# Uniform Mesh Integrations + +Uniform Mesh extends the Uniform UI with custom web applications. Integrations run on URLs you host and communicate with the Uniform dashboard via iframe messaging. + +## Core stack + +- **Framework**: Next.js with page router (recommended) +- **SDK**: `@uniformdev/mesh-sdk-react` +- **Design**: `@uniformdev/design-system` +- **CLI**: `@uniformdev/cli` (register in team, install in project) +- **Language**: TypeScript (recommended) + +## Manifest (mesh-manifest.json) + +Required: `type`, `displayName`, `baseLocationUrl`, `locations`. Optional: `logoIconUrl`, `badgeIconUrl`, `category`, `scopes`. + +## Location types + +- **Install**: Shown when installing; configure in manifest (description, informationUrl). +- **Settings**: Integration-wide config; use `useMeshLocation<'settings'>` with value/setValue. +- **Data Connectors**: Data Source Editor (connection settings, secure storage), Data Type Editor (path, parameters), Data Resource Editor (object search). Do not store secrets in Data Type; use Data Source for credentials. + +## Implementation + +Use `useMeshLocation()` for value and setValue. Use design-system components for consistent UI. Locations receive **value** (editable) and **metadata** (read-only). diff --git a/uniform-rules/rules/uniform-next-app-router.mdc b/uniform-rules/rules/uniform-next-app-router.mdc new file mode 100644 index 0000000..0341c62 --- /dev/null +++ b/uniform-rules/rules/uniform-next-app-router.mdc @@ -0,0 +1,32 @@ +--- +description: Rules for Uniform SDK for Next.js App Router +globs: "**/*.{tsx,jsx}" +alwaysApply: true +--- + +# Uniform React Next App Router + +See uniform.mdc for general Uniform principles and practices. +See uniform-sdk.mdc for framework-agnostic developer principles. + +## Required npm packages + +- `@uniformdev/canvas-next-rsc` +- `@uniformdev/canvas` + +## Config + +- Add `uniform.server.config.js` in project root (defaultConsent, evaluation, experimental). +- Wrap Next config with `withUniformConfig()` from `@uniformdev/canvas-next-rsc/config`. + +## Fetching and rendering + +In `app/[[...path]]/page.{tsx|jsx}` use `retrieveRoute(props)` and render with `UniformComposition` from `@uniformdev/canvas-next-rsc` and `resolveComponent` for mapping. Use `mode="server"`. + +## Layout + +Wrap `{children}` in `UniformContext` from `@uniformdev/canvas-next-rsc` in `app/layout.tsx` for personalization and A/B testing. + +## Component registration + +Use `resolveComponent` (or equivalent) to map Uniform component types to React components. Create a component for every composition component in the Uniform project and add slots as in the definition. diff --git a/uniform-rules/rules/uniform-next-page-router.mdc b/uniform-rules/rules/uniform-next-page-router.mdc new file mode 100644 index 0000000..44bd030 --- /dev/null +++ b/uniform-rules/rules/uniform-next-page-router.mdc @@ -0,0 +1,25 @@ +--- +description: Rules for Uniform SDK for Next.js Page Router +globs: "**/*.{tsx,jsx}" +alwaysApply: true +--- + +# Uniform Next.js Page Router + +See uniform.mdc for general Uniform principles and practices. +See uniform-sdk.mdc for framework-agnostic developer principles. + +## Required npm packages + +- `@uniformdev/canvas` +- `@uniformdev/canvas-react` +- `@uniformdev/canvas-next` +- `@uniformdev/context-react` + +## Fetching and rendering + +In `pages/[[...path]].{tsx|jsx}` use `withUniformGetServerSideProps()` for SSR and pass `data` to `UniformComposition` from `@uniformdev/canvas-react`. Type the page with `UniformCompositionNextPage`. + +## Component registration + +Use `registerUniformComponent({ type, component })` from `@uniformdev/canvas-react`. Import registrations in `_app.tsx` so they run. Use `ComponentProps` for parameter typing; all parameter props optional. Use `UniformSlot` for child slots. diff --git a/uniform-rules/rules/uniform-sdk.mdc b/uniform-rules/rules/uniform-sdk.mdc new file mode 100644 index 0000000..da2dc41 --- /dev/null +++ b/uniform-rules/rules/uniform-sdk.mdc @@ -0,0 +1,107 @@ +--- +description: Uniform SDK developer reference - auth, routing, CLI, frontend integration +globs: +alwaysApply: true +--- +# Uniform SDK Developer Reference + +This document details general information and practices about how Uniform works for developers writing frontend applications. + +See uniform.mdc for general Uniform principles and practices. + +## Authenticating to Uniform + +To fetch a composition, you need a Uniform API key configured. API keys are commonly stored as `UNIFORM_API_KEY` in a `.env` file. They follow the format `uf......`. The API key requires "Read Published Compositions" permission. + +## How Uniform transfers layout data to frontend applications + +Uniform provides _composition instances_, a hierarchical JSON structure of components that define screens or pages in an application. A composition is made up of any number of _components_ which have a type that we map to a frontend component. + +### Routing + +Uniform's _Project Map_ feature enables automatic dynamic route delegation to Uniform authors. Frontend applications define a wildcard route that delegates routing to the Uniform _Route API_, which takes a dynamic path and resolves the correct composition instance data to display for that path. + +### Syncing data with the Uniform CLI + +Uniform provides a CLI which can be used to sync the state of a Uniform project, such as component definitions, pattern definitions, or compositions, to files on disk. These files may be committed to source control and used to ensure the states of environment or developer-specific projects are kept up to date to reduce the chance of errors. + +#### Required package for Uniform CLI + +The Uniform CLI is contained in the `@uniformdev/cli` npm package. IMPORTANT: this package must be installed as a devDependency. + +#### Authenticating with the Uniform CLI + +The Uniform CLI requires a Uniform API key to authenticate. The API key and other connectivity details are stored in a `.env` file. When creating an API key for the CLI, the user can use the "Copy as .env" function in the Uniform dashboard to get the appropriate environment variable values. +API keys used for the Uniform CLI require read and write permissions to any entity types that are to be synced. The default 'developer' role is a shortcut to full permissions. + +#### Configuring the Uniform CLI + +Uniform CLI is configured using the `uniform.config.{ts,js}` file in the root of a project. The file can be configured in two ways: to sync everything (choose this for initial setup), or to pick specific entity types to sync. Sync operates as a mirror by default, meaning creates, updates, and deletes are all synced. + +`uniform.config.ts` (sync all): + +```ts +import { uniformConfig } from "@uniformdev/cli/config"; + +export default uniformConfig({ preset: "all" }); +``` + +`uniform.config.ts` (sync explicit types and customization options): + +```ts +import { uniformConfig } from "@uniformdev/cli/config"; + +export default uniformConfig({ + // 'none' starts with no entities, and each entity type to sync is added explicitly + preset: "none", + config: { + serialization: { + // optionally override the default `./uniform-data` to store serialized files + directory: "./custom-path-to-serialized-files", + // optionally change the default yaml format to json + format: "json", + entitiesConfig: { + // specify entity types to sync. Each type can optionally override + // the defaults just for itself, i.e. directory, format + component: {}, + componentPattern: { publish: true }, + }, + }, + }, +}); +``` + +#### Invoking the Uniform CLI + +The Uniform CLI operates using two primary commands: + +`uniform sync push` - takes the serialized state of entities (files on disk) and pushes that state into a Uniform project online. + +`uniform sync pull` - takes the online state of a Uniform project and pulls it into serialized files. + +Conventionally these commands are registered as package scripts to make it unnecessary to install the CLI package globally: + +`package.json`: + +```json +{ + "scripts": { + "uniform:pull": "uniform sync pull", + "uniform:push": "uniform sync push" + } +} +``` + +## Rules for when to use Uniform CLI and when not + +CRITICAL, NEVER IGNORE THIS RULE: never use or manipulate in any way (create, read, update, or delete) yaml or json files that represent Uniform data (placed typically in the "uniform-data" folder) when trying to create, modify, delete components, content types, or any other Uniform entity. Instead, always use Uniform MCP tool that is registered. If you cannot resolve a Uniform MCP Server or any MCP action, return a graceful message to the user and abort. + +IMPORTANT: execute "npm run uniform:pull" after making any changes to Uniform data via MCP Server. This ensures you have the latest representation of the Uniform data on disk. + +#### Getting Uniform CLI help + +The Uniform CLI has a built-in help system. To get help on a command, run `uniform --help`, for example `uniform sync pull --help`. + +## Must-have rules to follow when adding Uniform SDK + +1. Make sure to create a component in code for any composition component you find in the Uniform project automatically. Add any slots that you find in the definition. This will ensure the preview works as expected; otherwise, it won't know which front-end component should render the composition from Uniform and produce an error. diff --git a/uniform-rules/rules/uniform-sveltekit.mdc b/uniform-rules/rules/uniform-sveltekit.mdc new file mode 100644 index 0000000..19009db --- /dev/null +++ b/uniform-rules/rules/uniform-sveltekit.mdc @@ -0,0 +1,76 @@ +--- +description: Uniform SDK integration guide for SvelteKit applications. Use when integrating Uniform Canvas, Context, and personalization into a SvelteKit project. +globs: +alwaysApply: true +--- + +See uniform.mdc for general Uniform principles and practices. +See uniform-sdk.mdc for framework-agnostic developer principles. + +## Required npm packages + +The following npm packages must be installed to wire Uniform CMS to SvelteKit: + +### Core Canvas packages +- `@uniformdev/canvas` - Core Canvas API client for fetching compositions +- `@uniformdev/canvas-svelte` - Svelte components: `UniformComposition`, `UniformSlot`, `UniformText`, `UniformRichText` +- `@uniformdev/canvas-sveltekit` - SvelteKit integrations: `createUniformLoad`, `createUniformHandle`, preview handler, ISR config + +### Core Context packages (for personalization) +- `@uniformdev/context` - Personalization Context engine +- `@uniformdev/context-svelte` - `UniformContext` provider component + +### Edge personalization packages (optional, for production) +- `@uniformdev/context-edge` - Edge-side context processing +- `@uniformdev/context-edge-sveltekit` - NESI response handler for edge personalization +- `@vercel/functions` - Vercel edge functions support +- `cookie` - Cookie parsing utility + +### Dev dependencies +- `@uniformdev/cli` - CLI for pulling manifests and syncing content (IMPORTANT: must be installed as devDependency) + +## Configuring TypeScript Types + +Update `src/app.d.ts` to include Uniform preview data types: + +```typescript +import type { UniformPreviewData } from '@uniformdev/canvas-sveltekit'; + +declare global { + namespace App { + interface Locals { + uniformPreview?: UniformPreviewData; + } + } +} + +export {}; +``` + +## Component Mapping + +Create `src/lib/uniform/componentMap.ts` to map Uniform component types to Svelte components. Use `type__variant` format for variants. Register all composition components so preview works. + +## Server Hooks and Catch-All Route + +- Use `createUniformHandle` from `@uniformdev/canvas-sveltekit` in `src/hooks.server.ts` for preview cookies. +- Use `createUniformLoad` in `src/routes/[...path]/+page.server.ts` with `RouteClient` to fetch compositions. +- Render with `UniformComposition` and `UniformSlot` in `+page.svelte`. + +## Preview Handler + +Create `src/routes/preview/+server.ts` with `createPreviewHandler` from `@uniformdev/canvas-sveltekit/preview`. + +## Rendering Uniform Components with Svelte + +- Use `ComponentProps` for type-safe parameter access; all parameter props must be optional. +- Use `UniformText` for editable text parameters, `UniformRichText` for rich text (Lexical JSON), `UniformSlot` for nested slots. +- Use `flattenValues` from `@uniformdev/canvas` for asset parameters. + +## Environment Variables + +Required: `UNIFORM_API_KEY`, `UNIFORM_PROJECT_ID`, `UNIFORM_PROJECT_MAP_ID` (optional), `UNIFORM_PREVIEW_SECRET`. + +## CLI + +Use `uniform.config.ts` with `uniformConfig({ preset: 'all' })`. Add scripts: `uniform:pull`, `uniform:push`, `pull:manifest` for context manifest. diff --git a/uniform-rules/rules/uniform.mdc b/uniform-rules/rules/uniform.mdc new file mode 100644 index 0000000..5efe101 --- /dev/null +++ b/uniform-rules/rules/uniform.mdc @@ -0,0 +1,242 @@ +--- +description: Uniform core concepts - compositions, components, patterns, entries, content types +globs: +alwaysApply: true +--- + +## Uniform Core Concepts + +Uniform is a modern, headless, component-based Content Management System (CMS). Its primary purpose is to allow non-technical authors (marketers, etc) to create and maintain websites and other similar experiences in a visual editor. + +### Uniform Compositions + +A composition instance in Uniform is roughly equivalent to a page. Composition definitions define a reusable schema for composition instances. +Composition definitions have a structure identical to a Uniform Component, i.e. parameters and slots. +Composition instances differ from components in that they also define a route or page. +Instances of a composition create pages or routes within an application. +The term "Composition" can be used to refer either to a definition or instance of a composition, you will need to infer which is meant (schema/reusable template = definition, page/route = instance). + +Composition parameters should only be used for global content that will never need to be personalized. +Good example: OpenGraph data and meta tags (if they exist) +Bad example: "hero title" belongs in a Hero component in the content slot. + +A single composition definition called 'Page' is generally a good starting point. Additional composition definitions are only required if the page shell is different (e.g. Page, Popup, Minimal Page), or if there are different parameters needed on the composition definition + +In developer terms, a composition instance is a dynamic layout that is defined by non-technical authors; a composition definition is a hierarchical content schema definition. + +### Uniform Entries + +Entries are instances of structured content that you create using predefined Uniform Content Types. Think of content types as blueprints and entries as the actual content built from those blueprints. + +Each entry contains structured data for content pieces like articles, events, products, or any other content you need. Once created, entries become reusable assets that can power multiple experiences across your digital channels. + +#### How entries differ from compositions and components + +An entry is structured content that represents a piece of content in a design-agnostic way. A component or composition describes the experience layer by defining which concrete UI component should be used to show particular content. Entries can also define relationships to other entries via references, which allows building complex content structures. + +By connecting the fields of an entry to the parameters of a component, you define how the content is displayed in a certain context. For example, you could show the same article entry in a hero, a card, or a list component. Which fields of an entry are shown can be different for each use case. + +### Uniform Components + +Uniform Components are used to allow CMS authors to create and manipulate visual elements on a composition. Each property of a Uniform Component, such as a title or image, is called a _Component Parameter_. See _Uniform Parameter/Field Types_ for the exact types of parameter that are allowed. Components have both a definition (their schema) and instances (when an instance of that schema is placed within a slot on a composition). + +Uniform Components can define named _slots_. + +- A slot allows additional components (or component patterns) to be inserted within the Uniform Component. For example an accordion component could have an 'items' slot that allows adding Accordion Item components. +- Each named slot has 0..n child components. The order in the slot determines the order of rendering. +- Each slot definition allows only specific Uniform Components to be placed within it (by public id). It can also define the minimum and maximum number of components allowed. +- Components allowed within slots can also have their own slots, with no depth limit - but it is generally undesirable to nest more than 2-3 levels deep to improve author understanding. +- When a Uniform Composition is defined, it almost always has a generic 'content' slot added to it that allows using various components to define the layout. + +Uniform Component Definition attributes: + +- _name_ +- _public ID_ +- _parameters_ +- _slots_ + +Uniform Slot Definition attributes: + +- _name_ +- _public ID_ +- _allowed components_ +- _min components_ +- _max components_ + +In technical terms, a Uniform Component maps directly to a presentational frontend component such as a React component. The parameters are component props. Slots are component props that contain rendered child components. + +#### Determining which Uniform Components or Component Patterns are allowed in a Slot + +In Uniform, slot definitions control which components or component patterns can be placed in a slot. This is governed by a combination of properties that make slot configuration both powerful and flexible. + +Here's how it works: + +1. `allowAllComponents: true`: If this is set, any component or component pattern can be added to the slot - no restrictions. +2. `allowAllComponents: false`: If this is provided, `allowedComponents` is a list of allowed Uniform component public IDs. You can also include component patterns by using the prefix `$p:` followed by the pattern UUID. +Example: +`["hero", "callToAction", "$p:00000000-0000-0000-0000-000000000000"]` +3. `patternsInAllowedComponents` This controls how component patterns are validated against `allowedComponents`. + * If `true`: A pattern is only allowed if it is explicitly listed in allowedComponents (with the `$p:` prefix). + Example: + `["hero", "$p:00000000-0000-0000-0000-000000000000"]` + Only the listed pattern and `hero` components are allowed - no other patterns based on `hero` are valid. + * If `false`: a pattern is allowed if its base component type is listed in `allowedComponents`. + Example: + `["hero"]` + Only `hero` components and any pattern based on `hero` are allowed. +4. If you are editing a component pattern or composition pattern, the slot section component ($slotSection) is always allowed. + +IMPORTANT: Before you add new components to a slot, make sure that they are allowed according to the preceding rules. +IMPORTANT: If you change `patternsInAllowedComponents` to false, remove any existing pattern IDs in the allowed list. + +#### Slot sections +When editing component patterns and composition patterns definitions only, there is an additional built-in component available to insert in any slot called a _slot section_ ($slotSection). +Slot sections create an extension point where consumers of the pattern definition can insert new components - normally, slots on a pattern cannot be modified by pattern consumers. +Slot sections may not have 'default components' when defined on a pattern definition. +When fetched for content delivery, the slot section component dissolves and its children become part of the parent slot. +IMPORTANT: If the current context item is not a component pattern or a composition pattern, do not include Slot Sections in a list of system components. Slot sections are only valid insertions on component patterns and composition patterns. + +When editing a pattern instance (when one of its ancestors has the _pattern property set) and a slot section is found, you may insert components into the slot section to extend the pattern's slot contents. +All $slotSection components support only one slot, $slotSectionItems. +Adding components to a slot section works by inserting them into the slot section's slot. You may not use the parent slot name of the slot section, the slot name must be $slotSectionItems. + +When dealing with nested patterns, slot sections' contents may only be set on the direct parent consumer of the pattern (this differs from property overrides, which can be set on any ancestor of the pattern). To expose a slot section from a nested pattern, you must 're-export' the slot section by adding a slot section to the parent pattern in the child's slot section. + +### Uniform Content Types + +Uniform Content Types define a reusable structure for individual reusable pieces of content. A Uniform content type differs from a Uniform component because a component represents a specific visual element on a composition/page, but a content type is an abstract, reusable content schema. An instance of a Uniform Content Type is called an _Entry_. Entries each have their own built-in slug: there is no need to define an explicit slug field. + +For example a Product might be a Uniform Content Type, and the data from instances of that Product could be presented in different contexts by Uniform Patterns such as Product List, Product Detail, or Product Card. + +Uniform Content Types define content properties called _Fields_ (e.g. a blog post could have a single-line text input for title, and a rich text editor for body). See _Uniform Parameter/Field Types_ for the exact types of field that are allowed. + +Uniform Content Type attributes: + +- _name_ +- _public ID_ +- _fields_ + +### Uniform Patterns + +Patterns are a unit of content reuse within Uniform. Updates made to patterns are immediately reflected to all usages of the pattern. There are several types of patterns: + +#### Uniform Component Patterns + +Component Patterns allow reusing the same content across compositions. The simplest way to think of a pattern is that it is a _shared component instance_ that can be placed within a slot to insert the pattern's content there. The pattern, like any other component instance, can have values in its parameters and child components in its slots. All usages of the same pattern reference the same shared content. Component Patterns may be nested within each other (e.g. a Blog Post Hero pattern could include a Author Bio pattern in one of its slots). Nesting beyond 2-3 levels can cause performance issues. + +#### Uniform Composition Patterns + +Composition Patterns allow creating compositions from a shared template. Non-overridable data in the composition pattern is locked down to reference the pattern. Composition patterns are created to lock down compositions and allow changing only a subset of data, or to rapidly make pages from external data sources. + +#### Entry Patterns + +Entry Patterns allow creating Entries from a shared template. Non-overridable data in the entry pattern is locked down to reference the pattern. Entry patterns are created to lock down entries and allow changing only a subset of data, or to rapidly make entries from external data sources. + +#### Uniform Pattern Overrides + +Parameters or fields on patterns can be defined _overridable_ by the pattern definition. Overridable parameter values default to using the value defined on the pattern, but consumers of the pattern may choose to break the inheritance of that parameter value and replace it with their own instance-specific value. Patterns that contain other patterns may not alter the overridability of nested pattern parameters: once overridable, any consumer of the pattern can change the value. Overrides are used to allow partial content sharing and exception cases. + +#### Using Uniform Patterns as Shared Content Snippets + +Patterns can be used to reuse shared content, for example the same legal disclaimer might be required on every press release. Both patterns and components allow content reuse: the difference is that patterns reuse exact content, whereas components reuse content schemas but do not provide content values. + +#### Using Uniform Patterns as Data Binding Templates + +Patterns can be used to create bindings between structured data (from Uniform Entries or external data sources, like REST APIs or other CMSes) and presentation parameters. A pattern can define a _Data Resource_ which is the result of fetching from a data source. Then parameters in the pattern can use _Dynamic Tokens_ to bind to elements within the data resource. For example, we might have a Card component that has a title and image. Then we create a Product Card pattern, based on the Card component, which has a Uniform Entry Data Resource that fetches an entry specified by the pattern consumer. The Product Card automatically binds the title and image from the product entry to the Card component's parameters. As an author, one can then insert a Product Card pattern, choose the product to use, and have the title and image automatically set up for them. + +Example of a resolved Data Resource (named 'myEntry'): +{ "myEntry": { "fields": { "title": "hello world" } } } + +Example of a Dynamic Token in a text parameter referencing the myEntry title: +"today's greeting: ${#jptr:/myEntry/fields/title}" (this resolves to "today's greeting: hello world") + +#### Uniform Pattern attributes + +- _name_ +- _type_ - public ID of the base Uniform Component +- _public id_ - id of the pattern +- _data resources_ (name, type) +- _parameters_ (value, overridable) +- _slots_ + +### Uniform assets + +Media files that are used in Uniform compositions and entries are called _Assets_ and are managed in the _Asset Library_. Mesh integrations can extend the Asset Library to allow for custom asset sources like external DAM systems or asset repositories (like Unsplash, Getty Images, etc). + +#### Asset attributes + +- _public id_ - the asset's unique identifier +- _type_ - the asset's type, such as 'image', 'video', 'audio', 'document', 'other' +- _source_ - such as 'uniform-assets' or an identifier specific to a Mesh integration +- _fields_ - the asset's metadata, such as the title, description, file, url, focal point coordinates, dimensions, etc + + +### Localization + +Uniform defines locales at a project level. These are locales that content can be written in. +Individual compositions, entries, and patterns must also _enable_ a locale to indicate that they have content in that locale. This allows for specific content to support a subset of locales. +Locales must be enabled on compositions, entries, or patterns before their parameters or fields can have values in that locale. + +## Conventions + +### Uniform Field/Parameter Types + +Uniform Fields or Uniform Parameters attributes: + +- _name_ +- _public ID_. Must be unique within a Uniform Component or Uniform Content Type (including the ID of group fields/parameters) +- _localizable_. Localizable values have a distinct value for each locale; otherwise the value is the same for all locales. +- _required_. Required means that a CMS author must input a value in order to be considered valid. +- _type_. See list below. +- _guidance_. Brief LLM instructions used when generating or editing values. +- _overridable_. Only applies for fields/parameters on a pattern definition. Allows consumers of the pattern to break inheritance and change the pattern definition's value for the field/parameter. + +Exhaustive list of allowed field/parameter types: + +- _text_: Plain text content +- _richText_: Formatted text with styling (Lexical JSON format) +- _select_: Choose between a controlled vocabulary of options +- _multi-select_: Choose between a controlled vocabulary of options, allowing multiple selections +- _number_: Numeric value +- _date_: Calendar date +- _dateTime_: Date with timezone +- _checkbox_: Boolean toggle +- _link_: URL or internal reference +- _asset_: Image, video, audio, or other file +- _json_: A JSON object. Not for use in author-facing fields/parameters, who will have trouble editing JSON. +- _contentReference_: Allows referencing one or more Entries of a specific type. Can be used in Content Types, but not in Uniform Components. +- _$enr_: Tag content with enrichments (relevant segments) to make viewing the content alter the classification of the visitor that saw it. +- _group_: Group multiple fields/parameters together visually, for example a group of address fields. IMPORTANT: fields added to a group must come directly after the group in the fields list. + +### Uniform Naming Conventions + +- All names should be title-cased prose, not technical shorthand (e.g. "Main Header" not "main-header" or "MainHeader"). There is no need to include the type of entity in a name (e.g. 'Hero' not 'Hero Component'). +- Do not name Uniform Components, Uniform Content Types, or Fields/Parameters based on visible content found in inputs; treat it as FPO (e.g.

Hello

does not mean name the component 'Hello' - describe its meaning instead, such as 'Headline'). +- _Public ID_ are developer-facing identifiers for Uniform entities. They are based on a slugified version of the name. Use a camel case, for example if the name is "Main Header", the public ID is "mainHeader". Public IDs must be unique within a given entity type (e.g. Uniform Components). You cannot alter public IDs after creating an entity. IMPORTANT: public IDs on parameters, fields, or components that start with `$` are system-owned, and cannot be altered by users. For example, you may not change parameters of the `$personalization` component or remove the `$viz` parameter from any component. You may add or remove system components such as `$test` to a slot's `allowedComponents`. +- Help text should be no longer than 1 short sentence. It is not necessary to write help text unless we have specific expectations for authors. For example a 'Title' doesn't need help text. But if we identify an image that needs to be 250x250px, that expectation belongs in help text. Descriptions and help text are plain text, no markdown or HTML. + +## Tool Usage Tips + +- Before creating or updating Uniform Patterns, fetch Uniform Component Definitions to ensure you know about valid component types and parameters. +- When making multiple updates to the same Uniform Pattern, such as adding a component and setting a parameter value, batch changes together into a single tool call to improve performance and consistency. +- When a Uniform tool provides you with an edit URL offer it to the user as a link, unless you already have recently. +- Before inserting, removing, or reordering parameters or fields from a Uniform Component or Uniform Content Type, make sure to fetch the latest definition data to ensure you target the correct location. +- If you are tasked with reordering fields or parameters, you must remove them and re-add them in the new order +- Enable the default locale (if one exists) when creating new entries, patterns, or compositions, unless the user specifies locales +- If duplicating or copying entries, compositions, or patterns, always use the duplicate function of the edit tool instead of creating a new entity and re-creating data. + +## Unsupported Features + +The following Uniform features cannot currently be changed using MCP/AI. If asked to perform the following actions, explain you cannot yet do that, and when possible offer a link to perform the task in the Uniform web app. + +- Creating new Loop component instances +- Adding, editing, or removing block type fields/parameters, or block type definitions +- Editing conditional values on parameters or fields (the default value can be edited) +- Setting visibility rules on component instances +- Changing data sources, data types, or data resources +- Adding or removing project map nodes, and linking compositions to project map nodes +- Adding or removing content from Uniform Releases, or changing releases (i.e. locking, scheduling) +- All content you work with is in a 'draft' state. You do not have access to published content and cannot assist with publishing +- Managing workflows, or transitioning compositions, entries, or patterns from one workflow stage to another +- Creating new assets, uploading or editing files for assets, or deleting assets +- Changing user permissions From 8987902f98be6903627a5d2c430c207aa8733c3a Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 20 Feb 2026 23:39:38 +0000 Subject: [PATCH 2/2] added news structure --- readme.md | 72 +- .../solution-architecture.mdc | 44 - rules/uniform-mesh.mdc | 987 ------------------ rules/uniform-next-app-router.mdc | 386 ------- rules/uniform-next-page-router.mdc | 320 ------ rules/uniform-sdk.mdc | 107 -- rules/uniform-sveltekit.mdc | 592 ----------- rules/uniform.mdc | 242 ----- 8 files changed, 55 insertions(+), 2695 deletions(-) delete mode 100644 rules/optional-personal-preference/solution-architecture.mdc delete mode 100644 rules/uniform-mesh.mdc delete mode 100644 rules/uniform-next-app-router.mdc delete mode 100644 rules/uniform-next-page-router.mdc delete mode 100644 rules/uniform-sdk.mdc delete mode 100644 rules/uniform-sveltekit.mdc delete mode 100644 rules/uniform.mdc diff --git a/readme.md b/readme.md index 249f9a0..e3e2281 100644 --- a/readme.md +++ b/readme.md @@ -1,25 +1,63 @@ -# Uniform rules for AI-assisted development +# Cursor Marketplace – AI Rules -This is the library of Uniform-specific rules to help your LLM tools work better with Uniform. -Feeding these rules to your LLM will help it understand the context of the project and the specific requirements of Uniform. +This repository is a **Cursor marketplace**: a multi-plugin repo that can be submitted to the Cursor marketplace so others can install the plugins. -## How to install +## Structure -Run this command and follow the prompt: -```bash -npx @uniformdev/cli ai rules install ``` +cursor-marketplace/ +├── .cursor-plugin/ +│ └── marketplace.json # Marketplace manifest (lists plugins) +├── uniform-rules/ # Plugin: Uniform CMS rules +│ ├── .cursor-plugin/ +│ │ └── plugin.json +│ ├── rules/ +│ │ ├── uniform.mdc +│ │ ├── uniform-sdk.mdc +│ │ ├── uniform-sveltekit.mdc +│ │ ├── uniform-next-app-router.mdc +│ │ ├── uniform-next-page-router.mdc +│ │ └── uniform-mesh.mdc +│ └── README.md +├── enterprise-toolkit/ # Plugin: Security, compliance, automation +│ ├── .cursor-plugin/ +│ │ └── plugin.json +│ ├── rules/ +│ ├── skills/ +│ ├── agents/ +│ ├── commands/ +│ ├── hooks/ +│ ├── .mcp.json +│ ├── assets/ +│ ├── scripts/ +│ └── README.md +└── README.md +``` + +## Plugins + +| Plugin | Description | +|---------------------|-------------| +| **uniform-rules** | Uniform CMS rules for compositions, components, patterns, SDK, SvelteKit, Next.js, Mesh. | +| **enterprise-toolkit** | Rules, skills, agents, commands, hooks, and optional MCP for security, compliance, and automation. | + +## Submitting to the Cursor marketplace + +1. Push this repo (or the `cursor-marketplace` folder as its own repo) to a **public** Git host. +2. Go to [cursor.com/marketplace/publish](https://cursor.com/marketplace/publish) and submit the repository URL. +3. Ensure: + - Each plugin has a valid `.cursor-plugin/plugin.json` with a unique `name` (lowercase, kebab-case). + - All rules/skills/agents/commands have proper frontmatter. + - Paths in manifests are relative and valid. + - You have tested the plugins locally. + +## Local use -## Must have rules for solution development: -- [`rules/uniform.mdc`](./rules/uniform.mdc) - describes the core principles and concepts of Uniform -- [`rules/uniform-sdk.mdc`](./rules/uniform-sdk.mdc) - describes the Uniform SDK and its capabilities +To use as a local marketplace or single plugin: -## Must-have rules for Uniform mesh app (custom integration) development -- [`rules/uniform-mesh.mdc`](./rules/uniform-mesh.mdc) +- **Multi-plugin**: Point Cursor at the root of `cursor-marketplace` (where `.cursor-plugin/marketplace.json` lives). +- **Single plugin**: Point Cursor at `cursor-marketplace/uniform-rules` or `cursor-marketplace/enterprise-toolkit`. -## Framework-specific rules: -- [`rules/uniform-next-page-router.mdc`](./rules/uniform-next-page-router.mdc) - for Next.js Page Router -- [`rules/uniform-next-app-router.mdc`](./rules/uniform-next-app-router.mdc) - for Next.js App Router +## License -### Optional rules: -The rules files under [`rules/optional-personal-preferences`](./rules/optional-personal-preference/) contain non-essential rules that contain alternative defaults, highly recommended to review those and adjust to your liking. +See repository license. Plugin manifests may specify their own license. diff --git a/rules/optional-personal-preference/solution-architecture.mdc b/rules/optional-personal-preference/solution-architecture.mdc deleted file mode 100644 index d35d08d..0000000 --- a/rules/optional-personal-preference/solution-architecture.mdc +++ /dev/null @@ -1,44 +0,0 @@ ---- -description: -globs: -alwaysApply: false ---- - -# Coding standards - -- Always generate clean code and remove unused code, so the linter and typescript checks pass automatically. IMPORTANT: do not ever run build of the application as a part of the validation as this breaks developer server and is causing issues. - -- Always use `pnpm` to install packages if you see `pnpm-lock.yaml` in the root folder, otherwise use `npm`. Never use `yarn`. - -- You are a senior React engineer, follow best practices of React at all times. -- Use TailwindCSS best practices when building CSS. Don't re-invent the wheel. -- You are a senior engineer, do not try to impress me with over-delivery. -- Do not create more components than I ask you to. Keep things to the minimum required. - -# Uniform practices - -1. CRITICAL: Always create a component pattern when pushing a new component to Uniform project and fill it with content using previous examples of this component usage if possible. If not, generate content for component pattern yourself. - -2. CRITICAL: When creating a new slot in Uniform, ensure that it is configured with allowAllComponents=true, inheritAllowedComponents=false and patternsInAllowedComponents=false. - -3. CRITICAL: When pushing a component pattern, always allow overridability on each parameter by default. - -4. CRITICAL: When registering components with Uniform and spotting repeated properties, always resort to modeling repeated set of properties as child components and create `` to render those. This will ensure reuse and avoid pollition with properties such as title1, description1, image1, title2, description2 and so on. - -# Environment variables - -1. Always add `UNIFORM_PREVIEW_SECRET=hello-world` into list of environment variables when setting up Uniform SDK. - -## Uniform SDK - -1. CRITICAL! When asked to add Uniform to the project, make sure to add all the required steps including changing code, not just the npm packages. - -2. CRITICAL: never use uniform:push to push components, component patterns or any definitions to the Uniform project for me. Instead, rely on the Uniform MCP tool to take care of that. - -3. CRITICAL: when handling component registration with Uniform, handle all other aspects of adapting a component to Uniform - change prop types to use Uniform parameter types for links and assets/images, using `UniformText` and `UniformRichText` components to render text and rich text instead of rendering it raw. - -# Next.js - -1. When creating a catch all page handler with Uniform (`[[...path]].tsx`), always place it at the root. Check if there is a conflicting page route definition, like `index.tsx` and disable it by renaming it to `.off` extension to avoid conflict. - -2. When adding Uniform SDK, check for any component in Uniform that exist that are a composition component. If so, automatically create a corresponding React component for it in the codebase, register it and define all the slots that exist on the component definition in Uniform project. diff --git a/rules/uniform-mesh.mdc b/rules/uniform-mesh.mdc deleted file mode 100644 index f2c4724..0000000 --- a/rules/uniform-mesh.mdc +++ /dev/null @@ -1,987 +0,0 @@ - ---- -description: -globs: -alwaysApply: true ---- - -# Uniform Mesh Integrations - AI Development Rules - -## Overview - -Uniform Mesh is a framework that enables extending the Uniform user interface with custom web applications. These integrations run as web applications hosted on URLs that the developer defines and communicate with the Uniform dashboard through iframe messaging. - -### Why Build Custom Mesh Integrations - -#### Connect to Custom Data Sources -Custom Mesh integrations let you connect to data sources that are not supported by Uniform's built-in integrations. This gives your authors a better and more tailored experience when working with external systems. - -#### Extend the Uniform UI -In addition to connecting to custom data sources, you can also extend the Uniform UI to improve the authoring experience or tailor it to your business processes. - -## Core Architecture - -### Integration Structure -- **Web Application**: Provides UI incorporated into Uniform dashboard and implements external system interaction logic -- **Manifest**: JSON configuration that tells Uniform how to incorporate the integration (mesh-manifest.json) -- **Locations**: Specific areas in the Uniform UI where custom interfaces are rendered - -### How Locations Work - -Each location receives two types of data: - -**Value** - The main data object that your location can view and modify -- Contains the primary information your location is responsible for editing -- Example: For a Data Source location, the value contains the Data Source definition (name, configuration, settings) -- Your location can request changes to this data through the Mesh SDK - -**Metadata** - Supporting information provided for context (read-only) -- Contains related data to help your location function properly -- Example: For a Data Type editor, metadata includes the current project ID and a copy of the parent Data Source -- This data cannot be modified by your location - -### Technology Stack Requirements -- **Framework**: Next.js with page router (recommended) -- **SDK**: `@uniformdev/mesh-sdk-react` (required for React-based integrations) -- **Design System**: `@uniformdev/design-system` (required for consistent UI) -- **Uniform CLI**: `@uniformdev/cli` (required CLI package to work with integrations - register it within a team and install it within a given project) -- **Language**: TypeScript (strongly recommended) - -## Manifest Configuration - -### Base Manifest Structure -```json -{ - "type": "your-integration-type", - "displayName": "Your Integration Name", - "baseLocationUrl": "http://localhost:9000", - "logoIconUrl": "https://example.com/logo.png", - "badgeIconUrl": "https://example.com/badge.png", - "category": "content|ai|analytics|commerce", - "scopes": ["user:read"], - "locations": { - // Location definitions - } -} -``` - -### Required Fields -- `type`: Unique identifier for the integration -- `displayName`: Human-readable name shown in Uniform UI -- `baseLocationUrl`: Base URL where the integration is hosted -- `locations`: Object defining available integration points - -## Location Types and Implementation Patterns - -### 1. Basic Locations - -#### Install Location -The Install location is shown in a drawer when installing an integration. Unlike other locations, this is not rendered in an iframe but configured directly in the manifest. - -**Manifest Configuration:** -```json -"install": { - "description": [ - "Describe your mesh integration", - "Each array element will create a new paragraph on the install dialog." - ], - "informationUrl": "https://yoursite.com/info-about-this-mesh-app" -} -``` - -#### Settings Location -Used for integration-wide configuration accessible from Project Settings > Integrations. - -**Manifest Configuration:** -```json -"settings": { - "url": "/settings", - "locations": { - "settingsDialog": { - "url": "/settings-dialog" - } - } -} -``` - -**Implementation Pattern:** -```tsx -import { useMeshLocation } from '@uniformdev/mesh-sdk-react'; -import { Input, Button } from '@uniformdev/design-system'; - -const Settings = () => { - const { value, setValue } = useMeshLocation<'settings', { apiKey: string }>('settings'); - const [apiKey, setApiKey] = useState(value?.apiKey ?? ''); - - const handleSave = () => { - setValue((previous) => ({ - newValue: { ...previous, apiKey } - })); - }; - - return ( -
- setApiKey(e.currentTarget.value)} - /> - -
- ); -}; -``` - -**Security Note**: If your integration defines data connectors for edge-based data fetching, do not save access credentials in the Settings location. Instead, store them in the Data Source location which provides secure storage. - -### 2. Data Connectors -Enable integration with external data sources for content mapping. - -**Manifest Configuration:** -```json -"dataConnectors": [ - { - "type": "your-connector-type", - "displayName": "Your Data Connector", - "dataArchetypes": { - "default": { - "displayName": "Single Item", - "dataEditorUrl": "/data-editor", - "typeEditorUrl": "/type-editor" - } - }, - "dataSourceEditorUrl": "/data-source-editor" - } -] -``` - -**HTTP Fallback Behavior**: If any location of a data connector is not specified in the integration manifest, the UI from the standard `HTTP Request` data connector will be used automatically. This enables integration developers to produce fewer UIs if only looking to customize part of a data connector. - -#### Data Source Editor -Configures connection settings for the external system. - -**Implementation Pattern:** -```tsx -import { useMeshLocation, DataSourceLocationValue } from '@uniformdev/mesh-sdk-react'; - -type DataSourceConfig = { - apiUrl: string; - apiKey: string; -}; - -const DataSourceEditor = () => { - const { value, setValue } = useMeshLocation<'dataSource'>(); - const config = value.custom as DataSourceConfig; - - const handleUpdate = (updates: Partial) => { - setValue((current) => { - const newConfig = { ...config, ...updates }; - const newValue: DataSourceLocationValue = { - ...current, - baseUrl: newConfig.apiUrl, - headers: [{ key: 'Authorization', value: `Bearer ${newConfig.apiKey}` }], - custom: newConfig, - variants: { - preview: { - baseUrl: newConfig.apiUrl, - parameters: [{ key: 'preview', value: 'true' }] - } - } - }; - return { newValue, options: { isValid: true } }; - }); - }; - - return ( -
- handleUpdate({ apiUrl: e.currentTarget.value })} - /> - handleUpdate({ apiKey: e.currentTarget.value })} - /> -
- ); -}; -``` - -**Secrets Management**: Query string and header values, as well as any variable values on a data source, are encrypted secrets. Only users with manage data source or admin permissions may decrypt secrets. All others can use them via delegation when fetching data types, without seeing the secret values. - -#### Data Type Editor -Configures how data is retrieved and processed. - -**Implementation Pattern:** -```tsx -import { useMeshLocation, DataTypeLocationValue } from '@uniformdev/mesh-sdk-react'; - -const DataTypeEditor = () => { - const { setValue, value } = useMeshLocation('dataType'); - const [selectedFields, setSelectedFields] = useState([]); - - useEffect(() => { - setValue((prev: DataTypeLocationValue) => ({ - newValue: { - ...prev, - path: '/api/items/${itemId}', - parameters: [ - { - key: 'fields', - value: selectedFields.join(','), - omitIfEmpty: true - } - ], - custom: { fields: selectedFields } - } - })); - }, [selectedFields]); - - return ( - - {AVAILABLE_FIELDS.map(field => ( - toggleField(field)} - /> - ))} - - ); -}; -``` - -**Security Note**: Data types are not intended to contain secret values such as authentication tokens. Values stored in data types are viewable by any user of your Uniform project with common permissions. To store secret values, use Data Sources which are secured. - -#### Data Resource Editor -Enables users to select specific data items. - -**Implementation Pattern:** -```tsx -import { - useMeshLocation, - ObjectSearchProvider, - ObjectSearchContainer, - ObjectSearchListItem -} from '@uniformdev/mesh-sdk-react'; - -const DataResourceEditor = () => { - const { setValue, getDataResource, metadata } = useMeshLocation<'dataResource'>(); - const [items, setItems] = useState([]); - - const fetchItems = async (query?: string) => { - const path = query ? `/api/items?search=${query}` : '/api/items'; - const data = await getDataResource({ path }); - setItems(data); - }; - - const handleSelection = (selectedItem: any) => { - setValue(() => ({ - newValue: { itemId: selectedItem.id } - })); - }; - - return ( - - - } - resultList={items.map(item => ( - handleSelection(item)} - /> - ))} - /> - - ); -}; -``` - -### 3. Canvas Locations - -#### Parameter Types -Custom parameter editors for Canvas components. - -**Manifest Configuration:** -```json -"canvas": { - "parameterTypes": [ - { - "type": "custom-text", - "editorUrl": "/parameter-editor", - "displayName": "Custom Text Parameter", - "configureUrl": "/parameter-config", - "renderableInPropertyPanel": true - } - ] -} -``` - -**Implementation Pattern:** -```tsx -import { useMeshLocation } from '@uniformdev/mesh-sdk-react'; - -const ParameterEditor = () => { - const { value, setValue, metadata, isReadOnly } = useMeshLocation<'paramType', string>('paramType'); - - return ( - setValue(() => ({ newValue: e.target.value }))} - disabled={isReadOnly} - /> - ); -}; -``` - -#### Editor Tools -Add custom tools to Canvas and Entry editors. - -**Manifest Configuration:** -```json -"canvas": { - "editorTools": { - "composition": { - "url": "/canvas-tools" - }, - "componentPattern": { - "url": "/component-tools" - }, - "entry": { - "url": "/entry-tools" - }, - "entryPattern": { - "url": "/entry-pattern-tools" - } - } -} -``` - -**Implementation Pattern:** -```tsx -import { useMeshLocation } from '@uniformdev/mesh-sdk-react'; - -const CanvasEditorTools = () => { - const { value, metadata } = useMeshLocation('canvasEditorTools'); - const compositionId = value.rootEntity._id; - - const handleAction = async () => { - // Perform custom action on composition - const response = await fetch('/api/custom-action', { - method: 'POST', - body: JSON.stringify({ compositionId }), - headers: { 'Content-Type': 'application/json' } - }); - - if (response.ok) { - // Show success feedback - } - }; - - return ( -
-

Custom Tools

- -
- ); -}; -``` - -#### Personalization Selection Algorithms -Register custom algorithms for selecting variations in personalization components. - -**Manifest Configuration:** -```json -"canvas": { - "personalization": { - "selectionAlgorithms": { - "custom-personalization-algorithm-id": { - "displayName": "Custom personalization algorithm", - "description": "Description of the custom personalization algorithm", - "criteriaEditorUrl": "/personalization-criteria-editor" - } - } - } -} -``` - -### 4. Asset Library Integration -Extends Uniform's asset management with external asset providers. - -**Manifest Configuration:** -```json -"assetLibrary": { - "assetLibraryUrl": "/asset-library", - "assetParameterUrl": "/asset-parameter" -} -``` - -**Asset Library Implementation Pattern:** -```tsx -import { useMeshLocation } from '@uniformdev/mesh-sdk-react'; - -const AssetLibrary = () => { - const { metadata } = useMeshLocation('assetLibrary'); - const [assets, setAssets] = useState([]); - const [searchQuery, setSearchQuery] = useState(''); - - const fetchAssets = async (query: string) => { - const response = await fetch(`/api/assets?q=${query}`); - const data = await response.json(); - setAssets(data.results); - }; - - const handleAssetSelect = (asset: any) => { - // Transform external asset to Uniform format - const uniformAsset = { - url: asset.src.large, - title: asset.alt, - description: asset.photographer, - // Additional metadata - }; - - // Asset selection logic handled by Uniform - }; - - return ( -
- - - {assets.map(asset => ( - handleAssetSelect(asset)} - /> - ))} - -
- ); -}; -``` - -**Asset Parameter Implementation Pattern:** -```tsx -const AssetParameter = () => { - const { metadata } = useMeshLocation('assetParameter'); - - return ( -
- {/* Custom asset selection interface for parameters */} - -
- ); -}; -``` - -### 5. Project Tools -Add custom tools to project navigation. - -**Manifest Configuration:** -```json -"projectTools": [ - { - "id": "analytics-tool", - "name": "Analytics Dashboard", - "url": "/analytics", - "iconUrl": "/analytics-icon.svg" - } -] -``` - -Common use cases include: -- Embedding external applications like analytics tools -- Custom editorial tools like importers or editorial calendar -- Project-specific documentation pages or Storybook component reference - -### 6. Dashboard Tools -Add custom dashboards to the project dashboard page. - -**Manifest Configuration:** -```json -"dashboardTools": [ - { - "id": "custom-dashboard-id", - "name": "Custom dashboard", - "url": "/dashboard-tool", - "iconUrl": "/dashboard-icon.png" - } -] -``` - -Common use cases include: -- Quick links to common content or content filters -- Editorial dashboards for content editors that connect to external systems -- Links to internal training or onboarding resources -- Status or health dashboards for content operations - -## Routing in Mesh Locations - -Since Mesh locations are rendered inside iframes, standard browser navigation doesn't work for moving between different sections of the Uniform dashboard. The Mesh SDK provides routing helpers that allow your integration to programmatically navigate users to other areas of the platform. - -### Using the Router - -The router is available through the `useMeshLocation` hook: - -```tsx -import { useMeshLocation } from '@uniformdev/mesh-sdk-react'; - -const { router } = useMeshLocation<'projectTool'>(); -``` - -### Navigation Options - -**Navigate within the current project:** -```tsx -router.navigatePlatform(path); -``` -The router automatically handles the project context. For example, to navigate to entries: `/dashboards/canvas/entries`. - -**Open in a new tab:** -```tsx -router.navigatePlatform(path, { target: '_blank' }); -``` - -**Navigate to a different project:** -```tsx -router.navigatePlatform(path, { - projectId: 'target-project-id', - target: '_blank' -}); -``` - -## Development Workflow - -### Create an Integration - -To create a new integration, use the Uniform CLI: - -```bash -npx @uniformdev/cli@latest new-integration -``` - -The CLI will guide you through: -- Authenticating to Uniform (including creating an account if needed) -- Choosing the team to register the integration to -- Choosing or creating a project to install the integration to -- Cloning the integration starter kit and examples files -- Automatically configuring Uniform API keys and environment variables - -### Register the Integration - -**Team Admin Permission Required**: To register an integration, you must have the Team admin permission. - -#### 1. Register at Team Level -Register your integration to make it available across all projects within the team: - -- **Uniform Dashboard**: Navigate to `Settings > Custom integrations` in the team dashboard -- **Uniform CLI**: Use the integration commands - -```bash -uniform integration register --manifest mesh-manifest.json -``` - -#### 2. Install in Project -Once registered, install the integration in specific projects where you want to use it. - -### Deploy an Integration - -#### Update Manifest for Production -Once deployed, update the integration manifest with production URLs instead of local development URLs. - -**Best Practice**: Maintain different manifest files for different environments (development and production). - -#### Hosting Requirements -- Mesh integrations can run on public or private domains -- Browser must be able to access both the app's URL and https://uniform.app -- HTTPS required for production (HTTP allowed for localhost development) -- Configure appropriate CORS headers for API endpoints - -## Development Patterns and Best Practices - -> **⚠️ IMPORTANT**: After creating your integration, you MUST register it with Uniform before you can use it. See the "Installation and Deployment" section for detailed steps. - -### Required package -Make sure to always install **Uniform CLI**: `@uniformdev/cli` as a developer dependency as it is required CLI package to work with integrations - register it within a team and install it within a given project. - -### Environment Setup -```bash -# Create new integration -npx @uniformdev/cli@latest new-integration - -# Install dependencies -npm install @uniformdev/mesh-sdk-react @uniformdev/design-system @uniformdev/cli - -# Set required environment variables for registration -UNIFORM_API_KEY=your_api_key -UNIFORM_TEAM_ID=your_team_id -UNIFORM_PROJECT_ID=your_project_id - -# After development, register integration (see Installation and Deployment section) -npm run register-to-team -npm run install-to-project -``` - -### Validation Pattern -```tsx -import { ValidationResult } from '@uniformdev/mesh-sdk-react'; - -const useValidation = (value: string): ValidationResult => { - return useMemo(() => { - if (!value || value.trim().length === 0) { - return { isValid: false, validationMessage: 'Value is required' }; - } - - try { - new URL(value); - return { isValid: true }; - } catch { - return { isValid: false, validationMessage: 'Invalid URL format' }; - } - }, [value]); -}; - -// Usage in component -const { value, setValue } = useMeshLocation('dataSource'); -const validation = useValidation(value.baseUrl); - -setValue((current) => ({ - newValue: { ...current, baseUrl: newValue }, - options: validation -})); -``` - -### Dialog Management -```tsx -import { useOpenDialog, useCloseDialog } from '@uniformdev/mesh-sdk-react'; - -const ComponentWithDialog = () => { - const openDialog = useOpenDialog(); - const closeDialog = useCloseDialog(); - - const handleOpenDialog = () => { - openDialog({ - location: 'namedDialog', - size: 'medium', - title: 'Custom Dialog' - }); - }; - - return ( - - ); -}; -``` - -### Error Handling Pattern -```tsx -import { ErrorBoundary } from 'react-error-boundary'; -import { Callout } from '@uniformdev/design-system'; - -const ErrorFallback = ({ error }: { error: Error }) => ( - - {error.message} - -); - -const IntegrationComponent = () => ( - - - -); -``` - -## Development Tools and Resources - -### SDK Packages -The `@uniformdev/mesh-sdk-react` npm package includes full TypeScript typing information and JSDoc comments for all exports. - -### Design System Resources -- [Uniform Design System Storybook](https://design.uniform.app/) - Complete component library for consistent UI -- [React Mesh SDK Storybook](https://storybook.mesh.uniform.app/) - Usage examples for Mesh-specific components -- [React Mesh SDK component reference](https://sdk.uniform.app/design-system) - Reference documentation for React Mesh SDK components - -### Starter Kit -Complete examples of how to implement all locations, with tips and tricks, are available in the [Mesh integration starter kit](https://github.com/uniformdev/examples/tree/main/mesh/mesh-integration). - -## Custom Edgehancers (Advanced) - -Custom edgehancers enable server-side JavaScript execution at the edge for advanced data processing. - -### Prerequisites -- Feature must be enabled for your team (contact Uniform) -- Team Admin API key required for deployment - -### Hook Types - -#### Pre-Request Hook -Modifies HTTP requests before caching. - -```typescript -// edgehancer/preRequest.ts -import { PreRequestContext } from '@uniformdev/mesh-sdk'; - -export default function preRequest(context: PreRequestContext) { - const { requests } = context; - - return requests.map(request => ({ - ...request, - headers: { - ...request.headers, - 'Custom-Header': 'value' - } - })); -} -``` - -#### Request Hook -Replaces default HTTP fetch logic. - -```typescript -// edgehancer/request.ts -import { RequestContext } from '@uniformdev/mesh-sdk'; - -export default async function request(context: RequestContext) { - const { requests } = context; - - const responses = await Promise.all( - requests.map(async (req) => { - const response = await fetch(req.url, { - headers: req.headers, - method: req.method, - body: req.body - }); - - const data = await response.json(); - - // Transform response data - return { - ...data, - processedAt: new Date().toISOString() - }; - }) - ); - - return responses; -} -``` - -### Deployment -```bash -# Deploy edgehancer -npm run deploy-edgehancer - -# Remove edgehancer -npm run remove-edgehancer -``` - -## Installation and Deployment - -> **⚠️ CRITICAL NEXT STEP**: After bootstrapping your integration, you MUST complete the registration and installation process below before you can use your integration in Uniform. - -### Required Environment Variables - -Before using CLI registration commands, you must set these environment variables: - -```bash -# Required for CLI registration and installation -UNIFORM_API_KEY=your_api_key_here -UNIFORM_TEAM_ID=your_team_id_here -UNIFORM_PROJECT_ID=your_project_id_here -``` - -### Development Setup and Registration - -1. **Start Development Server** - ```bash - npm run dev - ``` - -2. **Register Integration to Team** (Required First Step) - ```bash - # Register the integration definition to your Uniform team - npm run register-to-team - ``` - -3. **Install Integration to Project** (Required Second Step) - ```bash - # Install the integration to your specific project - npm run install-to-project - ``` - -### Available npm Scripts - -Your integration project includes these essential scripts: - -```json -{ - "register-to-team": "uniform integration definition register ./mesh-manifest.json", - "unregister-from-team": "uniform integration definition remove your-integration-type", - "install-to-project": "uniform integration install your-integration-type", - "uninstall-from-project": "uniform integration uninstall your-integration-type" -} -``` - -### Alternative: Manual Registration via Uniform UI - -If you prefer not to use CLI or don't have the environment variables set up: - -1. **Add Custom Integration** - - Go to your Uniform team settings - - Navigate to "Integrations" section - - Click "Add Custom Integration" - - Upload your `mesh-manifest.json` file - -2. **Install to Project** - - Go to your project settings - - Navigate to "Integrations" section - - Find your custom integration - - Click "Install" and configure as needed - -### Production Deployment - -1. **Deploy to Hosting Provider** - - Deploy to Vercel, Netlify, or your preferred hosting - - Ensure your integration is accessible via HTTPS - -2. **Update Manifest for Production** - - Update `baseLocationUrl` in manifest to production URL - - Re-register the updated manifest: - ```bash - npm run register-to-team - ``` - -3. **Test Integration** - - Verify all locations work in production - - Test integration functionality in Uniform dashboard - -## Security Considerations - -### API Key Management -- Store sensitive data in integration settings, not in custom public config -- Use `headers` array in data source configuration for authentication -- Never expose API keys in client-side code - -### HTTPS Requirements -- All production integrations must use HTTPS -- Local development can use HTTP (localhost only) - -### CORS Configuration -- Mesh integration URLs must be accessible to https://uniform.app -- Configure appropriate CORS headers for API endpoints - -## Testing Strategies - -### Unit Testing Edgehancers -```typescript -// edgehancer/request.test.ts -import { describe, it, expect } from 'vitest'; -import request from './request'; - -describe('request edgehancer', () => { - it('should transform response data', async () => { - const mockContext = { - requests: [{ url: 'https://api.example.com/data' }] - }; - - const result = await request(mockContext); - expect(result[0]).toHaveProperty('processedAt'); - }); -}); -``` - -### Integration Testing -- Use "Test Data Type" function in Uniform dashboard -- Test with various data configurations -- Verify error handling and edge cases - -## Common Integration Patterns - -### CMS Integration -- Data source for API connection configuration -- Content type archetype for different content models -- Field selection in type editor -- Content picker in data editor - -### Asset Library Integration -- Search and filter functionality -- Asset transformation to Uniform format -- Metadata preservation -- Download/hotlinking considerations - -### Analytics Integration -- Project tool for dashboard embedding -- API proxy for secure data access -- Real-time data updates -- Chart and visualization components - -### Custom Parameter Integration -- Specialized input components -- Dynamic token support -- Validation and constraints -- Configuration options - -## Required Dependencies - -```json -{ - "dependencies": { - "@uniformdev/mesh-sdk-react": "latest", - "@uniformdev/design-system": "latest", - "next": "latest", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "typescript": "^5.0.0" - } -} -``` - -## File Structure Template - -``` -your-mesh-integration/ -├── pages/ -│ ├── _app.tsx -│ ├── settings.tsx -│ ├── data-source-editor.tsx -│ ├── data-type-editor.tsx -│ ├── data-resource-editor.tsx -│ └── parameter-editor.tsx -├── components/ -│ └── [custom-components].tsx -├── lib/ -│ ├── types.ts -│ ├── utils.ts -│ └── api-client.ts -├── edgehancer/ (optional) -│ ├── preRequest.ts -│ ├── request.ts -│ └── *.test.ts -├── mesh-manifest.json -├── package.json -└── tsconfig.json -``` - -This documentation provides the complete foundation for building Uniform Mesh integrations. Always refer to the latest Uniform documentation and SDK for any updates to the API or best practices. - -## Implementation guidance - -1. IMPORTANT: do not add anything extra to the implementation of locations that the user didn't ask for. Only add essential code that supports requested functionality. \ No newline at end of file diff --git a/rules/uniform-next-app-router.mdc b/rules/uniform-next-app-router.mdc deleted file mode 100644 index 5ee5bb2..0000000 --- a/rules/uniform-next-app-router.mdc +++ /dev/null @@ -1,386 +0,0 @@ ---- -description: Rules for Uniform SDK for Next.js App Router -globs: -alwaysApply: true ---- - -# Uniform React Next App Router Developer Reference - -This document details how to use Uniform with React.js with Next App Router. - -@uniform.mdc describes general Uniform principles and practices. -@uniform-sdk.mdc describes framework-agnostic developer principles. - -### Required npm packages - -The following npm packages must be installed to wire Uniform to Next App Router: - -@uniformdev/canvas-next-rsc -@uniformdev/canvas - -### Uniform server config - -A file names `uniform.server.config.js` should exist in the root of the Next.js project with the following content: - -```js -/** @type {import('@uniformdev/canvas-next-rsc/config').UniformServerConfig} */ -module.exports = { - defaultConsent: true, - evaluation: { - personalization: "hybrid", - }, - experimental: { - quirkSerialization: true, - }, -}; -``` - -### Enable Uniform server config - -To make the configuration available in Next.js, modify the next.config.js file in the root of the project and add in `withUniformConfig`: - -```js -const { withUniformConfig } = require("@uniformdev/canvas-next-rsc/config"); - -/** @type {import('next').NextConfig} */ -const nextConfig = { - reactStrictMode: true, -}; - -module.exports = withUniformConfig(nextConfig); -``` - -### Fetching and rendering the composition - -In your dynamic route file (`app/[[...path]]/page.{tsx|jsx}`), it is necessary to fetch the Uniform composition instance for the current route. - -```tsx -import { - UniformComposition, - PageParameters, - retrieveRoute, -} from "@uniformdev/canvas-next-rsc"; -import { resolveComponent } from "@/uniform/resolve"; - -export default async function Page(props: PageParameters) { - const route = await retrieveRoute(props); - return ( - <> - - - ); -} -``` - -### Wrapping page in Uniform Context - -In order for personalization and A/B testing functionality to work client side, we must wrap the entire page in the UniformContext component. This should modify `app/layout.tsx` and wrap `{children}`. - -```tsx -import { UniformContext } from "@uniformdev/canvas-next-rsc"; - -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - - -
- {children} -
- - - ); -} -``` - -### Rendering Uniform Components using React Components - -The `UniformComposition` component needs to know how to map a Uniform Component instance's `type` to a React component that implements the UI for that component. This is done using resolveComponent. To use the component registry, first create a component: - -```tsx -export const HeaderComponent = () => { - return <>Header; -}; -``` - -Then register it in the resolveComponent function: - -```tsx -import { - DefaultNotImplementedComponent, - ResolveComponentFunction, - ResolveComponentResult, -} from "@uniformdev/canvas-next-rsc/component"; -import { HeaderComponent } from "@/components/header"; - -export const resolveComponent: ResolveComponentFunction = ({ component }) => { - let result: ResolveComponentResult = { - component: DefaultNotImplementedComponent, - }; - - if (component.type === "header") { - result = { - component: HeaderComponent, - }; - } - - return result; -}; -``` - -#### Mapping Uniform Components to React Components - -React components that receive Uniform Component data are passed props that correspond to the shape of the component definition they render. The `ComponentProps` type can be used to make the mapping explicit: - -```tsx -import { ComponentProps } from "@uniformdev/canvas-next-rsc/component"; -import { - AssetParamValue, - LinkParamValue, - RichTextParamValue, -} from "@uniformdev/canvas"; - -type HeaderParameters = { - textParameter?: string; - richTextParameter?: RichTextParamValue; - linkParameter?: LinkParamValue; - assetParameter?: AssetParamValue; - // it is critical that all parameter props values are optional, because they can be undefined - even if 'required' on the component definition -}; - -type HeaderProps = ComponentProps; - -export const HeaderComponent = ({ textParameter }: HeaderProps) => { - return ( - <> - {textParameter} - - ); -}; -``` - -#### Accessing parameters - -IMPORTANT: When accessing component parameters, never use this way of accessing parameter values: `component?.parameters?..value`. While it works, there is a better way of destructuring the parameter name on props and accessing it directly as shown in the example below: - -```tsx -import { - ComponentProps, - UniformText, -} from "@uniformdev/canvas-next-rsc/component"; - -import { - LinkParamValue, -} from "@uniformdev/canvas"; - -type ComponentParameters = { - icon?: string; - label?: string; - link?: LinkParamValue; -}; - -export const ComponentName = ({ - link, - icon, - label, - component, - context, -}: ComponentProps) => { - return ( - - {icon} - - ); -}; -``` - -#### Rendering child slots - -If a Uniform Component definition has slots defined, the components in those slots can be rendered using the `UniformSlot` component. - -```tsx -import { - ComponentProps, - UniformSlot, -} from "@uniformdev/canvas-next-rsc/component"; -import { RichTextParamValue } from "@uniformdev/canvas"; - -type HeaderParameters = { - textParameter?: string; - richTextParameter?: RichTextParamValue; - // it is critical that all parameter props values are optional, because they can be undefined - even if 'required' on the component definition -}; -type HeaderSlots = "logo" | "navigation"; - -type HeaderProps = ComponentProps; - -export const HeaderComponent = ({ slots, context, component }: HeaderProps) => { - return ( - <> - - - - ); -}; -``` - -#### Rendering parameter values - -When rendering a `text` type parameter, using the `UniformText` component will enable authors to edit the value within the Uniform preview directly. Text parameters that do not have a visible component, such as alt text, should be rendered as their raw text value: - -```tsx -import { - ComponentProps, - UniformText, -} from "@uniformdev/canvas-next-rsc/component"; -import { RichTextParamValue } from "@uniformdev/canvas"; - -type HeaderParameters = { - textParameter?: string; - richTextParameter?: RichTextParamValue; - // it is critical that all parameter props values are optional, because they can be undefined - even if 'required' on the component definition -}; - -type HeaderProps = ComponentProps; - -export const HeaderComponent = ({ component, context }: HeaderProps) => { - return ( - <> - - - ); -}; -``` - -For rich text parameters, the `UniformRichText` component will automatically render the rich text stored as JSON to HTML: - -```tsx -import { - ComponentProps, - UniformRichText, -} from "@uniformdev/canvas-next-rsc/component"; -import { RichTextParamValue } from "@uniformdev/canvas"; - -type HeaderParameters = { - textParameter?: string; - richTextParameter?: RichTextParamValue; - // it is critical that all parameter props values are optional, because they can be undefined - even if 'required' on the component definition -}; - -type HeaderProps = ComponentProps; - -export const HeaderComponent = ({ component, context }: HeaderProps) => { - return ( - <> - - - ); -}; -``` - -Note: asset parameters are rendered directly from props, there is no `UniformAsset` component. - -##### Asset parameters/fields - -1. CRITICAL: Always use `flattenValues` from `@uniformdev/canvas` for handling asset parameters, not custom utility functions. -2. CRITICAL: Destructure asset parameters directly from component props (e.g., `{ logos, component, context }`) rather than accessing through `component?.parameters?.parameterName`. -3. Use `flattenValues(assetParam)` directly - it handles both single and multiple assets automatically. - -```tsx -import { AssetParamValue, flattenValues } from "@uniformdev/canvas"; - -interface MyComponentProps { - multipleImagesAssetParam: AssetParamValue; - singleImageAssetParam: AssetParamValue; -} - -function MyComponent({ - multipleImagesAssetParam, - singleImageAssetParam, -}: MyComponentProps) { - // when multiple assets are allowed, flatten to an array - const images = flattenValues(multipleImagesAssetParam); - // when only one asset is allowed, flatten to a single object - const image = flattenValues(singleImageAssetParam, { toSingle: true }); - - return ( - <> - {images?.map((img, index) => ( - - ))} - - - ); -} -``` - -4. Do NOT create custom utility functions like `getAssetValues` when `flattenValues` already exists and works perfectly. - -### Configuring Contextual Editing Live Preview - -To enable contextual editing and live preview to operate within the Uniform application, we need to register a _preview handler_ and _playground page_. The preview handler is an API endpoint that Uniform invokes when preview starts. It is responsible for mapping the composition ID under preview to a redirect to the correct frontend route to display that composition. The default handler does this using project map hierarchy. - -`app/api/preview/route.ts`: - -```tsx -import { - createPreviewGETRouteHandler, - createPreviewPOSTRouteHandler, - createPreviewOPTIONSRouteHandler, -} from "@uniformdev/canvas-next-rsc/handler"; - -export const GET = createPreviewGETRouteHandler({ - playgroundPath: "/playground", - resolveFullPath: ({ path }) => (path ? path : "/playground"), -}); -export const POST = createPreviewPOSTRouteHandler(); -export const OPTIONS = createPreviewOPTIONSRouteHandler(); -``` - -The preview playground is a special route used to preview Uniform Patterns (reusable chunks of a page). It should use the same resolveComponent function. The playground route includes the global page shell of the application: - -`app/playground/page.tsx`: - -```tsx -import { - UniformPlayground, - UniformPlaygroundProps, -} from "@uniformdev/canvas-next-rsc"; -import { resolveComponent } from "@/uniform/resolve"; - -export default function PlaygroundPage(props: { - searchParams: UniformPlaygroundProps["searchParams"]; -}) { - return ; -} -``` - -## Uniform manifest usage - -1. CRITICAL! If using Next.js App Router, you must ignore adding the following commands specific to Uniform manifest. This is for Next.js page router only. -```bash - "uniform:manifest": "uniform context manifest download --output ./lib/uniform/contextManifest.json", - "uniform:publish": "uniform context manifest publish" -``` diff --git a/rules/uniform-next-page-router.mdc b/rules/uniform-next-page-router.mdc deleted file mode 100644 index 63fe9a1..0000000 --- a/rules/uniform-next-page-router.mdc +++ /dev/null @@ -1,320 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- - -[uniform.mdc](mdc:.cursor/rules/uniform.mdc) describes general Uniform principles and practices. -[uniform-sdk.mdc](mdc:.cursor/rules/uniform-sdk.mdc) describes framework-agnostic developer principles. - -### Required npm packages - -The following npm packages must be installed to wire Uniform CMS to Next Page Router: - -@uniformdev/canvas -@uniformdev/canvas-react -@uniformdev/canvas-next -@uniformdev/context-react - -### Fetching and rendering the composition - -In your dynamic catch-all route file (`pages/[[...path]].{tsx|jsx}`), it is necessary to fetch the Uniform composition instance for the current route. This is done for server-side rendering using the `withUniformGetServerSideProps` function: - -```tsx -import type { UniformCompositionNextPage } from "@uniformdev/canvas-next"; -import { withUniformGetServerSideProps } from "@uniformdev/canvas-next/route"; -import { UniformComposition } from "@uniformdev/canvas-react"; - -// fetch the composition using SSR -export const getServerSideProps = withUniformGetServerSideProps(); - -// the function provides the composition to the route component as the `data` prop -// the UniformCompositionNextPage type provides typings to make sure that is clear -const page: UniformCompositionNextPage = ({ data }) => { - // the UniformComposition component takes over rendering the components on the composition data - return ; -}; - -export { page as default }; -``` - -### Rendering Uniform Components using React Components - -> IMPORTANT: before generating Uniform component code, always fetch available component definitions from Uniform to be aware of the schema. - -The `UniformComposition` component needs to know how to map a Uniform Component instance's `type` to a React component that implements the UI for that component. This is done using the Component Registry. To use the component registry, create a component and register it: - -`components/Hero.tsx`: - -```tsx -import { registerUniformComponent } from "@uniformdev/canvas-react"; - -function Hero() { - return
Hero Component Content
; -} - -registerUniformComponent({ - type: "hero", - component: Hero, -}); -``` -Conventionally Uniform components (like Hero.tsx above) are imported to a barrel file in `components/uniformComponents.ts` (e.g. `import 'componentFileName';`), and that barrel file is imported into `_app.tsx` (e.g. `import '../components/uniformComponents';`) to ensure the registrations are processed. - -#### Mapping Uniform Components to React Components - -React components that receive Uniform Component data are passed props that correspond to the shape of the component definition they render. The `ComponentProps` type can be used to make the mapping explicit: - -```tsx -import { - AssetParamValue, - LinkParamValue, - RichTextParamValue, -} from "@uniformdev/canvas"; - -type HeroProps = ComponentProps<{ - textParameter?: string; - richTextParameter?: RichTextParamValue; - linkParameter?: LinkParamValue; - assetParameter?: AssetParamValue; - // it is critical that all parameter props values are optional, because they can be undefined - even if 'required' on the component definition -}>; - -function Hero(props: HeroProps) { - return
{props.textParameter}
; -} -``` - -#### Rendering child slots - -If a Uniform Component definition has slots defined, the components in those slots can be rendered using the `UniformSlot` component. - -```tsx -import { UniformSlot } from "@uniformdev/canvas-react"; - -function Hero() { - return ( -
-
- -
-
- -
-
- ); -} -``` - -#### Rendering parameter/field values - -##### Text parameters/fields - -When rendering a `text` type parameter, always use the `UniformText` component to render the value. This will enable authors to edit the value within the Uniform preview directly. Text parameters that do not have a visible component, such as alt text, should be rendered as their raw text value: - -```tsx -import { UniformText } from "@uniformdev/canvas-react"; - -function Hero() { - return ( -
- {/* always specify placeholder text that an author will see in the visual editor when the value is empty */} - - {/* optionally you can specify a className or wrapping tag, as well as placeholder text that an author will see in the visual editor when the value is empty */} - -
- ); -} -``` - -##### Rich text parameters/fields - -For richText parameters, always use the `UniformRichText` component to automatically render the rich text (stored as Lexical JSON) to HTML: - -```tsx -import { UniformRichText } from "@uniformdev/canvas-react"; - -function Hero() { - return ( -
- -
- ); -} -``` - -##### Asset parameters/fields - -When rendering asset parameters, use the `flattenValues` helper to simplify value access: - -```tsx -import { AssetParamValue, flattenValues } from "@uniformdev/canvas"; - -interface MyComponentProps { - multipleImagesAssetParam: AssetParamValue; - singleImageAssetParam: AssetParamValue; -} - -function MyComponent({ - multipleImagesAssetParam, - singleImageAssetParam, -}: MyComponentProps) { - // when multiple assets are allowed, flatten to an array - const images = flattenValues(multipleImagesAssetParam); - // when only one asset is allowed, flatten to a single object - const image = flattenValues(singleImageAssetParam, { toSingle: true }); - - return ( - <> - {images?.map((img, index) => ( - - ))} - - - ); -} -``` - -### Configuring Contextual Editing Live Preview - -To enable contextual editing and live preview to operate within the Uniform application, we need to register a _preview handler_ and _playground page_. The preview handler is an API endpoint that Uniform invokes when preview starts. It is responsible for mapping the composition ID under preview to a redirect to the correct frontend route to display that composition. The default handler does this using project map hierarchy. - -`pages/api/preview.ts`: - -```tsx -import { createPreviewHandler } from "@uniformdev/canvas-next"; - -const handler = createPreviewHandler({ - // this is set in .env to an arbitrary value - secret: () => process.env.UNIFORM_PREVIEW_SECRET, - // optionally configure the playground route to enable previewing patterns - playgroundPath: "/playground", -}); - -export default handler; -``` - -The preview playground is a special route used to preview Uniform Patterns (reusable chunks of a page). The playground route includes the global page shell of the application: - -`pages/playground.tsx`: - -```tsx -import { UniformPlayground } from "@uniformdev/canvas-react"; - -export default function Playground() { - // wrap UniformPlayground in your page shell/styles to wrap the pattern previews with - return ; -} -``` - -## Configuring Personalization and A/B Testing (Uniform Context) - -### Required Context Packages - -The following npm packages must be installed to enable Uniform Context on Next Page Router: - -@uniformdev/context -@uniformdev/context-next -@uniformdev/context-react -@uniformdev/cli (IMPORTANT: this package must be installed as a devDependency) - -### Pulling the Uniform Context Manifest - -Uniform Context relies on a static _manifest_ that defines user classification criteria and active test names. This manifest is downloaded using an API endpoint to a local file that is built into the application. The following package.json script can be used to invoke the manifest download: - -```json -"uniform:pull:manifest": "uniform context manifest download --output ./src/uniform/contextManifest.json" -``` -The "dev" and "build" npm scripts should run "uniform:pull:manifest" before beginning their regular tasks. - -### Enable Uniform Context SDK - -In order to initialize Uniform Context, we need to configure it and provide the manifest to it: - -`src/uniform/createUniformContext.ts`: - -```tsx -import { - Context, - ManifestV2, - ContextPlugin, - enableDebugConsoleLogDrain, - enableContextDevTools -} from "@uniformdev/context"; -import { NextCookieTransitionDataStore } from "@uniformdev/context-next"; -import { NextPageContext } from "next"; -import manifest from "./contextManifest.json"; - -export function createUniformContext( - serverContext?: NextPageContext -): Context { - const plugins: ContextPlugin[] = [ - // optional, but smart defaults to help with debugging setup - enableContextDevTools(), - enableDebugConsoleLogDrain("debug"), - ]; - - const context = new Context({ - // disables needing visitor consent before storing data (for testing) - defaultConsent: true, - manifest: manifest as ManifestV2, - transitionStore: new NextCookieTransitionDataStore({ - serverContext, - }), - plugins, - }); - - return context; -} -``` - -The context instance must then be provided to the `_app.tsx` so Uniform knows about it when rendering: - -`pages/_app.tsx`: -```tsx -import { UniformContext } from "@uniformdev/context-react"; -import { UniformAppProps } from "@uniformdev/context-next"; -import { createUniformContext } from "../uniform/createUniformContext"; - -const clientContext = createUniformContext(); - -function MyApp({ - Component, - pageProps, - serverUniformContext, -}: UniformAppProps) { - return ( - - - - ); -} - -export default MyApp; -``` - -We must also configure the server-side Uniform Context instance when using server-side rendering: - -`pages/_document.tsx`: -```tsx -import { enableNextSsr } from "@uniformdev/context-next"; -import { createUniformContext } from "../uniform/uniformContext"; - - // required to enable SSR personalization - static async getInitialProps( - ctx: DocumentContext - ): Promise { - const serverTracker = createUniformContext(ctx); - enableNextSsr(ctx, serverTracker); - return await Document.getInitialProps(ctx); - } -``` - -CRITICAL! Ignore this if using Next.js app router. This is for page router only. When adding Uniform SDK only for Next.js page router, always add these npm scripts to package.json. Adapt the path to `contextManifest.json` as needed. Add `uniform:manifest` to the `dev` and `build` scripts so it is running before the dev server starts or before production build runs. - -```bash - "uniform:manifest": "uniform context manifest download --output ./lib/uniform/contextManifest.json", - "uniform:publish": "uniform context manifest publish" -``` diff --git a/rules/uniform-sdk.mdc b/rules/uniform-sdk.mdc deleted file mode 100644 index e2b62b3..0000000 --- a/rules/uniform-sdk.mdc +++ /dev/null @@ -1,107 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- -# Uniform SDK Developer Reference - -This document details general information and practices about how Uniform works for developers writing frontend applications. - -[uniform.mdc](mdc:.cursor/rules/uniform.mdc) describes general Uniform principles and practices. - -## Authenticating to Uniform - -To fetch a composition, you need a Uniform API key configured. API keys are commonly stored as `UNIFORM_API_KEY` in a `.env` file. They follow the format `uf......`. The API key requires "Read Published Compositions" permission. - -## How Uniform transfers layout data to frontend applications - -Uniform provides _composition instances_, a hierarchical JSON structure of components that define screens or pages in an application. A composition is made up of any number of _components_ which have a type that we map to a frontend component. - -### Routing - -Uniform's _Project Map_ feature enables automatic dynamic route delegation to Uniform authors. Frontend applications define a wildcard route that delegates routing to the Uniform _Route API_, which takes a dynamic path and resolves the correct composition instance data to display for that path. - -### Syncing data with the Uniform CLI - -Uniform provides a CLI which can be used to sync the state of a Uniform project, such as component definitions, pattern definitions, or compositions, to files on disk. These files may be committed to source control and used to ensure the states of environment or developer-specific projects are kept up to date to reduce the chance of errors. - -#### Required package for Uniform CLI - -The Uniform CLI is contained in the `@uniformdev/cli` npm package. IMPORTANT: this package must be installed as a devDependency. - -#### Authenticating with the Uniform CLI - -The Uniform CLI requires a Uniform API key to authenticate. The API key and other connectivity details are stored in a `.env` file. When creating an API key for the CLI, the user can use the "Copy as .env" function in the Uniform dashboard to get the appropriate environment variable values. -API keys used for the Uniform CLI require read and write permissions to any entity types that are to be synced. The default 'developer' role is a shortcut to full permissions. - -#### Configuring the Uniform CLI - -Uniform CLI is configured using the `uniform.config.{ts,js}` file in the root of a project. The file can be configured in two ways: to sync everything (choose this for initial setup), or to pick specific entity types to sync. Sync operates as a mirror by default, meaning creates, updates, and deletes are all synced. - -`uniform.config.ts` (sync all): - -```ts -import { uniformConfig } from "@uniformdev/cli/config"; - -export default uniformConfig({ preset: "all" }); -``` - -`uniform.config.ts` (sync explicit types and customization options): - -```ts -import { uniformConfig } from "@uniformdev/cli/config"; - -export default uniformConfig({ - // 'none' starts with no entities, and each entity type to sync is added explicitly - preset: "none", - config: { - serialization: { - // optionally override the default `./uniform-data` to store serialized files - directory: "./custom-path-to-serialized-files", - // optionally change the default yaml format to json - format: "json", - entitiesConfig: { - // specify entity types to sync. Each type can optionally override - // the defaults just for itself, i.e. directory, format - component: {}, - componentPattern: { publish: true }, - }, - }, - }, -}); -``` - -#### Invoking the Uniform CLI - -The Uniform CLI operates using two primary commands: - -`uniform sync push` - takes the serialized state of entities (files on disk) and pushes that state into a Uniform project online. - -`uniform sync pull` - takes the online state of a Uniform project and pulls it into serialized files. - -Conventionally these commands are registered as package scripts to make it unnecessary to install the CLI package globally: - -`package.json`: - -```json -{ - "scripts": { - "uniform:pull": "uniform sync pull", - "uniform:push": "uniform sync push" - } -} -``` - -## Rules for when to use Uniform CLI and when not - -CRITICAL, NEVER IGNORE THIS RULE: never use or manipulate in any way (create, read, update, or delete) yaml or json files that represent Uniform data (placed typically in the "uniform-data" folder) when trying to create, modify, delete components, content types, or any other Uniform entity. Instead, always use Uniform MCP tool that is registered. If you cannot resolve a Uniform MCP Server or any MCP action, return a graceful message to the user and abort. - -IMPORTANT: execute "npm run uniform:pull" after making any changes to Uniform data via MCP Server. This ensures you have the latest representation of the Uniform data on disk. - -#### Getting Uniform CLI help - -The Uniform CLI has a built-in help system. To get help on a command, run `uniform --help`, for example `uniform sync pull --help`. - -## Must-have rules to follow when adding Uniform SDK - -1. Make sure to create a component in code for any composition component you find in the Uniform project automatically. Add any slots that you find in the definition. This will ensure the preview works as expected; otherwise, it won't know which front-end component should render the composition from Uniform and produce an error. diff --git a/rules/uniform-sveltekit.mdc b/rules/uniform-sveltekit.mdc deleted file mode 100644 index a087244..0000000 --- a/rules/uniform-sveltekit.mdc +++ /dev/null @@ -1,592 +0,0 @@ ---- -description: Uniform SDK integration guide for SvelteKit applications. Use when integrating Uniform Canvas, Context, and personalization into a SvelteKit project. -globs: -alwaysApply: true ---- - -[uniform.mdc](mdc:.cursor/rules/uniform.mdc) describes general Uniform principles and practices. -[uniform-sdk.mdc](mdc:.cursor/rules/uniform-sdk.mdc) describes framework-agnostic developer principles. - -## Required npm packages - -The following npm packages must be installed to wire Uniform CMS to SvelteKit: - -### Core Canvas packages -- `@uniformdev/canvas` - Core Canvas API client for fetching compositions -- `@uniformdev/canvas-svelte` - Svelte components: `UniformComposition`, `UniformSlot`, `UniformText`, `UniformRichText` -- `@uniformdev/canvas-sveltekit` - SvelteKit integrations: `createUniformLoad`, `createUniformHandle`, preview handler, ISR config - -### Core Context packages (for personalization) -- `@uniformdev/context` - Personalization Context engine -- `@uniformdev/context-svelte` - `UniformContext` provider component - -### Edge personalization packages (optional, for production) -- `@uniformdev/context-edge` - Edge-side context processing -- `@uniformdev/context-edge-sveltekit` - NESI response handler for edge personalization -- `@vercel/functions` - Vercel edge functions support -- `cookie` - Cookie parsing utility - -### Dev dependencies -- `@uniformdev/cli` - CLI for pulling manifests and syncing content (IMPORTANT: must be installed as devDependency) - -## Configuring TypeScript Types - -Update `src/app.d.ts` to include Uniform preview data types: - -```typescript -import type { UniformPreviewData } from '@uniformdev/canvas-sveltekit'; - -declare global { - namespace App { - interface Locals { - uniformPreview?: UniformPreviewData; - } - } -} - -export {}; -``` - -## Component Mapping - -Create `src/lib/uniform/componentMap.ts` to map Uniform component types to Svelte components: - -```typescript -import type { ComponentMap } from '@uniformdev/canvas-svelte'; -import Hero from '$lib/components/Hero.svelte'; -import Page from '$lib/components/Page.svelte'; - -/** - * Maps Uniform component types to Svelte components. - * The key is the component type from Uniform Canvas. - * Use `type__variant` format to map specific variants. - */ -export const componentMap: ComponentMap = { - page: Page, - hero: Hero, - // Variant example: card__featured uses same component with variant styling - // card__featured: Card, -}; -``` - -## Server Hooks Configuration - -Create `src/hooks.server.ts` to handle Uniform preview cookies: - -```typescript -import { sequence } from '@sveltejs/kit/hooks'; -import { createUniformHandle } from '@uniformdev/canvas-sveltekit'; - -const uniformHandle = createUniformHandle({ - onPreview: (event, previewData) => { - if (previewData.isUniformContextualEditing) { - console.log('[Uniform] Contextual editing mode active for:', previewData.compositionPath); - } - }, -}); - -export const handle = sequence(uniformHandle); -``` - -## Root Layout with Context Provider - -Update `src/routes/+layout.svelte` to initialize Uniform Context: - -```svelte - - - - {@render children()} - -``` - -**Important:** The `outputType` prop controls personalization rendering: -- `standard`: Used in development - personalization happens client-side -- `edge`: Used in production - outputs NESI placeholders that the edge middleware replaces - -## Catch-All Route for Compositions - -### Server Load Function - -Create `src/routes/[...path]/+page.server.ts` to fetch compositions: - -```typescript -import { error } from '@sveltejs/kit'; -import { RouteClient } from '@uniformdev/canvas'; -import { env } from '$env/dynamic/private'; -import type { PageServerLoad } from './$types'; - -// Optional: ISR on Vercel -import { createVercelIsrConfig } from '@uniformdev/canvas-sveltekit'; -export const config = createVercelIsrConfig({ expiration: 60 }); - -function hasUniformCredentials(): boolean { - return Boolean(env.UNIFORM_API_KEY && env.UNIFORM_PROJECT_ID); -} - -export const load: PageServerLoad = async (event) => { - if (!hasUniformCredentials()) { - error(500, 'Uniform credentials not configured. Set UNIFORM_API_KEY and UNIFORM_PROJECT_ID in your .env file.'); - } - - // Lazy import to avoid initialization errors when credentials are missing - const { createUniformLoad } = await import('@uniformdev/canvas-sveltekit/route'); - - const client = new RouteClient({ - apiKey: env.UNIFORM_API_KEY, - projectId: env.UNIFORM_PROJECT_ID, - }); - - const uniformLoad = createUniformLoad({ - client, - projectMapId: env.UNIFORM_PROJECT_MAP_ID, - param: 'path', // Matches [...path] - }); - - return uniformLoad(event); -}; -``` - -### Page Component - -Create `src/routes/[...path]/+page.svelte` to render compositions: - -```svelte - - - - - -``` - -### Error Page - -Create `src/routes/[...path]/+error.svelte`: - -```svelte - - -
-

{$page.status}

-

{$page.error?.message || 'Page not found'}

- ← Back to home -
-``` - -## Preview Handler - -Create `src/routes/preview/+server.ts` for Canvas contextual editing: - -```typescript -import { createPreviewHandler } from '@uniformdev/canvas-sveltekit/preview'; -import { env } from '$env/dynamic/private'; - -const handlers = createPreviewHandler({ - secret: () => env.UNIFORM_PREVIEW_SECRET ?? '', - playgroundPath: '/playground', - resolveFullPath: ({ path, slug }) => { - return path || slug || '/'; - }, -}); - -export const GET = handlers.GET; -export const POST = handlers.POST; -export const OPTIONS = handlers.OPTIONS; -``` - -## Playground Page - -Create `src/routes/playground/+page.svelte` for component/pattern previews: - -```svelte - - -
- - - -
- - -``` - -## Rendering Uniform Components with Svelte - -> IMPORTANT: before generating Uniform component code, always fetch available component definitions from Uniform to be aware of the schema. - -### Component Props Typing - -Use `ComponentProps` for type-safe parameter access. All parameter props must be optional since they can be undefined: - -```svelte - -``` - -### Text Parameters - -Always use `UniformText` for editable text parameters. This enables inline editing in Canvas: - -```svelte - - - - - - - -``` - -Text parameters without visible components (e.g., alt text) should use raw values. - -### Rich Text Parameters - -Always use `UniformRichText` for rich text parameters (stored as Lexical JSON): - -```svelte - - - -``` - -### Slots - -Use `UniformSlot` to render nested child components from composition slots: - -```svelte - - -
- -
- - -``` - -### Asset Parameters - -Use `flattenValues` helper to simplify asset value access: - -```svelte - - -{#if img} - -{/if} - -{#if images} - {#each images as item} - - {/each} -{/if} -``` - -### Complete Component Example - -```svelte - - -
- -
- -
- {#if showCta} - - {/if} -
-``` - -## Edge Personalization (Production) - -For production edge personalization with NESI (Nested Edge-Side Includes), create `middleware.ts` in the project root: - -```typescript -import { - Context, - CookieTransitionDataStore, - UNIFORM_DEFAULT_COOKIE_NAME, -} from '@uniformdev/context'; -import { createUniformNesiResponseHandler } from '@uniformdev/context-edge-sveltekit'; -import { next } from '@vercel/functions'; -import { parse } from 'cookie'; -import type { ManifestV2 } from '@uniformdev/context'; -import manifestJson from './src/lib/uniform/contextManifest.json'; - -const manifest = manifestJson as ManifestV2; - -export default async function middleware(request: Request) { - // Skip subrequests from this middleware - if (request.headers.get('x-from-middleware') === 'true') { - return next(request); - } - - const url = new URL(request.url); - const cookieValue = request.headers.get('cookie'); - const cookies = parse(cookieValue ?? ''); - - const context = new Context({ - manifest: manifest as ManifestV2, - defaultConsent: true, - transitionStore: new CookieTransitionDataStore({ - serverCookieValue: cookies[UNIFORM_DEFAULT_COOKIE_NAME] ?? undefined, - }), - }); - - await context.update({ cookies, url }); - - const response = await fetch(url, { - headers: { 'x-from-middleware': 'true' }, - }); - - const handler = createUniformNesiResponseHandler(); - return handler({ response, context }); -} - -export const config = { - matcher: [ - '/((?!_app|__data\\.json|@vite|@id|@fs|_next|.*\\..*|favicon\\.ico).*)', - ], -}; -``` - -**Note:** The `@uniformdev/context-edge-sveltekit` package requires an NPM token. Create `.npmrc`: - -``` -//registry.npmjs.org/:_authToken=${NPM_TOKEN} -``` - -## CLI Configuration and Scripts - -### uniform.config.ts - -```typescript -import { uniformConfig } from '@uniformdev/cli/config'; - -export default uniformConfig({ preset: 'all', disableEntities: ['webhook'] }); -``` - -### Package.json scripts - -Add these npm scripts: - -```json -{ - "scripts": { - "dev": "pnpm pull:manifest && vite dev", - "build": "pnpm pull:manifest && vite build", - "pull:manifest": "uniform context manifest download --output ./src/lib/uniform/contextManifest.json", - "pull:content": "uniform sync pull", - "push:content": "uniform sync push" - } -} -``` - -### Placeholder manifest - -Create `src/lib/uniform/contextManifest.json`: - -```json -{ - "project": {} -} -``` - -Add to `src/lib/uniform/.gitignore`: - -``` -contextManifest.json -``` - -## Environment Variables - -Required `.env` configuration: - -```bash -UNIFORM_API_KEY= # From Uniform dashboard -UNIFORM_PROJECT_ID= # Your Uniform project ID -UNIFORM_PROJECT_MAP_ID= # Optional - uses default if not set -UNIFORM_PREVIEW_SECRET=hello-world # Secret for preview validation -``` - -## Vercel Adapter Configuration - -For Vercel deployments, update `svelte.config.js`: - -```javascript -import adapter from '@sveltejs/adapter-vercel'; - -/** @type {import('@sveltejs/kit').Config} */ -const config = { - kit: { - adapter: adapter(), - }, -}; - -export default config; -``` - -## Project Structure Reference - -``` -your-project/ -├── src/ -│ ├── app.d.ts # TypeScript declarations -│ ├── app.html # HTML template -│ ├── hooks.server.ts # Server hooks -│ ├── lib/ -│ │ ├── components/ # Svelte components -│ │ │ ├── Hero.svelte -│ │ │ ├── Page.svelte -│ │ │ └── index.ts -│ │ └── uniform/ -│ │ ├── componentMap.ts # Component type mapping -│ │ ├── contextManifest.json # Generated by CLI -│ │ └── .gitignore -│ └── routes/ -│ ├── +layout.svelte # Root layout with UniformContext -│ ├── [...path]/ -│ │ ├── +page.server.ts # Fetches compositions -│ │ ├── +page.svelte # Renders compositions -│ │ └── +error.svelte -│ ├── playground/ -│ │ └── +page.svelte -│ └── preview/ -│ └── +server.ts -├── middleware.ts # Edge middleware (optional) -├── uniform.config.ts # CLI configuration -├── package.json -├── svelte.config.js -├── vite.config.ts -└── .env -``` - -## Key Differences from Next.js - -| Aspect | Next.js Page Router | SvelteKit | -|--------|---------------------|-----------| -| Component registration | `registerUniformComponent()` | `componentMap` object | -| SSR data loading | `withUniformGetServerSideProps()` | `createUniformLoad()` in `+page.server.ts` | -| Preview handler | `pages/api/preview.ts` | `src/routes/preview/+server.ts` | -| Server hooks | `_app.tsx` / `_document.tsx` | `hooks.server.ts` | -| Context provider | HOC in `_app.tsx` | `UniformContext` in `+layout.svelte` | -| Props pattern | `ComponentProps` generic | `ComponentProps` with `$props()` | -| Reactivity | React hooks | Svelte runes (`$derived`, `$props`) | - -## Troubleshooting - -### Common Issues - -1. **"Cannot find module contextManifest.json"** - - Run `pnpm pull:manifest` to download the manifest - - Ensure valid `UNIFORM_API_KEY` and `UNIFORM_PROJECT_ID` are set - -2. **Preview not working** - - Verify preview URL is configured in Uniform Canvas settings - - Check `UNIFORM_PREVIEW_SECRET` matches in both places - - Consult [troubleshooting guide](https://docs.uniform.app/docs/guides/composition/visual-editing/troubleshoot-preview) - -3. **Components not rendering** - - Verify component type names in `componentMap` match Uniform Canvas - - Check browser console for mapping errors - -4. **TypeScript errors with slots** - - Ensure `UniformSlot` name matches the slot name in Uniform Canvas - -5. **Edge personalization not working** - - Confirm `outputType="edge"` is set in production layout - - Verify middleware is correctly deployed and matching paths diff --git a/rules/uniform.mdc b/rules/uniform.mdc deleted file mode 100644 index 0ae81f7..0000000 --- a/rules/uniform.mdc +++ /dev/null @@ -1,242 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- - -## Uniform Core Concepts - -Uniform is a modern, headless, component-based Content Management System (CMS). Its primary purpose is to allow non-technical authors (marketers, etc) to create and maintain websites and other similar experiences in a visual editor. - -### Uniform Compositions - -A composition instance in Uniform is roughly equivalent to a page. Composition definitions define a reusable schema for composition instances. -Composition definitions have a structure identical to a Uniform Component, i.e. parameters and slots. -Composition instances differ from components in that they also define a route or page. -Instances of a composition create pages or routes within an application. -The term "Composition" can be used to refer either to a definition or instance of a composition, you will need to infer which is meant (schema/reusable template = definition, page/route = instance). - -Composition parameters should only be used for global content that will never need to be personalized. -Good example: OpenGraph data and meta tags (if they exist) -Bad example: "hero title" belongs in a Hero component in the content slot. - -A single composition definition called 'Page' is generally a good starting point. Additional composition definitions are only required if the page shell is different (e.g. Page, Popup, Minimal Page), or if there are different parameters needed on the composition definition - -In developer terms, a composition instance is a dynamic layout that is defined by non-technical authors; a composition definition is a hierarchical content schema definition. - -### Uniform Entries - -Entries are instances of structured content that you create using predefined Uniform Content Types. Think of content types as blueprints and entries as the actual content built from those blueprints. - -Each entry contains structured data for content pieces like articles, events, products, or any other content you need. Once created, entries become reusable assets that can power multiple experiences across your digital channels. - -#### How entries differ from compositions and components - -An entry is structured content that represents a piece of content in a design-agnostic way. A component or composition describes the experience layer by defining which concrete UI component should be used to show particular content. Entries can also define relationships to other entries via references, which allows building complex content structures. - -By connecting the fields of an entry to the parameters of a component, you define how the content is displayed in a certain context. For example, you could show the same article entry in a hero, a card, or a list component. Which fields of an entry are shown can be different for each use case. - -### Uniform Components - -Uniform Components are used to allow CMS authors to create and manipulate visual elements on a composition. Each property of a Uniform Component, such as a title or image, is called a _Component Parameter_. See _Uniform Parameter/Field Types_ for the exact types of parameter that are allowed. Components have both a definition (their schema) and instances (when an instance of that schema is placed within a slot on a composition). - -Uniform Components can define named _slots_. - -- A slot allows additional components (or component patterns) to be inserted within the Uniform Component. For example an accordion component could have an 'items' slot that allows adding Accordion Item components. -- Each named slot has 0..n child components. The order in the slot determines the order of rendering. -- Each slot definition allows only specific Uniform Components to be placed within it (by public id). It can also define the minimum and maximum number of components allowed. -- Components allowed within slots can also have their own slots, with no depth limit - but it is generally undesirable to nest more than 2-3 levels deep to improve author understanding. -- When a Uniform Composition is defined, it almost always has a generic 'content' slot added to it that allows using various components to define the layout. - -Uniform Component Definition attributes: - -- _name_ -- _public ID_ -- _parameters_ -- _slots_ - -Uniform Slot Definition attributes: - -- _name_ -- _public ID_ -- _allowed components_ -- _min components_ -- _max components_ - -In technical terms, a Uniform Component maps directly to a presentational frontend component such as a React component. The parameters are component props. Slots are component props that contain rendered child components. - -#### Determining which Uniform Components or Component Patterns are allowed in a Slot - -In Uniform, slot definitions control which components or component patterns can be placed in a slot. This is governed by a combination of properties that make slot configuration both powerful and flexible. - -Here's how it works: - -1. `allowAllComponents: true`: If this is set, any component or component pattern can be added to the slot - no restrictions. -2. `allowAllComponents: false`: If this is provided, `allowedComponents` is a list of allowed Uniform component public IDs. You can also include component patterns by using the prefix `$p:` followed by the pattern UUID. -Example: -`["hero", "callToAction", "$p:00000000-0000-0000-0000-000000000000"]` -3. `patternsInAllowedComponents` This controls how component patterns are validated against `allowedComponents`. - * If `true`: A pattern is only allowed if it is explicitly listed in allowedComponents (with the `$p:` prefix). - Example: - `["hero", "$p:00000000-0000-0000-0000-000000000000"]` - Only the listed pattern and `hero` components are allowed - no other patterns based on `hero` are valid. - * If `false`: a pattern is allowed if its base component type is listed in `allowedComponents`. - Example: - `["hero"]` - Only `hero` components and any pattern based on `hero` are allowed. -4. If you are editing a component pattern or composition pattern, the slot section component ($slotSection) is always allowed. - -IMPORTANT: Before you add new components to a slot, make sure that they are allowed according to the preceding rules. -IMPORTANT: If you change `patternsInAllowedComponents` to false, remove any existing pattern IDs in the allowed list. - -#### Slot sections -When editing component patterns and composition patterns definitions only, there is an additional built-in component available to insert in any slot called a _slot section_ ($slotSection). -Slot sections create an extension point where consumers of the pattern definition can insert new components - normally, slots on a pattern cannot be modified by pattern consumers. -Slot sections may not have 'default components' when defined on a pattern definition. -When fetched for content delivery, the slot section component dissolves and its children become part of the parent slot. -IMPORTANT: If the current context item is not a component pattern or a composition pattern, do not include Slot Sections in a list of system components. Slot sections are only valid insertions on component patterns and composition patterns. - -When editing a pattern instance (when one of its ancestors has the _pattern property set) and a slot section is found, you may insert components into the slot section to extend the pattern's slot contents. -All $slotSection components support only one slot, $slotSectionItems. -Adding components to a slot section works by inserting them into the slot section's slot. You may not use the parent slot name of the slot section, the slot name must be $slotSectionItems. - -When dealing with nested patterns, slot sections' contents may only be set on the direct parent consumer of the pattern (this differs from property overrides, which can be set on any ancestor of the pattern). To expose a slot section from a nested pattern, you must 're-export' the slot section by adding a slot section to the parent pattern in the child's slot section. - -### Uniform Content Types - -Uniform Content Types define a reusable structure for individual reusable pieces of content. A Uniform content type differs from a Uniform component because a component represents a specific visual element on a composition/page, but a content type is an abstract, reusable content schema. An instance of a Uniform Content Type is called an _Entry_. Entries each have their own built-in slug: there is no need to define an explicit slug field. - -For example a Product might be a Uniform Content Type, and the data from instances of that Product could be presented in different contexts by Uniform Patterns such as Product List, Product Detail, or Product Card. - -Uniform Content Types define content properties called _Fields_ (e.g. a blog post could have a single-line text input for title, and a rich text editor for body). See _Uniform Parameter/Field Types_ for the exact types of field that are allowed. - -Uniform Content Type attributes: - -- _name_ -- _public ID_ -- _fields_ - -### Uniform Patterns - -Patterns are a unit of content reuse within Uniform. Updates made to patterns are immediately reflected to all usages of the pattern. There are several types of patterns: - -#### Uniform Component Patterns - -Component Patterns allow reusing the same content across compositions. The simplest way to think of a pattern is that it is a _shared component instance_ that can be placed within a slot to insert the pattern's content there. The pattern, like any other component instance, can have values in its parameters and child components in its slots. All usages of the same pattern reference the same shared content. Component Patterns may be nested within each other (e.g. a Blog Post Hero pattern could include a Author Bio pattern in one of its slots). Nesting beyond 2-3 levels can cause performance issues. - -#### Uniform Composition Patterns - -Composition Patterns allow creating compositions from a shared template. Non-overridable data in the composition pattern is locked down to reference the pattern. Composition patterns are created to lock down compositions and allow changing only a subset of data, or to rapidly make pages from external data sources. - -#### Entry Patterns - -Entry Patterns allow creating Entries from a shared template. Non-overridable data in the entry pattern is locked down to reference the pattern. Entry patterns are created to lock down entries and allow changing only a subset of data, or to rapidly make entries from external data sources. - -#### Uniform Pattern Overrides - -Parameters or fields on patterns can be defined _overridable_ by the pattern definition. Overridable parameter values default to using the value defined on the pattern, but consumers of the pattern may choose to break the inheritance of that parameter value and replace it with their own instance-specific value. Patterns that contain other patterns may not alter the overridability of nested pattern parameters: once overridable, any consumer of the pattern can change the value. Overrides are used to allow partial content sharing and exception cases. - -#### Using Uniform Patterns as Shared Content Snippets - -Patterns can be used to reuse shared content, for example the same legal disclaimer might be required on every press release. Both patterns and components allow content reuse: the difference is that patterns reuse exact content, whereas components reuse content schemas but do not provide content values. - -#### Using Uniform Patterns as Data Binding Templates - -Patterns can be used to create bindings between structured data (from Uniform Entries or external data sources, like REST APIs or other CMSes) and presentation parameters. A pattern can define a _Data Resource_ which is the result of fetching from a data source. Then parameters in the pattern can use _Dynamic Tokens_ to bind to elements within the data resource. For example, we might have a Card component that has a title and image. Then we create a Product Card pattern, based on the Card component, which has a Uniform Entry Data Resource that fetches an entry specified by the pattern consumer. The Product Card automatically binds the title and image from the product entry to the Card component's parameters. As an author, one can then insert a Product Card pattern, choose the product to use, and have the title and image automatically set up for them. - -Example of a resolved Data Resource (named 'myEntry'): -{ "myEntry": { "fields": { "title": "hello world" } } } - -Example of a Dynamic Token in a text parameter referencing the myEntry title: -"today's greeting: ${#jptr:/myEntry/fields/title}" (this resolves to "today's greeting: hello world") - -#### Uniform Pattern attributes - -- _name_ -- _type_ - public ID of the base Uniform Component -- _public id_ - id of the pattern -- _data resources_ (name, type) -- _parameters_ (value, overridable) -- _slots_ - -### Uniform assets - -Media files that are used in Uniform compositions and entries are called _Assets_ and are managed in the _Asset Library_. Mesh integrations can extend the Asset Library to allow for custom asset sources like external DAM systems or asset repositories (like Unsplash, Getty Images, etc). - -#### Asset attributes - -- _public id_ - the asset's unique identifier -- _type_ - the asset's type, such as 'image', 'video', 'audio', 'document', 'other' -- _source_ - such as 'uniform-assets' or an identifier specific to a Mesh integration -- _fields_ - the asset's metadata, such as the title, description, file, url, focal point coordinates, dimensions, etc - - -### Localization - -Uniform defines locales at a project level. These are locales that content can be written in. -Individual compositions, entries, and patterns must also _enable_ a locale to indicate that they have content in that locale. This allows for specific content to support a subset of locales. -Locales must be enabled on compositions, entries, or patterns before their parameters or fields can have values in that locale. - -## Conventions - -### Uniform Field/Parameter Types - -Uniform Fields or Uniform Parameters attributes: - -- _name_ -- _public ID_. Must be unique within a Uniform Component or Uniform Content Type (including the ID of group fields/parameters) -- _localizable_. Localizable values have a distinct value for each locale; otherwise the value is the same for all locales. -- _required_. Required means that a CMS author must input a value in order to be considered valid. -- _type_. See list below. -- _guidance_. Brief LLM instructions used when generating or editing values. -- _overridable_. Only applies for fields/parameters on a pattern definition. Allows consumers of the pattern to break inheritance and change the pattern definition's value for the field/parameter. - -Exhaustive list of allowed field/parameter types: - -- _text_: Plain text content -- _richText_: Formatted text with styling (Lexical JSON format) -- _select_: Choose between a controlled vocabulary of options -- _multi-select_: Choose between a controlled vocabulary of options, allowing multiple selections -- _number_: Numeric value -- _date_: Calendar date -- _dateTime_: Date with timezone -- _checkbox_: Boolean toggle -- _link_: URL or internal reference -- _asset_: Image, video, audio, or other file -- _json_: A JSON object. Not for use in author-facing fields/parameters, who will have trouble editing JSON. -- _contentReference_: Allows referencing one or more Entries of a specific type. Can be used in Content Types, but not in Uniform Components. -- _$enr_: Tag content with enrichments (relevant segments) to make viewing the content alter the classification of the visitor that saw it. -- _group_: Group multiple fields/parameters together visually, for example a group of address fields. IMPORTANT: fields added to a group must come directly after the group in the fields list. - -### Uniform Naming Conventions - -- All names should be title-cased prose, not technical shorthand (e.g. "Main Header" not "main-header" or "MainHeader"). There is no need to include the type of entity in a name (e.g. 'Hero' not 'Hero Component'). -- Do not name Uniform Components, Uniform Content Types, or Fields/Parameters based on visible content found in inputs; treat it as FPO (e.g.

Hello

does not mean name the component 'Hello' - describe its meaning instead, such as 'Headline'). -- _Public ID_ are developer-facing identifiers for Uniform entities. They are based on a slugified version of the name. Use a camel case, for example if the name is "Main Header", the public ID is "mainHeader". Public IDs must be unique within a given entity type (e.g. Uniform Components). You cannot alter public IDs after creating an entity. IMPORTANT: public IDs on parameters, fields, or components that start with `$` are system-owned, and cannot be altered by users. For example, you may not change parameters of the `$personalization` component or remove the `$viz` parameter from any component. You may add or remove system components such as `$test` to a slot's `allowedComponents`. -- Help text should be no longer than 1 short sentence. It is not necessary to write help text unless we have specific expectations for authors. For example a 'Title' doesn't need help text. But if we identify an image that needs to be 250x250px, that expectation belongs in help text. Descriptions and help text are plain text, no markdown or HTML. - -## Tool Usage Tips - -- Before creating or updating Uniform Patterns, fetch Uniform Component Definitions to ensure you know about valid component types and parameters. -- When making multiple updates to the same Uniform Pattern, such as adding a component and setting a parameter value, batch changes together into a single tool call to improve performance and consistency. -- When a Uniform tool provides you with an edit URL offer it to the user as a link, unless you already have recently. -- Before inserting, removing, or reordering parameters or fields from a Uniform Component or Uniform Content Type, make sure to fetch the latest definition data to ensure you target the correct location. -- If you are tasked with reordering fields or parameters, you must remove them and re-add them in the new order -- Enable the default locale (if one exists) when creating new entries, patterns, or compositions, unless the user specifies locales -- If duplicating or copying entries, compositions, or patterns, always use the duplicate function of the edit tool instead of creating a new entity and re-creating data. - -## Unsupported Features - -The following Uniform features cannot currently be changed using MCP/AI. If asked to perform the following actions, explain you cannot yet do that, and when possible offer a link to perform the task in the Uniform web app. - -- Creating new Loop component instances -- Adding, editing, or removing block type fields/parameters, or block type definitions -- Editing conditional values on parameters or fields (the default value can be edited) -- Setting visibility rules on component instances -- Changing data sources, data types, or data resources -- Adding or removing project map nodes, and linking compositions to project map nodes -- Adding or removing content from Uniform Releases, or changing releases (i.e. locking, scheduling) -- All content you work with is in a 'draft' state. You do not have access to published content and cannot assist with publishing -- Managing workflows, or transitioning compositions, entries, or patterns from one workflow stage to another -- Creating new assets, uploading or editing files for assets, or deleting assets -- Changing user permissions