@ucptools/validator 1.0.0 → 1.0.1
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/settings.local.json +60 -0
- package/.vercel/README.txt +11 -0
- package/.vercel/project.json +1 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +279 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/compliance/compliance-generator.d.ts +34 -0
- package/dist/compliance/compliance-generator.d.ts.map +1 -0
- package/dist/compliance/compliance-generator.js +320 -0
- package/dist/compliance/compliance-generator.js.map +1 -0
- package/dist/compliance/index.d.ts +8 -0
- package/dist/compliance/index.d.ts.map +1 -0
- package/dist/compliance/index.js +17 -0
- package/dist/compliance/index.js.map +1 -0
- package/dist/compliance/templates.d.ts +34 -0
- package/dist/compliance/templates.d.ts.map +1 -0
- package/{src/compliance/templates.ts → dist/compliance/templates.js} +117 -155
- package/dist/compliance/templates.js.map +1 -0
- package/dist/compliance/types.d.ts +64 -0
- package/dist/compliance/types.d.ts.map +1 -0
- package/dist/compliance/types.js +64 -0
- package/dist/compliance/types.js.map +1 -0
- package/dist/db/index.d.ts +11 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +63 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +444 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +65 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/feed-analyzer/feed-analyzer.d.ts +26 -0
- package/dist/feed-analyzer/feed-analyzer.d.ts.map +1 -0
- package/{src/feed-analyzer/feed-analyzer.ts → dist/feed-analyzer/feed-analyzer.js} +642 -726
- package/dist/feed-analyzer/feed-analyzer.js.map +1 -0
- package/dist/feed-analyzer/index.d.ts +8 -0
- package/dist/feed-analyzer/index.d.ts.map +1 -0
- package/dist/feed-analyzer/index.js +19 -0
- package/dist/feed-analyzer/index.js.map +1 -0
- package/dist/feed-analyzer/types.d.ts +204 -0
- package/dist/feed-analyzer/types.d.ts.map +1 -0
- package/dist/feed-analyzer/types.js +162 -0
- package/dist/feed-analyzer/types.js.map +1 -0
- package/{src/generator/index.ts → dist/generator/index.d.ts} +1 -1
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +13 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/key-generator.d.ts +24 -0
- package/dist/generator/key-generator.d.ts.map +1 -0
- package/dist/generator/key-generator.js +144 -0
- package/dist/generator/key-generator.js.map +1 -0
- package/dist/generator/profile-builder.d.ts +15 -0
- package/dist/generator/profile-builder.d.ts.map +1 -0
- package/dist/generator/profile-builder.js +338 -0
- package/dist/generator/profile-builder.js.map +1 -0
- package/dist/hosting/artifacts-generator.d.ts +10 -0
- package/dist/hosting/artifacts-generator.d.ts.map +1 -0
- package/{src/hosting/artifacts-generator.ts → dist/hosting/artifacts-generator.js} +191 -241
- package/dist/hosting/artifacts-generator.js.map +1 -0
- package/{src/hosting/index.ts → dist/hosting/index.d.ts} +1 -1
- package/dist/hosting/index.d.ts.map +1 -0
- package/dist/hosting/index.js +10 -0
- package/dist/hosting/index.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -0
- package/{src/security/index.ts → dist/security/index.d.ts} +8 -15
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +12 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/security-scanner.d.ts +10 -0
- package/dist/security/security-scanner.d.ts.map +1 -0
- package/dist/security/security-scanner.js +541 -0
- package/dist/security/security-scanner.js.map +1 -0
- package/dist/security/types.d.ts +48 -0
- package/dist/security/types.d.ts.map +1 -0
- package/dist/security/types.js +21 -0
- package/dist/security/types.js.map +1 -0
- package/dist/services/directory.d.ts +104 -0
- package/dist/services/directory.d.ts.map +1 -0
- package/dist/services/directory.js +333 -0
- package/dist/services/directory.js.map +1 -0
- package/dist/simulator/agent-simulator.d.ts +69 -0
- package/dist/simulator/agent-simulator.d.ts.map +1 -0
- package/{src/simulator/agent-simulator.ts → dist/simulator/agent-simulator.js} +650 -941
- package/dist/simulator/agent-simulator.js.map +1 -0
- package/{src/simulator/index.ts → dist/simulator/index.d.ts} +7 -7
- package/dist/simulator/index.d.ts.map +1 -0
- package/dist/simulator/index.js +23 -0
- package/dist/simulator/index.js.map +1 -0
- package/{src/simulator/types.ts → dist/simulator/types.d.ts} +145 -170
- package/dist/simulator/types.d.ts.map +1 -0
- package/dist/simulator/types.js +18 -0
- package/dist/simulator/types.js.map +1 -0
- package/dist/types/generator.d.ts +106 -0
- package/dist/types/generator.d.ts.map +1 -0
- package/dist/types/generator.js +6 -0
- package/dist/types/generator.js.map +1 -0
- package/{src/types/index.ts → dist/types/index.d.ts} +1 -1
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/ucp-profile.d.ts +103 -0
- package/dist/types/ucp-profile.d.ts.map +1 -0
- package/dist/types/ucp-profile.js +45 -0
- package/dist/types/ucp-profile.js.map +1 -0
- package/dist/types/validation.d.ts +68 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +32 -0
- package/dist/types/validation.js.map +1 -0
- package/dist/validator/index.d.ts +26 -0
- package/dist/validator/index.d.ts.map +1 -0
- package/dist/validator/index.js +161 -0
- package/dist/validator/index.js.map +1 -0
- package/dist/validator/network-validator.d.ts +28 -0
- package/dist/validator/network-validator.d.ts.map +1 -0
- package/dist/validator/network-validator.js +319 -0
- package/dist/validator/network-validator.js.map +1 -0
- package/dist/validator/rules-validator.d.ts +11 -0
- package/dist/validator/rules-validator.d.ts.map +1 -0
- package/dist/validator/rules-validator.js +257 -0
- package/dist/validator/rules-validator.js.map +1 -0
- package/dist/validator/sdk-validator.d.ts +58 -0
- package/dist/validator/sdk-validator.d.ts.map +1 -0
- package/{src/validator/sdk-validator.ts → dist/validator/sdk-validator.js} +273 -330
- package/dist/validator/sdk-validator.js.map +1 -0
- package/dist/validator/structural-validator.d.ts +11 -0
- package/dist/validator/structural-validator.d.ts.map +1 -0
- package/dist/validator/structural-validator.js +415 -0
- package/dist/validator/structural-validator.js.map +1 -0
- package/package.json +1 -1
- package/publish-output.txt +0 -0
- package/CLAUDE.md +0 -109
- package/api/analyze-feed.js +0 -140
- package/api/badge.js +0 -185
- package/api/benchmark.js +0 -177
- package/api/directory-stats.ts +0 -29
- package/api/directory.ts +0 -73
- package/api/generate-compliance.js +0 -143
- package/api/generate-schema.js +0 -457
- package/api/generate.js +0 -132
- package/api/security-scan.js +0 -133
- package/api/simulate.js +0 -187
- package/api/tsconfig.json +0 -10
- package/api/validate.js +0 -1351
- package/apify-actor/.actor/actor.json +0 -68
- package/apify-actor/.actor/input_schema.json +0 -32
- package/apify-actor/APIFY-STORE-LISTING.md +0 -412
- package/apify-actor/Dockerfile +0 -8
- package/apify-actor/README.md +0 -166
- package/apify-actor/main.ts +0 -111
- package/apify-actor/package.json +0 -17
- package/apify-actor/src/main.js +0 -199
- package/docs/BRAND-IDENTITY.md +0 -238
- package/docs/BRAND-STYLE-GUIDE.md +0 -356
- package/drizzle/0000_black_king_cobra.sql +0 -39
- package/drizzle/meta/0000_snapshot.json +0 -309
- package/drizzle/meta/_journal.json +0 -13
- package/drizzle.config.ts +0 -10
- package/public/.well-known/ucp +0 -25
- 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 +0 -321
- package/public/directory.html +0 -701
- 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 +0 -743
- package/public/guides/fastucp.html +0 -838
- package/public/guides/magento.html +0 -779
- package/public/guides/shopify.html +0 -726
- package/public/guides/squarespace.html +0 -749
- package/public/guides/wix.html +0 -747
- package/public/guides/woocommerce.html +0 -733
- package/public/index.html +0 -3835
- package/public/learn.html +0 -396
- 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 +0 -6
- package/public/site.webmanifest +0 -31
- package/public/sitemap.xml +0 -69
- 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 +0 -410
- package/scripts/generate-favicons.js +0 -44
- package/scripts/generate-ico.js +0 -23
- package/scripts/generate-og-image.js +0 -45
- package/scripts/reset-db.ts +0 -77
- package/scripts/seed-db.ts +0 -71
- package/scripts/setup-benchmark-db.js +0 -70
- package/src/api/server.ts +0 -266
- package/src/cli/index.ts +0 -302
- package/src/compliance/compliance-generator.ts +0 -452
- package/src/compliance/index.ts +0 -28
- package/src/compliance/types.ts +0 -170
- package/src/db/index.ts +0 -28
- package/src/db/schema.ts +0 -84
- package/src/feed-analyzer/index.ts +0 -34
- package/src/feed-analyzer/types.ts +0 -354
- package/src/generator/key-generator.ts +0 -124
- package/src/generator/profile-builder.ts +0 -402
- package/src/index.ts +0 -105
- package/src/security/security-scanner.ts +0 -604
- package/src/security/types.ts +0 -55
- package/src/services/directory.ts +0 -434
- package/src/types/generator.ts +0 -140
- package/src/types/ucp-profile.ts +0 -140
- package/src/types/validation.ts +0 -89
- package/src/validator/index.ts +0 -194
- package/src/validator/network-validator.ts +0 -417
- package/src/validator/rules-validator.ts +0 -297
- package/src/validator/structural-validator.ts +0 -476
- package/tests/fixtures/non-compliant-profile.json +0 -25
- package/tests/fixtures/official-sample-profile.json +0 -75
- package/tests/integration/benchmark.test.ts +0 -207
- package/tests/integration/database.test.ts +0 -163
- package/tests/integration/directory-api.test.ts +0 -268
- package/tests/integration/simulate-api.test.ts +0 -230
- package/tests/integration/validate-api.test.ts +0 -269
- package/tests/setup.ts +0 -15
- package/tests/unit/agent-simulator.test.ts +0 -575
- package/tests/unit/compliance-generator.test.ts +0 -374
- package/tests/unit/directory-service.test.ts +0 -272
- package/tests/unit/feed-analyzer.test.ts +0 -517
- package/tests/unit/lint-suggestions.test.ts +0 -423
- package/tests/unit/official-samples.test.ts +0 -211
- package/tests/unit/pdf-report.test.ts +0 -390
- package/tests/unit/sdk-validator.test.ts +0 -531
- package/tests/unit/security-scanner.test.ts +0 -410
- package/tests/unit/validation.test.ts +0 -390
- package/vercel.json +0 -34
- package/vitest.config.ts +0 -22
package/apify-actor/main.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UCP Profile Validator - Apify Actor
|
|
3
|
-
* Validates any domain's UCP Business Profile at /.well-known/ucp
|
|
4
|
-
*
|
|
5
|
-
* Free tier: validation + report
|
|
6
|
-
* Paid tier: generation + monitoring
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { Actor } from 'apify';
|
|
10
|
-
import { validateRemote, validateQuick } from '../src/validator/index.js';
|
|
11
|
-
|
|
12
|
-
interface Input {
|
|
13
|
-
domain: string;
|
|
14
|
-
mode?: 'quick' | 'full';
|
|
15
|
-
includeRecommendations?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface Output {
|
|
19
|
-
domain: string;
|
|
20
|
-
profileUrl: string;
|
|
21
|
-
valid: boolean;
|
|
22
|
-
score: number;
|
|
23
|
-
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
24
|
-
ucpVersion?: string;
|
|
25
|
-
errors: number;
|
|
26
|
-
warnings: number;
|
|
27
|
-
issues: Array<{
|
|
28
|
-
severity: string;
|
|
29
|
-
code: string;
|
|
30
|
-
message: string;
|
|
31
|
-
hint?: string;
|
|
32
|
-
}>;
|
|
33
|
-
recommendations?: string[];
|
|
34
|
-
checkedAt: string;
|
|
35
|
-
// CTA for monetization
|
|
36
|
-
upgradeUrl: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
await Actor.init();
|
|
40
|
-
|
|
41
|
-
const input = await Actor.getInput<Input>();
|
|
42
|
-
|
|
43
|
-
if (!input?.domain) {
|
|
44
|
-
throw new Error('Missing required input: domain');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const domain = input.domain.replace(/^https?:\/\//, '').replace(/\/$/, '');
|
|
48
|
-
|
|
49
|
-
console.log(`Validating UCP profile for: ${domain}`);
|
|
50
|
-
|
|
51
|
-
const report = await validateRemote(domain, {
|
|
52
|
-
mode: input.mode === 'quick' ? 'rules' : 'full',
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const profileUrl = report.profile_url || `https://${domain}/.well-known/ucp`;
|
|
56
|
-
|
|
57
|
-
// Calculate score (0-100)
|
|
58
|
-
const errorWeight = 20;
|
|
59
|
-
const warnWeight = 5;
|
|
60
|
-
const errors = report.issues.filter(i => i.severity === 'error').length;
|
|
61
|
-
const warnings = report.issues.filter(i => i.severity === 'warn').length;
|
|
62
|
-
const score = Math.max(0, 100 - (errors * errorWeight) - (warnings * warnWeight));
|
|
63
|
-
|
|
64
|
-
// Calculate grade
|
|
65
|
-
const grade = score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : score >= 60 ? 'D' : 'F';
|
|
66
|
-
|
|
67
|
-
// Generate recommendations
|
|
68
|
-
const recommendations: string[] = [];
|
|
69
|
-
if (errors > 0) {
|
|
70
|
-
recommendations.push('Fix all errors before going live with UCP-enabled agents');
|
|
71
|
-
}
|
|
72
|
-
if (!report.ucp_version) {
|
|
73
|
-
recommendations.push('Ensure your profile is accessible at /.well-known/ucp');
|
|
74
|
-
}
|
|
75
|
-
if (report.issues.some(i => i.code === 'UCP_MISSING_SIGNING_KEYS')) {
|
|
76
|
-
recommendations.push('Add signing_keys if you plan to use Order capability with webhooks');
|
|
77
|
-
}
|
|
78
|
-
if (report.issues.some(i => i.code === 'UCP_ENDPOINT_NOT_HTTPS')) {
|
|
79
|
-
recommendations.push('All endpoints must use HTTPS for security');
|
|
80
|
-
}
|
|
81
|
-
if (score === 100) {
|
|
82
|
-
recommendations.push('Your profile is fully compliant! Consider adding more capabilities.');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const output: Output = {
|
|
86
|
-
domain,
|
|
87
|
-
profileUrl,
|
|
88
|
-
valid: report.ok,
|
|
89
|
-
score,
|
|
90
|
-
grade,
|
|
91
|
-
ucpVersion: report.ucp_version,
|
|
92
|
-
errors,
|
|
93
|
-
warnings,
|
|
94
|
-
issues: report.issues.map(i => ({
|
|
95
|
-
severity: i.severity,
|
|
96
|
-
code: i.code,
|
|
97
|
-
message: i.message,
|
|
98
|
-
hint: i.hint,
|
|
99
|
-
})),
|
|
100
|
-
recommendations: input.includeRecommendations !== false ? recommendations : undefined,
|
|
101
|
-
checkedAt: report.validated_at,
|
|
102
|
-
upgradeUrl: 'https://ucp.tools/generate?ref=apify',
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
console.log(`\nValidation complete: ${grade} (${score}/100)`);
|
|
106
|
-
console.log(`Errors: ${errors}, Warnings: ${warnings}`);
|
|
107
|
-
|
|
108
|
-
await Actor.pushData(output);
|
|
109
|
-
await Actor.setValue('OUTPUT', output);
|
|
110
|
-
|
|
111
|
-
await Actor.exit();
|
package/apify-actor/package.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "ucp-profile-validator-actor",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "Apify Actor: Validate UCP Business Profiles",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "src/main.js",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"start": "node src/main.js",
|
|
9
|
-
"test": "echo \"No tests yet\""
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"apify": "^3.1.0"
|
|
13
|
-
},
|
|
14
|
-
"engines": {
|
|
15
|
-
"node": ">=18"
|
|
16
|
-
}
|
|
17
|
-
}
|
package/apify-actor/src/main.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UCP Profile Validator - Apify Actor
|
|
3
|
-
* Validates any domain's UCP Business Profile at /.well-known/ucp
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Actor } from 'apify';
|
|
7
|
-
|
|
8
|
-
const VERSION_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
9
|
-
|
|
10
|
-
async function fetchProfile(domain) {
|
|
11
|
-
// Try both /.well-known/ucp and /.well-known/ucp.json
|
|
12
|
-
const urls = [
|
|
13
|
-
`https://${domain}/.well-known/ucp`,
|
|
14
|
-
`https://${domain}/.well-known/ucp.json`,
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
for (const url of urls) {
|
|
18
|
-
try {
|
|
19
|
-
const res = await fetch(url, {
|
|
20
|
-
headers: { 'Accept': 'application/json', 'User-Agent': 'UCP-Validator-Apify/1.0' },
|
|
21
|
-
signal: AbortSignal.timeout(15000),
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
if (!res.ok) continue;
|
|
25
|
-
|
|
26
|
-
const text = await res.text();
|
|
27
|
-
// Check if response looks like JSON (not HTML)
|
|
28
|
-
if (text.trim().startsWith('<')) continue;
|
|
29
|
-
|
|
30
|
-
const profile = JSON.parse(text);
|
|
31
|
-
return { profile, profileUrl: url };
|
|
32
|
-
} catch (e) {
|
|
33
|
-
// Try next URL
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return { profile: null, error: 'No UCP profile found at /.well-known/ucp or /.well-known/ucp.json' };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function validateProfile(profile) {
|
|
42
|
-
const issues = [];
|
|
43
|
-
|
|
44
|
-
if (!profile || typeof profile !== 'object') {
|
|
45
|
-
issues.push({ severity: 'error', code: 'UCP_MISSING_ROOT', path: '$', message: 'Profile must be a JSON object' });
|
|
46
|
-
return issues;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (!profile.ucp || typeof profile.ucp !== 'object') {
|
|
50
|
-
issues.push({ severity: 'error', code: 'UCP_MISSING_ROOT', path: '$.ucp', message: 'Missing required "ucp" object' });
|
|
51
|
-
return issues;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const ucp = profile.ucp;
|
|
55
|
-
|
|
56
|
-
// Version validation
|
|
57
|
-
if (!ucp.version) {
|
|
58
|
-
issues.push({ severity: 'error', code: 'UCP_MISSING_VERSION', path: '$.ucp.version', message: 'Missing version field' });
|
|
59
|
-
} else if (!VERSION_REGEX.test(ucp.version)) {
|
|
60
|
-
issues.push({ severity: 'error', code: 'UCP_INVALID_VERSION', path: '$.ucp.version', message: `Invalid version: ${ucp.version}`, hint: 'Use YYYY-MM-DD format' });
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Services validation
|
|
64
|
-
if (!ucp.services || typeof ucp.services !== 'object') {
|
|
65
|
-
issues.push({ severity: 'error', code: 'UCP_MISSING_SERVICES', path: '$.ucp.services', message: 'Missing services' });
|
|
66
|
-
} else {
|
|
67
|
-
for (const [name, svc] of Object.entries(ucp.services)) {
|
|
68
|
-
if (!svc.version) issues.push({ severity: 'error', code: 'UCP_INVALID_SERVICE', path: `$.ucp.services["${name}"].version`, message: `Service "${name}" missing version` });
|
|
69
|
-
if (!svc.spec) issues.push({ severity: 'error', code: 'UCP_INVALID_SERVICE', path: `$.ucp.services["${name}"].spec`, message: `Service "${name}" missing spec` });
|
|
70
|
-
if (!svc.rest && !svc.mcp && !svc.a2a && !svc.embedded) {
|
|
71
|
-
issues.push({ severity: 'warn', code: 'UCP_NO_TRANSPORT', path: `$.ucp.services["${name}"]`, message: `Service "${name}" has no transport bindings` });
|
|
72
|
-
}
|
|
73
|
-
if (svc.rest?.endpoint) {
|
|
74
|
-
if (!svc.rest.endpoint.startsWith('https://')) {
|
|
75
|
-
issues.push({ severity: 'error', code: 'UCP_ENDPOINT_NOT_HTTPS', path: `$.ucp.services["${name}"].rest.endpoint`, message: 'Endpoint must use HTTPS' });
|
|
76
|
-
}
|
|
77
|
-
if (svc.rest.endpoint.endsWith('/')) {
|
|
78
|
-
issues.push({ severity: 'warn', code: 'UCP_TRAILING_SLASH', path: `$.ucp.services["${name}"].rest.endpoint`, message: 'Remove trailing slash' });
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Capabilities validation
|
|
85
|
-
if (!ucp.capabilities || !Array.isArray(ucp.capabilities)) {
|
|
86
|
-
issues.push({ severity: 'error', code: 'UCP_MISSING_CAPABILITIES', path: '$.ucp.capabilities', message: 'Missing capabilities array' });
|
|
87
|
-
} else {
|
|
88
|
-
const capNames = new Set(ucp.capabilities.map(c => c.name));
|
|
89
|
-
ucp.capabilities.forEach((cap, i) => {
|
|
90
|
-
const path = `$.ucp.capabilities[${i}]`;
|
|
91
|
-
if (!cap.name) issues.push({ severity: 'error', code: 'UCP_INVALID_CAP', path: `${path}.name`, message: 'Missing name' });
|
|
92
|
-
if (!cap.version) issues.push({ severity: 'error', code: 'UCP_INVALID_CAP', path: `${path}.version`, message: 'Missing version' });
|
|
93
|
-
if (!cap.spec) issues.push({ severity: 'error', code: 'UCP_INVALID_CAP', path: `${path}.spec`, message: 'Missing spec' });
|
|
94
|
-
if (!cap.schema) issues.push({ severity: 'error', code: 'UCP_INVALID_CAP', path: `${path}.schema`, message: 'Missing schema' });
|
|
95
|
-
|
|
96
|
-
// Namespace checks
|
|
97
|
-
if (cap.name?.startsWith('dev.ucp.')) {
|
|
98
|
-
if (cap.spec && !cap.spec.startsWith('https://ucp.dev/')) {
|
|
99
|
-
issues.push({ severity: 'error', code: 'UCP_NS_MISMATCH', path: `${path}.spec`, message: 'dev.ucp.* spec must be on ucp.dev' });
|
|
100
|
-
}
|
|
101
|
-
if (cap.schema && !cap.schema.startsWith('https://ucp.dev/')) {
|
|
102
|
-
issues.push({ severity: 'error', code: 'UCP_NS_MISMATCH', path: `${path}.schema`, message: 'dev.ucp.* schema must be on ucp.dev' });
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Extension checks
|
|
107
|
-
if (cap.extends && !capNames.has(cap.extends)) {
|
|
108
|
-
issues.push({ severity: 'error', code: 'UCP_ORPHAN_EXT', path: `${path}.extends`, message: `Parent "${cap.extends}" not found` });
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// Signing keys check
|
|
113
|
-
const hasOrder = ucp.capabilities.some(c => c.name === 'dev.ucp.shopping.order');
|
|
114
|
-
if (hasOrder && (!profile.signing_keys || profile.signing_keys.length === 0)) {
|
|
115
|
-
issues.push({ severity: 'error', code: 'UCP_MISSING_KEYS', path: '$.signing_keys', message: 'Order requires signing_keys' });
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return issues;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
await Actor.init();
|
|
123
|
-
|
|
124
|
-
const input = await Actor.getInput();
|
|
125
|
-
|
|
126
|
-
if (!input?.domain) {
|
|
127
|
-
throw new Error('Missing required input: domain');
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const domain = input.domain.replace(/^https?:\/\//, '').replace(/\/$/, '');
|
|
131
|
-
|
|
132
|
-
console.log(`🔍 Validating UCP profile for: ${domain}`);
|
|
133
|
-
|
|
134
|
-
const { profile, profileUrl: foundProfileUrl, error } = await fetchProfile(domain);
|
|
135
|
-
const profileUrl = foundProfileUrl || `https://${domain}/.well-known/ucp`;
|
|
136
|
-
|
|
137
|
-
let issues = [];
|
|
138
|
-
let ucpVersion = null;
|
|
139
|
-
|
|
140
|
-
if (error || !profile) {
|
|
141
|
-
issues.push({
|
|
142
|
-
severity: 'error',
|
|
143
|
-
code: 'UCP_FETCH_FAILED',
|
|
144
|
-
path: '$.well-known/ucp',
|
|
145
|
-
message: error || 'Failed to fetch profile',
|
|
146
|
-
});
|
|
147
|
-
} else {
|
|
148
|
-
issues = validateProfile(profile);
|
|
149
|
-
ucpVersion = profile?.ucp?.version;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Calculate score
|
|
153
|
-
const errors = issues.filter(i => i.severity === 'error').length;
|
|
154
|
-
const warnings = issues.filter(i => i.severity === 'warn').length;
|
|
155
|
-
const score = Math.max(0, 100 - (errors * 20) - (warnings * 5));
|
|
156
|
-
const grade = score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : score >= 60 ? 'D' : 'F';
|
|
157
|
-
|
|
158
|
-
// Recommendations
|
|
159
|
-
const recommendations = [];
|
|
160
|
-
if (errors > 0) recommendations.push('Fix all errors before deploying');
|
|
161
|
-
if (!ucpVersion) recommendations.push('Ensure profile is accessible at /.well-known/ucp');
|
|
162
|
-
if (issues.some(i => i.code === 'UCP_MISSING_KEYS')) recommendations.push('Add signing_keys for Order capability');
|
|
163
|
-
if (score === 100) recommendations.push('Profile is fully compliant!');
|
|
164
|
-
|
|
165
|
-
const output = {
|
|
166
|
-
domain,
|
|
167
|
-
profileUrl,
|
|
168
|
-
valid: errors === 0,
|
|
169
|
-
score,
|
|
170
|
-
grade,
|
|
171
|
-
ucpVersion,
|
|
172
|
-
errors,
|
|
173
|
-
warnings,
|
|
174
|
-
issues: issues.map(i => ({
|
|
175
|
-
severity: i.severity,
|
|
176
|
-
code: i.code,
|
|
177
|
-
message: i.message,
|
|
178
|
-
hint: i.hint,
|
|
179
|
-
})),
|
|
180
|
-
recommendations: input.includeRecommendations !== false ? recommendations : undefined,
|
|
181
|
-
checkedAt: new Date().toISOString(),
|
|
182
|
-
generatorUrl: 'https://ucptools.dev/generate',
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
console.log(`\n📊 Result: ${grade} (${score}/100)`);
|
|
186
|
-
console.log(` Errors: ${errors}, Warnings: ${warnings}`);
|
|
187
|
-
if (errors === 0) {
|
|
188
|
-
console.log('✅ Profile is valid!');
|
|
189
|
-
} else {
|
|
190
|
-
console.log('❌ Profile has issues that need to be fixed');
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Push result to dataset
|
|
194
|
-
// Note: Using PPE with synthetic 'apify-default-dataset-item' event
|
|
195
|
-
// This automatically charges users per result - no manual Actor.charge() needed
|
|
196
|
-
await Actor.pushData(output);
|
|
197
|
-
await Actor.setValue('OUTPUT', output);
|
|
198
|
-
|
|
199
|
-
await Actor.exit();
|
package/docs/BRAND-IDENTITY.md
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
# UCP.tools - Brand Identity Guide
|
|
2
|
-
|
|
3
|
-
## Brand Overview
|
|
4
|
-
|
|
5
|
-
**UCP.tools** is an independent developer tool that helps merchants prepare for AI-powered commerce by validating and generating Universal Commerce Protocol (UCP) business profiles.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Brand Name & Variations
|
|
10
|
-
|
|
11
|
-
| Context | Usage |
|
|
12
|
-
|---------|-------|
|
|
13
|
-
| **Primary** | UCP.tools |
|
|
14
|
-
| **Domain** | ucptools.dev (or ucptools.io as fallback) |
|
|
15
|
-
| **Apify Actor** | UCP Profile Validator |
|
|
16
|
-
| **npm package** | ucp-profile-tools |
|
|
17
|
-
| **GitHub** | ucp-tools |
|
|
18
|
-
| **Tagline** | "Get ready for AI commerce" |
|
|
19
|
-
| **Short tagline** | "Validate. Generate. Ship." |
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Brand Voice & Personality
|
|
24
|
-
|
|
25
|
-
### Tone
|
|
26
|
-
- **Developer-first**: Technical but approachable
|
|
27
|
-
- **Direct**: No fluff, get to the point
|
|
28
|
-
- **Helpful**: Focus on solving problems
|
|
29
|
-
- **Independent**: Not affiliated with any platform
|
|
30
|
-
|
|
31
|
-
### Language Style
|
|
32
|
-
- Use "you/your" not "users/merchants"
|
|
33
|
-
- Active voice: "Validate your profile" not "Profiles can be validated"
|
|
34
|
-
- Confident: "Fix issues instantly" not "May help fix issues"
|
|
35
|
-
- No corporate jargon: "Check" not "Leverage our validation capabilities"
|
|
36
|
-
|
|
37
|
-
### Example Copy
|
|
38
|
-
|
|
39
|
-
**Good:**
|
|
40
|
-
> "Your UCP profile has 2 errors. Here's how to fix them."
|
|
41
|
-
|
|
42
|
-
**Bad:**
|
|
43
|
-
> "Our comprehensive validation engine has detected potential compliance issues in your Universal Commerce Protocol business profile configuration."
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## Visual Identity
|
|
48
|
-
|
|
49
|
-
### Colors
|
|
50
|
-
|
|
51
|
-
| Name | Hex | Usage |
|
|
52
|
-
|------|-----|-------|
|
|
53
|
-
| **Primary Blue** | `#2563eb` | Buttons, links, accents |
|
|
54
|
-
| **Primary Dark** | `#1d4ed8` | Hover states |
|
|
55
|
-
| **Success Green** | `#16a34a` | Valid, success states |
|
|
56
|
-
| **Warning Amber** | `#ca8a04` | Warnings |
|
|
57
|
-
| **Error Red** | `#dc2626` | Errors, invalid states |
|
|
58
|
-
| **Background** | `#f8fafc` | Page background |
|
|
59
|
-
| **Card White** | `#ffffff` | Cards, panels |
|
|
60
|
-
| **Text Dark** | `#1e293b` | Primary text |
|
|
61
|
-
| **Text Muted** | `#64748b` | Secondary text |
|
|
62
|
-
| **Border** | `#e2e8f0` | Borders, dividers |
|
|
63
|
-
|
|
64
|
-
### Typography
|
|
65
|
-
|
|
66
|
-
- **Headings**: System font stack (SF Pro, Segoe UI, Roboto)
|
|
67
|
-
- **Body**: Same system font stack
|
|
68
|
-
- **Code**: Monospace (SF Mono, Consolas, Monaco)
|
|
69
|
-
- **Font weights**: 400 (normal), 500 (medium), 600 (semibold), 700 (bold)
|
|
70
|
-
|
|
71
|
-
### Logo Concepts
|
|
72
|
-
|
|
73
|
-
**Text Logo:**
|
|
74
|
-
```
|
|
75
|
-
UCP.tools
|
|
76
|
-
```
|
|
77
|
-
- "UCP" in Primary Blue (#2563eb), bold
|
|
78
|
-
- ".tools" in Text Muted (#64748b), normal weight
|
|
79
|
-
|
|
80
|
-
**Icon Concepts:**
|
|
81
|
-
- Checkmark inside a document/file icon
|
|
82
|
-
- Shield with checkmark (security/validation)
|
|
83
|
-
- Interconnected nodes (protocol/commerce)
|
|
84
|
-
|
|
85
|
-
### Grade Badges (Validation Scores)
|
|
86
|
-
|
|
87
|
-
| Grade | Background | Text Color |
|
|
88
|
-
|-------|------------|------------|
|
|
89
|
-
| A | `#dcfce7` | `#16a34a` |
|
|
90
|
-
| B | `#dbeafe` | `#2563eb` |
|
|
91
|
-
| C | `#fef9c3` | `#ca8a04` |
|
|
92
|
-
| D | `#fed7aa` | `#ea580c` |
|
|
93
|
-
| F | `#fee2e2` | `#dc2626` |
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## Messaging Framework
|
|
98
|
-
|
|
99
|
-
### Elevator Pitch (10 seconds)
|
|
100
|
-
> "UCP.tools validates and generates UCP business profiles so your store is ready for AI shopping agents."
|
|
101
|
-
|
|
102
|
-
### Short Description (30 seconds)
|
|
103
|
-
> "UCP.tools is a free validator and generator for Universal Commerce Protocol profiles. Check if your /.well-known/ucp endpoint is correct, generate compliant profiles, and get ready for AI-powered commerce - in seconds."
|
|
104
|
-
|
|
105
|
-
### Full Description (Product Hunt / Apify Store)
|
|
106
|
-
> "The Universal Commerce Protocol (UCP) lets AI agents discover and transact with online stores. But getting your profile right is tricky - wrong namespaces, missing fields, and endpoint issues break agent compatibility.
|
|
107
|
-
>
|
|
108
|
-
> UCP.tools fixes that:
|
|
109
|
-
> - **Validate** any domain's UCP profile instantly
|
|
110
|
-
> - **Generate** compliant profiles with a simple wizard
|
|
111
|
-
> - **Get actionable fixes** for every issue found
|
|
112
|
-
> - **Score your readiness** with A-F grades
|
|
113
|
-
>
|
|
114
|
-
> Free to use. No signup required. Built by developers, for developers."
|
|
115
|
-
|
|
116
|
-
### Key Messages
|
|
117
|
-
|
|
118
|
-
1. **Problem**: "AI agents can't discover your store if your UCP profile is broken"
|
|
119
|
-
2. **Solution**: "Validate and fix your profile in seconds"
|
|
120
|
-
3. **Proof**: "Checks all UCP spec rules: namespaces, endpoints, signing keys"
|
|
121
|
-
4. **CTA**: "Check your profile free at ucptools.dev"
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## Target Audience
|
|
126
|
-
|
|
127
|
-
### Primary: Developers & Technical Founders
|
|
128
|
-
- Building on headless commerce (Medusa, Saleor, custom)
|
|
129
|
-
- Care about standards compliance
|
|
130
|
-
- Comfortable with JSON/APIs
|
|
131
|
-
- Value speed and accuracy
|
|
132
|
-
|
|
133
|
-
### Secondary: E-commerce Agencies
|
|
134
|
-
- Managing multiple client stores
|
|
135
|
-
- Need bulk validation
|
|
136
|
-
- Want white-label reports
|
|
137
|
-
|
|
138
|
-
### Tertiary: Non-technical Merchants
|
|
139
|
-
- Shopify/WooCommerce store owners
|
|
140
|
-
- Need simple "is it working?" check
|
|
141
|
-
- May upgrade to managed service
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Competitive Positioning
|
|
146
|
-
|
|
147
|
-
### We Are
|
|
148
|
-
- Free and instant
|
|
149
|
-
- Developer-focused
|
|
150
|
-
- Independent (not affiliated with Google/Shopify)
|
|
151
|
-
- Self-serve first
|
|
152
|
-
|
|
153
|
-
### We Are Not
|
|
154
|
-
- Enterprise sales motion
|
|
155
|
-
- Full UCP implementation service
|
|
156
|
-
- Platform-specific (works with any backend)
|
|
157
|
-
|
|
158
|
-
### Differentiators
|
|
159
|
-
| Feature | UCP.tools | UCP Ready | WellKnown | UCP Playground |
|
|
160
|
-
|---------|-----------|-----------|-----------|----------------|
|
|
161
|
-
| Free validation | ✅ Unlimited | Limited | ❌ | Demo only |
|
|
162
|
-
| Profile generation | ✅ | ❌ | ❌ | ❌ |
|
|
163
|
-
| CLI/API access | ✅ | ❌ | ❌ | ❌ |
|
|
164
|
-
| No signup | ✅ | ? | ❌ | ✅ |
|
|
165
|
-
|
|
166
|
-
---
|
|
167
|
-
|
|
168
|
-
## Content Guidelines
|
|
169
|
-
|
|
170
|
-
### Headlines
|
|
171
|
-
- Lead with benefit: "Validate Your UCP Profile" not "UCP Validation Tool"
|
|
172
|
-
- Use numbers: "Fix 12 common UCP errors" not "Fix UCP errors"
|
|
173
|
-
- Create urgency: "AI agents are coming. Is your store ready?"
|
|
174
|
-
|
|
175
|
-
### Call-to-Actions
|
|
176
|
-
- Primary: "Validate Now" / "Check Your Profile"
|
|
177
|
-
- Secondary: "Generate Profile" / "Download JSON"
|
|
178
|
-
- Tertiary: "See Pricing" / "Get Pro"
|
|
179
|
-
|
|
180
|
-
### Error Messages
|
|
181
|
-
- Be specific: "Endpoint must use HTTPS" not "Invalid endpoint"
|
|
182
|
-
- Be helpful: Include "hint" with fix suggestion
|
|
183
|
-
- Be human: "Oops, we couldn't reach your profile" not "Error 404"
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## Social Media Templates
|
|
188
|
-
|
|
189
|
-
### Twitter/X Bio
|
|
190
|
-
> Free UCP profile validator & generator. Get your store ready for AI commerce agents. ⚡ Instant results, no signup.
|
|
191
|
-
|
|
192
|
-
### Product Hunt Tagline
|
|
193
|
-
> Validate and generate UCP profiles for AI-powered commerce
|
|
194
|
-
|
|
195
|
-
### GitHub Description
|
|
196
|
-
> Free, open-source UCP (Universal Commerce Protocol) profile validator and generator. CLI + API + Web UI.
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
## Legal & Disclaimers
|
|
201
|
-
|
|
202
|
-
### Standard Disclaimer
|
|
203
|
-
> "UCP.tools is an independent project and is not affiliated with, endorsed by, or sponsored by Google, Shopify, or the Universal Commerce Protocol working group."
|
|
204
|
-
|
|
205
|
-
### Open Source Notice
|
|
206
|
-
> "UCP.tools is open source under the MIT license. The UCP specification is maintained by the UCP working group."
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
## Asset Checklist for Launch
|
|
211
|
-
|
|
212
|
-
- [ ] Logo (SVG, PNG @1x, @2x)
|
|
213
|
-
- [ ] Favicon (16x16, 32x32, apple-touch-icon)
|
|
214
|
-
- [ ] Open Graph image (1200x630)
|
|
215
|
-
- [ ] Twitter card image (1200x600)
|
|
216
|
-
- [ ] Product Hunt thumbnail (240x240)
|
|
217
|
-
- [ ] Apify Actor icon (256x256)
|
|
218
|
-
- [ ] Screenshots (web UI, CLI output, validation report)
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
## GPT Prompt for Brand-Consistent Content
|
|
223
|
-
|
|
224
|
-
When generating content for UCP.tools, use this context:
|
|
225
|
-
|
|
226
|
-
```
|
|
227
|
-
You are writing for UCP.tools, a free developer tool that validates and generates Universal Commerce Protocol (UCP) business profiles.
|
|
228
|
-
|
|
229
|
-
Brand voice: Developer-first, direct, helpful, independent
|
|
230
|
-
Target audience: Developers building e-commerce, technical founders, agencies
|
|
231
|
-
Key differentiator: Free, instant, no signup, generates profiles (not just validates)
|
|
232
|
-
|
|
233
|
-
Avoid: Corporate jargon, "leverage", "utilize", "comprehensive solution"
|
|
234
|
-
Use: "Check", "fix", "validate", "generate", "your profile", "instant"
|
|
235
|
-
|
|
236
|
-
Colors: Blue (#2563eb), Green for success, Red for errors
|
|
237
|
-
Tagline: "Get ready for AI commerce"
|
|
238
|
-
```
|