@ucptools/validator 1.0.0 → 1.1.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/dist/auth/config.d.ts +20 -0
- package/dist/auth/config.d.ts.map +1 -0
- package/dist/auth/config.js +114 -0
- package/dist/auth/config.js.map +1 -0
- package/dist/auth/index.d.ts +5 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +17 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/middleware.d.ts +45 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +170 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/service.d.ts +80 -0
- package/dist/auth/service.d.ts.map +1 -0
- package/dist/auth/service.js +298 -0
- package/dist/auth/service.js.map +1 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +375 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/mock-server.d.ts +20 -0
- package/dist/cli/mock-server.d.ts.map +1 -0
- package/dist/cli/mock-server.js +261 -0
- package/dist/cli/mock-server.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 +17 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +80 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +3886 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +425 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/utils.d.ts +252 -0
- package/dist/db/utils.d.ts.map +1 -0
- package/dist/db/utils.js +295 -0
- package/dist/db/utils.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} +856 -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 +285 -0
- package/dist/feed-analyzer/types.d.ts.map +1 -0
- package/dist/feed-analyzer/types.js +175 -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/dist/lib/analytics.d.ts +337 -0
- package/dist/lib/analytics.d.ts.map +1 -0
- package/dist/lib/analytics.js +188 -0
- package/dist/lib/analytics.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 +669 -0
- package/dist/security/security-scanner.js.map +1 -0
- package/dist/security/types.d.ts +80 -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/analytics.d.ts +114 -0
- package/dist/services/analytics.d.ts.map +1 -0
- package/dist/services/analytics.js +862 -0
- package/dist/services/analytics.js.map +1 -0
- package/dist/services/badge.d.ts +31 -0
- package/dist/services/badge.d.ts.map +1 -0
- package/dist/services/badge.js +152 -0
- package/dist/services/badge.js.map +1 -0
- package/dist/services/cron.d.ts +125 -0
- package/dist/services/cron.d.ts.map +1 -0
- package/dist/services/cron.js +613 -0
- package/dist/services/cron.js.map +1 -0
- package/dist/services/directory.d.ts +106 -0
- package/dist/services/directory.d.ts.map +1 -0
- package/dist/services/directory.js +351 -0
- package/dist/services/directory.js.map +1 -0
- package/dist/services/email.d.ts +112 -0
- package/dist/services/email.d.ts.map +1 -0
- package/dist/services/email.js +772 -0
- package/dist/services/email.js.map +1 -0
- package/dist/services/hosted-profiles.d.ts +77 -0
- package/dist/services/hosted-profiles.d.ts.map +1 -0
- package/dist/services/hosted-profiles.js +433 -0
- package/dist/services/hosted-profiles.js.map +1 -0
- package/dist/services/latency.d.ts +67 -0
- package/dist/services/latency.d.ts.map +1 -0
- package/dist/services/latency.js +274 -0
- package/dist/services/latency.js.map +1 -0
- package/dist/services/manifest-compliance.d.ts +64 -0
- package/dist/services/manifest-compliance.d.ts.map +1 -0
- package/dist/services/manifest-compliance.js +271 -0
- package/dist/services/manifest-compliance.js.map +1 -0
- package/dist/services/monitoring-diff.d.ts +31 -0
- package/dist/services/monitoring-diff.d.ts.map +1 -0
- package/dist/services/monitoring-diff.js +189 -0
- package/dist/services/monitoring-diff.js.map +1 -0
- package/dist/services/notifications.d.ts +46 -0
- package/dist/services/notifications.d.ts.map +1 -0
- package/dist/services/notifications.js +88 -0
- package/dist/services/notifications.js.map +1 -0
- package/dist/services/stripe.d.ts +93 -0
- package/dist/services/stripe.d.ts.map +1 -0
- package/dist/services/stripe.js +490 -0
- package/dist/services/stripe.js.map +1 -0
- package/dist/services/validation-history.d.ts +99 -0
- package/dist/services/validation-history.d.ts.map +1 -0
- package/dist/services/validation-history.js +344 -0
- package/dist/services/validation-history.js.map +1 -0
- package/dist/services/validation-logging.d.ts +103 -0
- package/dist/services/validation-logging.d.ts.map +1 -0
- package/dist/services/validation-logging.js +210 -0
- package/dist/services/validation-logging.js.map +1 -0
- package/dist/services/validation.d.ts +119 -0
- package/dist/services/validation.d.ts.map +1 -0
- package/dist/services/validation.js +1185 -0
- package/dist/services/validation.js.map +1 -0
- package/dist/simulator/agent-simulator.d.ts +69 -0
- package/dist/simulator/agent-simulator.d.ts.map +1 -0
- package/dist/simulator/agent-simulator.js +870 -0
- 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} +171 -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/acp-validation.d.ts +87 -0
- package/dist/types/acp-validation.d.ts.map +1 -0
- package/dist/types/acp-validation.js +40 -0
- package/dist/types/acp-validation.js.map +1 -0
- package/dist/types/analytics.d.ts +182 -0
- package/dist/types/analytics.d.ts.map +1 -0
- package/dist/types/analytics.js +7 -0
- package/dist/types/analytics.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 +111 -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 +76 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +42 -0
- package/dist/types/validation.js.map +1 -0
- package/dist/validator/acp/index.d.ts +31 -0
- package/dist/validator/acp/index.d.ts.map +1 -0
- package/dist/validator/acp/index.js +574 -0
- package/dist/validator/acp/index.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 +19 -0
- package/dist/validator/rules-validator.d.ts.map +1 -0
- package/dist/validator/rules-validator.js +306 -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 +549 -0
- package/dist/validator/structural-validator.js.map +1 -0
- package/dist/validator/utils.d.ts +51 -0
- package/dist/validator/utils.d.ts.map +1 -0
- package/dist/validator/utils.js +132 -0
- package/dist/validator/utils.js.map +1 -0
- package/package.json +44 -12
- 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/simulator/agent-simulator.ts +0 -941
- 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/tsconfig.json +0 -20
- package/vercel.json +0 -34
- package/vitest.config.ts +0 -22
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Validator Utilities
|
|
4
|
+
* Helper functions for normalizing UCP profile data
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.normalizeCapabilities = normalizeCapabilities;
|
|
8
|
+
exports.normalizeServices = normalizeServices;
|
|
9
|
+
/**
|
|
10
|
+
* Capabilities can be in two formats:
|
|
11
|
+
* 1. Array format: [{ name, version, spec, schema, ... }, ...]
|
|
12
|
+
* 2. Object format (Shopify): { [name]: [{ version, spec, schema, ... }, ...] }
|
|
13
|
+
*
|
|
14
|
+
* This function normalizes both to our standard array format.
|
|
15
|
+
*/
|
|
16
|
+
function normalizeCapabilities(capabilities) {
|
|
17
|
+
if (!capabilities) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
// Already an array - validate it looks like capabilities and return
|
|
21
|
+
if (Array.isArray(capabilities)) {
|
|
22
|
+
// Check if array items look like UcpCapability (have name property)
|
|
23
|
+
if (capabilities.length === 0 || (capabilities[0] && 'name' in capabilities[0])) {
|
|
24
|
+
return capabilities;
|
|
25
|
+
}
|
|
26
|
+
// Array but not capabilities format - return empty
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
// Object format - convert to array
|
|
30
|
+
if (typeof capabilities === 'object') {
|
|
31
|
+
const normalized = [];
|
|
32
|
+
for (const [name, entries] of Object.entries(capabilities)) {
|
|
33
|
+
// Each capability name can have multiple version entries
|
|
34
|
+
if (Array.isArray(entries)) {
|
|
35
|
+
for (const entry of entries) {
|
|
36
|
+
if (entry && typeof entry === 'object') {
|
|
37
|
+
normalized.push({
|
|
38
|
+
name,
|
|
39
|
+
version: entry.version || '',
|
|
40
|
+
spec: entry.spec || '',
|
|
41
|
+
schema: entry.schema || '',
|
|
42
|
+
extends: entry.extends,
|
|
43
|
+
config: entry.config,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return normalized;
|
|
50
|
+
}
|
|
51
|
+
// Unknown format - return empty array
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Services can be in two formats:
|
|
56
|
+
* 1. Object format (our format): { [name]: { version, rest?, mcp?, ... } }
|
|
57
|
+
* 2. Array format (Shopify): { [name]: [{ version, transport, endpoint, ... }, ...] }
|
|
58
|
+
*
|
|
59
|
+
* This function normalizes services and returns individual service objects.
|
|
60
|
+
*/
|
|
61
|
+
function normalizeServices(services) {
|
|
62
|
+
if (!services) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
const normalized = [];
|
|
66
|
+
for (const [serviceName, serviceData] of Object.entries(services)) {
|
|
67
|
+
if (Array.isArray(serviceData)) {
|
|
68
|
+
// Array format - convert each entry to UcpService
|
|
69
|
+
for (const entry of serviceData) {
|
|
70
|
+
const service = convertServiceEntry(entry);
|
|
71
|
+
if (service) {
|
|
72
|
+
normalized.push({ name: serviceName, service });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (serviceData && typeof serviceData === 'object') {
|
|
77
|
+
// Already UcpService format
|
|
78
|
+
normalized.push({ name: serviceName, service: serviceData });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return normalized;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Convert a Shopify-style service entry to our UcpService format
|
|
85
|
+
*/
|
|
86
|
+
function convertServiceEntry(entry) {
|
|
87
|
+
if (!entry || typeof entry !== 'object') {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const service = {
|
|
91
|
+
version: entry.version || '',
|
|
92
|
+
spec: entry.spec || '',
|
|
93
|
+
};
|
|
94
|
+
// Handle transport-based entries (Shopify format)
|
|
95
|
+
if (entry.transport) {
|
|
96
|
+
switch (entry.transport) {
|
|
97
|
+
case 'rest':
|
|
98
|
+
service.rest = {
|
|
99
|
+
schema: entry.schema || '',
|
|
100
|
+
endpoint: entry.endpoint || '',
|
|
101
|
+
};
|
|
102
|
+
break;
|
|
103
|
+
case 'mcp':
|
|
104
|
+
service.mcp = {
|
|
105
|
+
schema: entry.schema || '',
|
|
106
|
+
endpoint: entry.endpoint || '',
|
|
107
|
+
};
|
|
108
|
+
break;
|
|
109
|
+
case 'a2a':
|
|
110
|
+
service.a2a = {
|
|
111
|
+
agentCard: entry.endpoint || '',
|
|
112
|
+
};
|
|
113
|
+
break;
|
|
114
|
+
case 'embedded':
|
|
115
|
+
service.embedded = {
|
|
116
|
+
schema: entry.schema || '',
|
|
117
|
+
};
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Handle direct transport properties (our format)
|
|
122
|
+
if (entry.rest)
|
|
123
|
+
service.rest = entry.rest;
|
|
124
|
+
if (entry.mcp)
|
|
125
|
+
service.mcp = entry.mcp;
|
|
126
|
+
if (entry.a2a)
|
|
127
|
+
service.a2a = entry.a2a;
|
|
128
|
+
if (entry.embedded)
|
|
129
|
+
service.embedded = entry.embedded;
|
|
130
|
+
return service;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/validator/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,58 +1,91 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ucptools/validator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Validate and generate UCP (Universal Commerce Protocol) Business Profiles",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"bin": {
|
|
8
|
-
"ucp-validate": "./dist/cli/index.js"
|
|
8
|
+
"ucp-validate": "./dist/cli/index.js",
|
|
9
|
+
"ucptools": "./dist/cli/index.js"
|
|
9
10
|
},
|
|
10
11
|
"scripts": {
|
|
11
|
-
"
|
|
12
|
-
"dev": "tsx watch src/api/server.ts",
|
|
13
|
-
"
|
|
12
|
+
"dev": "next dev -p 3001",
|
|
13
|
+
"dev:api": "tsx watch --env-file=.env.local src/api/server.ts",
|
|
14
|
+
"build": "next build && tsc -p tsconfig.api.json",
|
|
15
|
+
"build:api": "tsc -p tsconfig.api.json",
|
|
16
|
+
"start": "next start",
|
|
17
|
+
"start:api": "node dist/api/server.js",
|
|
14
18
|
"test": "vitest",
|
|
15
|
-
"lint": "eslint src --ext .ts",
|
|
19
|
+
"lint": "next lint && eslint src --ext .ts",
|
|
20
|
+
"typecheck": "tsc --noEmit --pretty && node -e \"console.log('\\n✓ TypeScript check completed successfully')\"",
|
|
16
21
|
"validate": "tsx src/cli/index.ts",
|
|
17
22
|
"generate": "tsx src/cli/generate.ts",
|
|
18
23
|
"db:generate": "drizzle-kit generate",
|
|
19
|
-
"db:migrate": "
|
|
24
|
+
"db:migrate": "node scripts/migrate.js",
|
|
20
25
|
"db:push": "drizzle-kit push",
|
|
21
|
-
"db:studio": "drizzle-kit studio"
|
|
26
|
+
"db:studio": "drizzle-kit studio",
|
|
27
|
+
"analyze:competition": "tsx scripts/competition-analysis.ts"
|
|
22
28
|
},
|
|
23
29
|
"keywords": [
|
|
24
30
|
"ucp",
|
|
25
31
|
"universal-commerce-protocol",
|
|
26
32
|
"profile-generator",
|
|
27
|
-
"validator"
|
|
33
|
+
"validator",
|
|
34
|
+
"ucp-mock-server",
|
|
35
|
+
"ucp-simulator",
|
|
36
|
+
"ucp-cli",
|
|
37
|
+
"ucp-testing",
|
|
38
|
+
"ai-commerce",
|
|
39
|
+
"agentic-commerce",
|
|
40
|
+
"google-shopping",
|
|
41
|
+
"shopify-ucp"
|
|
28
42
|
],
|
|
29
43
|
"author": "UCP.tools",
|
|
30
44
|
"license": "MIT",
|
|
31
45
|
"dependencies": {
|
|
32
|
-
"@
|
|
46
|
+
"@auth/core": "^0.41.1",
|
|
47
|
+
"@auth/drizzle-adapter": "^1.11.1",
|
|
48
|
+
"@heroicons/react": "^2.2.0",
|
|
33
49
|
"@ucp-js/sdk": "^0.1.0",
|
|
34
50
|
"ajv": "^8.17.1",
|
|
35
51
|
"ajv-formats": "^3.0.1",
|
|
52
|
+
"bcryptjs": "^3.0.3",
|
|
36
53
|
"chalk": "^5.3.0",
|
|
37
54
|
"commander": "^12.1.0",
|
|
55
|
+
"cookie-parser": "^1.4.7",
|
|
38
56
|
"drizzle-orm": "^0.45.1",
|
|
39
57
|
"express": "^4.21.0",
|
|
58
|
+
"google-auth-library": "^10.5.0",
|
|
40
59
|
"jose": "^5.9.6",
|
|
60
|
+
"jspdf": "^4.0.0",
|
|
61
|
+
"jspdf-autotable": "^5.0.7",
|
|
41
62
|
"nanoid": "^5.0.7",
|
|
63
|
+
"next": "^16.1.4",
|
|
42
64
|
"pg": "^8.13.0",
|
|
43
65
|
"pino": "^9.5.0",
|
|
44
66
|
"pino-pretty": "^11.3.0",
|
|
67
|
+
"playwright": "^1.58.0",
|
|
68
|
+
"posthog-js": "^1.205.0",
|
|
69
|
+
"puppeteer": "^24.36.1",
|
|
70
|
+
"react": "^19.2.3",
|
|
71
|
+
"react-dom": "^19.2.3",
|
|
72
|
+
"stripe": "^20.2.0",
|
|
45
73
|
"zod": "^3.23.8"
|
|
46
74
|
},
|
|
47
75
|
"devDependencies": {
|
|
76
|
+
"@types/bcryptjs": "^2.4.6",
|
|
77
|
+
"@types/cookie-parser": "^1.4.10",
|
|
48
78
|
"@types/express": "^5.0.0",
|
|
49
79
|
"@types/node": "^22.9.0",
|
|
50
80
|
"@types/pg": "^8.11.10",
|
|
81
|
+
"@types/react": "19.2.9",
|
|
82
|
+
"@types/supertest": "^6.0.3",
|
|
51
83
|
"@vercel/node": "^5.5.20",
|
|
52
84
|
"dotenv": "^17.2.3",
|
|
53
85
|
"drizzle-kit": "^0.31.8",
|
|
54
86
|
"png-to-ico": "^3.0.1",
|
|
55
87
|
"sharp": "^0.34.5",
|
|
88
|
+
"supertest": "^7.2.2",
|
|
56
89
|
"tsx": "^4.19.2",
|
|
57
90
|
"typescript": "^5.6.3",
|
|
58
91
|
"vitest": "^4.0.17"
|
|
@@ -60,8 +93,7 @@
|
|
|
60
93
|
"overrides": {
|
|
61
94
|
"diff": "^8.0.3",
|
|
62
95
|
"undici": "^7.0.0",
|
|
63
|
-
"esbuild": "^0.25.0"
|
|
64
|
-
"path-to-regexp": "^8.0.0"
|
|
96
|
+
"esbuild": "^0.25.0"
|
|
65
97
|
},
|
|
66
98
|
"engines": {
|
|
67
99
|
"node": ">=20.0.0"
|
package/CLAUDE.md
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
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/api/analyze-feed.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
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
|
-
}
|