@ucptools/validator 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +109 -0
- package/CONTRIBUTING.md +113 -0
- package/LICENSE +21 -0
- package/README.md +203 -0
- package/api/analyze-feed.js +140 -0
- package/api/badge.js +185 -0
- package/api/benchmark.js +177 -0
- package/api/directory-stats.ts +29 -0
- package/api/directory.ts +73 -0
- package/api/generate-compliance.js +143 -0
- package/api/generate-schema.js +457 -0
- package/api/generate.js +132 -0
- package/api/security-scan.js +133 -0
- package/api/simulate.js +187 -0
- package/api/tsconfig.json +10 -0
- package/api/validate.js +1351 -0
- package/apify-actor/.actor/actor.json +68 -0
- package/apify-actor/.actor/input_schema.json +32 -0
- package/apify-actor/APIFY-STORE-LISTING.md +412 -0
- package/apify-actor/Dockerfile +8 -0
- package/apify-actor/README.md +166 -0
- package/apify-actor/main.ts +111 -0
- package/apify-actor/package.json +17 -0
- package/apify-actor/src/main.js +199 -0
- package/docs/BRAND-IDENTITY.md +238 -0
- package/docs/BRAND-STYLE-GUIDE.md +356 -0
- package/drizzle/0000_black_king_cobra.sql +39 -0
- package/drizzle/meta/0000_snapshot.json +309 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +10 -0
- package/examples/full-profile.json +70 -0
- package/examples/minimal-profile.json +23 -0
- package/package.json +69 -0
- package/public/.well-known/ucp +25 -0
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/brand.css +321 -0
- package/public/directory.html +701 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/guides/bigcommerce.html +743 -0
- package/public/guides/fastucp.html +838 -0
- package/public/guides/magento.html +779 -0
- package/public/guides/shopify.html +726 -0
- package/public/guides/squarespace.html +749 -0
- package/public/guides/wix.html +747 -0
- package/public/guides/woocommerce.html +733 -0
- package/public/index.html +3835 -0
- package/public/learn.html +396 -0
- package/public/logo.jpeg +0 -0
- package/public/og-image-icon.png +0 -0
- package/public/og-image.png +0 -0
- package/public/robots.txt +6 -0
- package/public/site.webmanifest +31 -0
- package/public/sitemap.xml +69 -0
- package/public/social/linkedin-banner-1128x191.png +0 -0
- package/public/social/temp.PNG +0 -0
- package/public/social/x-header-1500x500.png +0 -0
- package/public/verify.html +410 -0
- package/scripts/generate-favicons.js +44 -0
- package/scripts/generate-ico.js +23 -0
- package/scripts/generate-og-image.js +45 -0
- package/scripts/reset-db.ts +77 -0
- package/scripts/seed-db.ts +71 -0
- package/scripts/setup-benchmark-db.js +70 -0
- package/src/api/server.ts +266 -0
- package/src/cli/index.ts +302 -0
- package/src/compliance/compliance-generator.ts +452 -0
- package/src/compliance/index.ts +28 -0
- package/src/compliance/templates.ts +338 -0
- package/src/compliance/types.ts +170 -0
- package/src/db/index.ts +28 -0
- package/src/db/schema.ts +84 -0
- package/src/feed-analyzer/feed-analyzer.ts +726 -0
- package/src/feed-analyzer/index.ts +34 -0
- package/src/feed-analyzer/types.ts +354 -0
- package/src/generator/index.ts +7 -0
- package/src/generator/key-generator.ts +124 -0
- package/src/generator/profile-builder.ts +402 -0
- package/src/hosting/artifacts-generator.ts +679 -0
- package/src/hosting/index.ts +6 -0
- package/src/index.ts +105 -0
- package/src/security/index.ts +15 -0
- package/src/security/security-scanner.ts +604 -0
- package/src/security/types.ts +55 -0
- package/src/services/directory.ts +434 -0
- package/src/simulator/agent-simulator.ts +941 -0
- package/src/simulator/index.ts +7 -0
- package/src/simulator/types.ts +170 -0
- package/src/types/generator.ts +140 -0
- package/src/types/index.ts +7 -0
- package/src/types/ucp-profile.ts +140 -0
- package/src/types/validation.ts +89 -0
- package/src/validator/index.ts +194 -0
- package/src/validator/network-validator.ts +417 -0
- package/src/validator/rules-validator.ts +297 -0
- package/src/validator/sdk-validator.ts +330 -0
- package/src/validator/structural-validator.ts +476 -0
- package/tests/fixtures/non-compliant-profile.json +25 -0
- package/tests/fixtures/official-sample-profile.json +75 -0
- package/tests/integration/benchmark.test.ts +207 -0
- package/tests/integration/database.test.ts +163 -0
- package/tests/integration/directory-api.test.ts +268 -0
- package/tests/integration/simulate-api.test.ts +230 -0
- package/tests/integration/validate-api.test.ts +269 -0
- package/tests/setup.ts +15 -0
- package/tests/unit/agent-simulator.test.ts +575 -0
- package/tests/unit/compliance-generator.test.ts +374 -0
- package/tests/unit/directory-service.test.ts +272 -0
- package/tests/unit/feed-analyzer.test.ts +517 -0
- package/tests/unit/lint-suggestions.test.ts +423 -0
- package/tests/unit/official-samples.test.ts +211 -0
- package/tests/unit/pdf-report.test.ts +390 -0
- package/tests/unit/sdk-validator.test.ts +531 -0
- package/tests/unit/security-scanner.test.ts +410 -0
- package/tests/unit/validation.test.ts +390 -0
- package/tsconfig.json +20 -0
- package/vercel.json +34 -0
- package/vitest.config.ts +22 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
UCP Profile Manager is a toolkit for validating and generating UCP (Universal Commerce Protocol) Business Profiles - an open standard enabling AI agents to discover, browse, and complete purchases on UCP-enabled merchants. The project includes a core library, REST API, CLI tools, web UI, and Apify actor integration.
|
|
8
|
+
|
|
9
|
+
**Live deployment:** https://ucptools.dev
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Development
|
|
15
|
+
npm run dev # Watch mode Express server (tsx watch src/api/server.ts)
|
|
16
|
+
npm run build # TypeScript compilation
|
|
17
|
+
npm start # Production server (node dist/api/server.js)
|
|
18
|
+
|
|
19
|
+
# Testing
|
|
20
|
+
npm test # Vitest tests (30s timeout, v8 coverage)
|
|
21
|
+
|
|
22
|
+
# Linting
|
|
23
|
+
npm run lint # ESLint on src/**/*.ts
|
|
24
|
+
|
|
25
|
+
# CLI tools
|
|
26
|
+
npm run validate # Run validator CLI (tsx src/cli/index.ts)
|
|
27
|
+
npm run generate # Run generator CLI (tsx src/cli/generate.ts)
|
|
28
|
+
|
|
29
|
+
# Database (Drizzle + PostgreSQL)
|
|
30
|
+
npm run db:generate # Generate Drizzle schema
|
|
31
|
+
npm run db:migrate # Apply migrations
|
|
32
|
+
npm run db:push # Push schema to DB
|
|
33
|
+
npm run db:studio # Open Drizzle Studio
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Architecture
|
|
37
|
+
|
|
38
|
+
### Core Library (`/src/`)
|
|
39
|
+
|
|
40
|
+
**Validator (`/src/validator/`)** - Four validation levels:
|
|
41
|
+
- `structural-validator.ts` - JSON structure, required fields, version format (YYYY-MM-DD)
|
|
42
|
+
- `rules-validator.ts` - UCP compliance (namespace/origin binding, extension chains, HTTPS endpoints, signing keys)
|
|
43
|
+
- `network-validator.ts` - Remote schema fetching/verification, self-describing schema validation
|
|
44
|
+
- `sdk-validator.ts` - Integration with @ucp-js/sdk for official UCP compliance
|
|
45
|
+
- `index.ts` - Orchestrator exposing `validateProfile()`, `validateRemote()`, `validateQuick()`, `validateJsonString()`
|
|
46
|
+
|
|
47
|
+
**Generator (`/src/generator/`)** - Profile generation:
|
|
48
|
+
- `profile-builder.ts` - `buildProfile()` for full profiles, `generateMinimalProfile()` for checkout-only
|
|
49
|
+
- `key-generator.ts` - Ed25519/ES256 signing key generation (`generateSigningKeyPair()`)
|
|
50
|
+
|
|
51
|
+
**Simulator (`/src/simulator/`)** - AI agent interaction simulation:
|
|
52
|
+
- `agent-simulator.ts` - Tests real-world functionality: discovery flow, capability inspection, checkout simulation
|
|
53
|
+
- Not just spec compliance - simulates actual agent workflows
|
|
54
|
+
|
|
55
|
+
**Hosting (`/src/hosting/`)** - Platform-specific deployment configs:
|
|
56
|
+
- `artifacts-generator.ts` - Generates installation artifacts for Nginx, Apache, Vercel, Netlify, Cloudflare Workers, S3+CloudFront
|
|
57
|
+
|
|
58
|
+
### API & Deployment
|
|
59
|
+
|
|
60
|
+
**Express API (`/src/api/server.ts`)** - REST endpoints:
|
|
61
|
+
- `POST /v1/profiles/validate`, `/validate-quick`, `/validate-remote`, `/validate-json`
|
|
62
|
+
- `POST /v1/profiles/generate`, `/generate-minimal`
|
|
63
|
+
- `POST /v1/hosting/artifacts`
|
|
64
|
+
|
|
65
|
+
**Vercel Serverless (`/api/`)** - Edge functions for ucptools.dev
|
|
66
|
+
|
|
67
|
+
**Database (`/src/db/`)** - Drizzle ORM with PostgreSQL (Neon):
|
|
68
|
+
- Schema: merchants (directory), benchmarkStats, benchmarkSummary
|
|
69
|
+
- Service: `/src/services/directory.ts` - merchant CRUD, filtering, stats
|
|
70
|
+
|
|
71
|
+
### Types (`/src/types/`)
|
|
72
|
+
- `ucp-profile.ts` - UCP specification types
|
|
73
|
+
- `validation.ts` - ValidationReport, ValidationIssue interfaces
|
|
74
|
+
- `generator.ts` - Generator input/output types
|
|
75
|
+
|
|
76
|
+
## Key Patterns
|
|
77
|
+
|
|
78
|
+
**Validation Issue Structure:**
|
|
79
|
+
```typescript
|
|
80
|
+
{
|
|
81
|
+
severity: 'error' | 'warn' | 'info',
|
|
82
|
+
code: string, // e.g., 'UCP_NS_ORIGIN_MISMATCH'
|
|
83
|
+
path: string, // JSON path, e.g., '$.ucp.capabilities[0]'
|
|
84
|
+
message: string,
|
|
85
|
+
hint?: string // Fix suggestion
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Error Codes:** `UCP_MISSING_ROOT`, `UCP_MISSING_VERSION`, `UCP_INVALID_VERSION_FORMAT`, `UCP_NS_ORIGIN_MISMATCH`, `UCP_ORPHANED_EXTENSION`, `UCP_ENDPOINT_NOT_HTTPS`, `UCP_ENDPOINT_TRAILING_SLASH`, `UCP_MISSING_SIGNING_KEYS`, `UCP_SCHEMA_FETCH_FAILED`
|
|
90
|
+
|
|
91
|
+
## Environment Variables
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
DATABASE_URL # PostgreSQL connection string (Neon)
|
|
95
|
+
NODE_ENV # development | production
|
|
96
|
+
PORT # API port (default: 3000)
|
|
97
|
+
LOG_LEVEL # Pino log level (default: info)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Tech Stack
|
|
101
|
+
|
|
102
|
+
- **Runtime:** Node.js 20+, TypeScript 5.6, ES2022 target
|
|
103
|
+
- **API:** Express 4.21
|
|
104
|
+
- **Database:** PostgreSQL via @neondatabase/serverless, Drizzle ORM
|
|
105
|
+
- **Validation:** AJV 8.17 (JSON Schema), Zod 3.23, @ucp-js/sdk 0.1
|
|
106
|
+
- **Crypto:** jose (JWT/JWK), Ed25519 signing
|
|
107
|
+
- **CLI:** Commander 12, Chalk 5
|
|
108
|
+
- **Testing:** Vitest
|
|
109
|
+
- **Deployment:** Vercel
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Contributing to @ucptools/validator
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to the UCP Validator! This document provides guidelines and instructions for contributing.
|
|
4
|
+
|
|
5
|
+
## Code of Conduct
|
|
6
|
+
|
|
7
|
+
By participating in this project, you agree to maintain a respectful and inclusive environment for everyone.
|
|
8
|
+
|
|
9
|
+
## How to Contribute
|
|
10
|
+
|
|
11
|
+
### Reporting Bugs
|
|
12
|
+
|
|
13
|
+
1. Check if the bug has already been reported in [Issues](https://github.com/Nolpak14/ucp-tools/issues)
|
|
14
|
+
2. If not, create a new issue with:
|
|
15
|
+
- A clear, descriptive title
|
|
16
|
+
- Steps to reproduce the issue
|
|
17
|
+
- Expected vs actual behavior
|
|
18
|
+
- Your environment (Node.js version, OS)
|
|
19
|
+
- Sample UCP profile if applicable
|
|
20
|
+
|
|
21
|
+
### Suggesting Features
|
|
22
|
+
|
|
23
|
+
1. Check existing issues for similar suggestions
|
|
24
|
+
2. Create a new issue with the `enhancement` label
|
|
25
|
+
3. Describe the feature and its use case
|
|
26
|
+
4. Explain how it benefits UCP profile validation/generation
|
|
27
|
+
|
|
28
|
+
### Pull Requests
|
|
29
|
+
|
|
30
|
+
1. Fork the repository
|
|
31
|
+
2. Create a feature branch: `git checkout -b feature/your-feature-name`
|
|
32
|
+
3. Make your changes
|
|
33
|
+
4. Run tests: `npm test`
|
|
34
|
+
5. Run linting: `npm run lint`
|
|
35
|
+
6. Commit with a clear message describing your changes
|
|
36
|
+
7. Push to your fork and submit a pull request
|
|
37
|
+
|
|
38
|
+
## Development Setup
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Clone your fork
|
|
42
|
+
git clone https://github.com/YOUR_USERNAME/ucp-tools.git
|
|
43
|
+
cd ucp-tools
|
|
44
|
+
|
|
45
|
+
# Install dependencies
|
|
46
|
+
npm install
|
|
47
|
+
|
|
48
|
+
# Run tests
|
|
49
|
+
npm test
|
|
50
|
+
|
|
51
|
+
# Run in development mode
|
|
52
|
+
npm run dev
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Project Structure
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
src/
|
|
59
|
+
types/ # TypeScript type definitions
|
|
60
|
+
validator/ # Validation logic (structural, rules, network, SDK)
|
|
61
|
+
generator/ # Profile and key generation
|
|
62
|
+
simulator/ # AI agent simulation
|
|
63
|
+
hosting/ # Deployment artifact generation
|
|
64
|
+
api/ # Express REST API
|
|
65
|
+
cli/ # Command-line tools
|
|
66
|
+
db/ # Database schema and services
|
|
67
|
+
examples/ # Sample UCP profiles
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Coding Standards
|
|
71
|
+
|
|
72
|
+
- Use TypeScript for all new code
|
|
73
|
+
- Follow existing code style (enforced by ESLint)
|
|
74
|
+
- Add JSDoc comments for public APIs
|
|
75
|
+
- Write tests for new functionality
|
|
76
|
+
- Keep functions focused and single-purpose
|
|
77
|
+
|
|
78
|
+
## Testing
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Run all tests
|
|
82
|
+
npm test
|
|
83
|
+
|
|
84
|
+
# Run tests in watch mode
|
|
85
|
+
npm test -- --watch
|
|
86
|
+
|
|
87
|
+
# Run specific test file
|
|
88
|
+
npm test -- src/validator/structural-validator.test.ts
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Validation Error Codes
|
|
92
|
+
|
|
93
|
+
When adding new validation rules, follow the existing pattern:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
{
|
|
97
|
+
severity: 'error' | 'warn' | 'info',
|
|
98
|
+
code: 'UCP_YOUR_ERROR_CODE', // Prefix with UCP_
|
|
99
|
+
path: '$.ucp.path.to.issue', // JSON path format
|
|
100
|
+
message: 'Clear description of the issue',
|
|
101
|
+
hint: 'Suggestion to fix the issue' // Optional
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Questions?
|
|
106
|
+
|
|
107
|
+
- Open an issue for general questions
|
|
108
|
+
- Check [ucptools.dev](https://ucptools.dev) for documentation
|
|
109
|
+
- Review the [UCP Specification](https://ucp.dev/specification/overview/)
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 UCP.tools
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# @ucptools/validator
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ucptools/validator)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
**Validate and generate UCP (Universal Commerce Protocol) Business Profiles** for AI-powered shopping agents like ChatGPT, Google AI Mode, and Copilot checkout.
|
|
7
|
+
|
|
8
|
+
> **Try it online:** [ucptools.dev](https://ucptools.dev) - Free AI Commerce Readiness Checker
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## What is UCP?
|
|
13
|
+
|
|
14
|
+
The [Universal Commerce Protocol](https://ucp.dev) is an open standard enabling AI agents to discover, browse, and complete purchases on any UCP-enabled merchant. Google announced UCP on January 11, 2026, with support from Shopify, Target, Walmart, and 20+ ecosystem partners.
|
|
15
|
+
|
|
16
|
+
This library helps you:
|
|
17
|
+
- **Validate** your UCP profile for compliance
|
|
18
|
+
- **Generate** properly formatted UCP profiles
|
|
19
|
+
- **Verify** schemas and capability declarations
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @ucptools/validator
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
### Validate a Profile
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { validateProfile, validateQuick, validateRemote } from '@ucptools/validator';
|
|
37
|
+
|
|
38
|
+
// Validate a local profile object
|
|
39
|
+
const report = await validateProfile(myProfile);
|
|
40
|
+
console.log(report.ok ? 'Valid!' : 'Issues found:', report.issues);
|
|
41
|
+
|
|
42
|
+
// Quick validation (no network calls)
|
|
43
|
+
const quickReport = validateQuick(myProfile);
|
|
44
|
+
|
|
45
|
+
// Validate a remote profile by domain
|
|
46
|
+
const remoteReport = await validateRemote('example.com');
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Generate a Profile
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { buildProfile, generateMinimalProfile } from '@ucptools/validator';
|
|
53
|
+
|
|
54
|
+
// Generate a minimal profile (checkout only)
|
|
55
|
+
const minimal = generateMinimalProfile({
|
|
56
|
+
endpoint: 'https://api.yourstore.com/ucp/v1',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Generate a full profile
|
|
60
|
+
const result = await buildProfile({
|
|
61
|
+
merchant: {
|
|
62
|
+
merchantId: 'store-123',
|
|
63
|
+
primaryDomain: 'yourstore.com',
|
|
64
|
+
},
|
|
65
|
+
transport: {
|
|
66
|
+
rest: { endpoint: 'https://api.yourstore.com/ucp/v1' },
|
|
67
|
+
},
|
|
68
|
+
capabilities: {
|
|
69
|
+
checkout: true,
|
|
70
|
+
order: true,
|
|
71
|
+
fulfillment: false,
|
|
72
|
+
discount: false,
|
|
73
|
+
product: false,
|
|
74
|
+
inventory: false,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
console.log(result.profileJson);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Generate Signing Keys
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { generateSigningKeyPair } from '@ucptools/validator';
|
|
85
|
+
|
|
86
|
+
// Generate Ed25519 key pair for Order capability
|
|
87
|
+
const { publicKey, privateKey, kid } = await generateSigningKeyPair('Ed25519');
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Validation Levels
|
|
93
|
+
|
|
94
|
+
### 1. Structural Validation (Fast, Offline)
|
|
95
|
+
- JSON structure verification
|
|
96
|
+
- Required fields check
|
|
97
|
+
- Version format validation (YYYY-MM-DD)
|
|
98
|
+
|
|
99
|
+
### 2. UCP Rules Validation (Offline)
|
|
100
|
+
- Namespace/origin binding (`dev.ucp.*` must use `ucp.dev` URLs)
|
|
101
|
+
- Extension chain validation (no orphaned `extends`)
|
|
102
|
+
- Endpoint rules (HTTPS, no trailing slash)
|
|
103
|
+
- Signing keys requirement for Order capability
|
|
104
|
+
|
|
105
|
+
### 3. Network Validation (Online)
|
|
106
|
+
- Fetch and verify remote schemas
|
|
107
|
+
- Self-describing schema validation
|
|
108
|
+
- Schema/capability version matching
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Validation Report
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
interface ValidationReport {
|
|
116
|
+
ok: boolean; // true if no errors
|
|
117
|
+
profile_url?: string; // URL of validated profile
|
|
118
|
+
ucp_version?: string; // UCP version from profile
|
|
119
|
+
issues: ValidationIssue[]; // Array of issues found
|
|
120
|
+
validated_at: string; // ISO timestamp
|
|
121
|
+
validation_mode: ValidationMode;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
interface ValidationIssue {
|
|
125
|
+
severity: 'error' | 'warn' | 'info';
|
|
126
|
+
code: string; // e.g., 'UCP_NS_ORIGIN_MISMATCH'
|
|
127
|
+
path: string; // JSON path, e.g., '$.ucp.capabilities[0]'
|
|
128
|
+
message: string;
|
|
129
|
+
hint?: string; // Suggestion to fix
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Error Codes
|
|
136
|
+
|
|
137
|
+
| Code | Severity | Description |
|
|
138
|
+
|------|----------|-------------|
|
|
139
|
+
| `UCP_MISSING_ROOT` | error | Missing `ucp` object at root |
|
|
140
|
+
| `UCP_MISSING_VERSION` | error | Missing version field |
|
|
141
|
+
| `UCP_INVALID_VERSION_FORMAT` | error | Version not in YYYY-MM-DD format |
|
|
142
|
+
| `UCP_NS_ORIGIN_MISMATCH` | error | Schema URL doesn't match namespace origin |
|
|
143
|
+
| `UCP_ORPHANED_EXTENSION` | error | Extends references non-existent capability |
|
|
144
|
+
| `UCP_ENDPOINT_NOT_HTTPS` | error | Endpoint must use HTTPS |
|
|
145
|
+
| `UCP_ENDPOINT_TRAILING_SLASH` | warn | Remove trailing slash from endpoint |
|
|
146
|
+
| `UCP_MISSING_SIGNING_KEYS` | error | Order capability requires signing_keys |
|
|
147
|
+
| `UCP_SCHEMA_FETCH_FAILED` | warn | Could not fetch remote schema |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## CLI Usage
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Validate a local file
|
|
155
|
+
npx @ucptools/validator validate -f ucp.json
|
|
156
|
+
|
|
157
|
+
# Validate a remote profile
|
|
158
|
+
npx @ucptools/validator validate -r yourstore.com
|
|
159
|
+
|
|
160
|
+
# Generate a minimal profile
|
|
161
|
+
npx @ucptools/validator generate-minimal -e https://api.example.com/ucp/v1 -o ucp.json
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Online Tool
|
|
167
|
+
|
|
168
|
+
Don't want to install anything? Use our free online tool:
|
|
169
|
+
|
|
170
|
+
**[ucptools.dev](https://ucptools.dev)** - AI Commerce Readiness Checker
|
|
171
|
+
|
|
172
|
+
- Validates UCP profiles + Schema.org requirements
|
|
173
|
+
- Generates UCP profiles with a simple form
|
|
174
|
+
- Creates Schema.org snippets (MerchantReturnPolicy, shippingDetails)
|
|
175
|
+
- Provides A-F grading and actionable recommendations
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Resources
|
|
180
|
+
|
|
181
|
+
- [UCP Specification](https://ucp.dev/specification/overview/)
|
|
182
|
+
- [UCP GitHub Repository](https://github.com/Universal-Commerce-Protocol/ucp)
|
|
183
|
+
- [Google UCP Business Profile Guide](https://developers.google.com/merchant/ucp/guides/business-profile)
|
|
184
|
+
- [UCP JavaScript SDK](https://github.com/Universal-Commerce-Protocol/js-sdk)
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Contributing
|
|
189
|
+
|
|
190
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT - See [LICENSE](LICENSE) for details.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
<p align="center">
|
|
201
|
+
Built with love for the AI Commerce ecosystem<br>
|
|
202
|
+
<a href="https://ucptools.dev">ucptools.dev</a>
|
|
203
|
+
</p>
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel Serverless Function: Product Feed Quality Analyzer
|
|
3
|
+
* POST /api/analyze-feed
|
|
4
|
+
*
|
|
5
|
+
* Analyzes product feed quality for AI agent visibility.
|
|
6
|
+
*
|
|
7
|
+
* Request body:
|
|
8
|
+
* {
|
|
9
|
+
* "url": "https://example.com/products",
|
|
10
|
+
* "maxProducts": 50,
|
|
11
|
+
* "includeProductDetails": true
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* GET /api/analyze-feed?url=https://example.com/products
|
|
15
|
+
* Quick analysis with default options.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export default async function handler(req, res) {
|
|
19
|
+
// Handle CORS
|
|
20
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
21
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
22
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
23
|
+
|
|
24
|
+
if (req.method === 'OPTIONS') {
|
|
25
|
+
return res.status(200).end();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Extract URL from query (GET) or body (POST)
|
|
29
|
+
let url;
|
|
30
|
+
let maxProducts = 50;
|
|
31
|
+
let includeProductDetails = true;
|
|
32
|
+
|
|
33
|
+
if (req.method === 'GET') {
|
|
34
|
+
url = req.query.url;
|
|
35
|
+
if (req.query.maxProducts) {
|
|
36
|
+
maxProducts = parseInt(req.query.maxProducts, 10);
|
|
37
|
+
}
|
|
38
|
+
if (req.query.includeProductDetails === 'false') {
|
|
39
|
+
includeProductDetails = false;
|
|
40
|
+
}
|
|
41
|
+
} else if (req.method === 'POST') {
|
|
42
|
+
const body = req.body || {};
|
|
43
|
+
url = body.url;
|
|
44
|
+
maxProducts = body.maxProducts || 50;
|
|
45
|
+
includeProductDetails = body.includeProductDetails !== false;
|
|
46
|
+
} else {
|
|
47
|
+
return res.status(405).json({
|
|
48
|
+
error: 'Method not allowed',
|
|
49
|
+
message: 'Use GET or POST to analyze a product feed',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Validate URL
|
|
54
|
+
if (!url) {
|
|
55
|
+
return res.status(400).json({
|
|
56
|
+
error: 'Missing URL',
|
|
57
|
+
message: 'Please provide a URL to analyze',
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
new URL(url);
|
|
63
|
+
} catch {
|
|
64
|
+
return res.status(400).json({
|
|
65
|
+
error: 'Invalid URL',
|
|
66
|
+
message: 'Please provide a valid URL',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Validate maxProducts
|
|
71
|
+
if (maxProducts < 1 || maxProducts > 100) {
|
|
72
|
+
return res.status(400).json({
|
|
73
|
+
error: 'Invalid maxProducts',
|
|
74
|
+
message: 'maxProducts must be between 1 and 100',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
// Fetch the page content
|
|
80
|
+
const controller = new AbortController();
|
|
81
|
+
const timeoutId = setTimeout(() => controller.abort(), 30000);
|
|
82
|
+
|
|
83
|
+
const response = await fetch(url, {
|
|
84
|
+
headers: {
|
|
85
|
+
'User-Agent': 'UCP-Tools Feed Analyzer/1.0 (https://ucp.day)',
|
|
86
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
87
|
+
},
|
|
88
|
+
signal: controller.signal,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
clearTimeout(timeoutId);
|
|
92
|
+
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
return res.status(400).json({
|
|
95
|
+
error: 'Failed to fetch URL',
|
|
96
|
+
message: `Server returned ${response.status}: ${response.statusText}`,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const html = await response.text();
|
|
101
|
+
|
|
102
|
+
// Import and run the analyzer
|
|
103
|
+
const { analyzeProductFeedFromHtml } = await import('../src/feed-analyzer/index.js');
|
|
104
|
+
|
|
105
|
+
const result = analyzeProductFeedFromHtml(html, url, {
|
|
106
|
+
maxProducts,
|
|
107
|
+
includeProductDetails,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Check if any products were found
|
|
111
|
+
if (result.productsFound === 0) {
|
|
112
|
+
return res.status(200).json({
|
|
113
|
+
success: true,
|
|
114
|
+
warning: 'No products found',
|
|
115
|
+
message: 'No Schema.org Product markup was found on this page. Make sure your page includes JSON-LD structured data with @type: "Product".',
|
|
116
|
+
...result,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return res.status(200).json({
|
|
121
|
+
success: true,
|
|
122
|
+
...result,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error('Feed analysis error:', error);
|
|
127
|
+
|
|
128
|
+
if (error.name === 'AbortError') {
|
|
129
|
+
return res.status(408).json({
|
|
130
|
+
error: 'Request timeout',
|
|
131
|
+
message: 'The request took too long. The target server may be slow or unresponsive.',
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return res.status(500).json({
|
|
136
|
+
error: 'Analysis failed',
|
|
137
|
+
message: error.message || 'An unexpected error occurred',
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|