@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
package/src/db/schema.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
pgTable,
|
|
3
|
-
uuid,
|
|
4
|
-
varchar,
|
|
5
|
-
text,
|
|
6
|
-
integer,
|
|
7
|
-
timestamp,
|
|
8
|
-
boolean,
|
|
9
|
-
index,
|
|
10
|
-
decimal,
|
|
11
|
-
} from 'drizzle-orm/pg-core';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Merchants table - stores UCP-enabled merchant directory entries
|
|
15
|
-
*/
|
|
16
|
-
export const merchants = pgTable(
|
|
17
|
-
'merchants',
|
|
18
|
-
{
|
|
19
|
-
id: uuid('id').primaryKey().defaultRandom(),
|
|
20
|
-
// The merchant's primary domain (e.g., "example.com")
|
|
21
|
-
domain: varchar('domain', { length: 255 }).notNull().unique(),
|
|
22
|
-
// Display name for the merchant
|
|
23
|
-
displayName: varchar('display_name', { length: 255 }).notNull(),
|
|
24
|
-
// Optional description
|
|
25
|
-
description: text('description'),
|
|
26
|
-
// Logo URL
|
|
27
|
-
logoUrl: varchar('logo_url', { length: 512 }),
|
|
28
|
-
// Website URL (full URL including protocol)
|
|
29
|
-
websiteUrl: varchar('website_url', { length: 512 }),
|
|
30
|
-
// Category (e-commerce, saas, marketplace, etc.)
|
|
31
|
-
category: varchar('category', { length: 100 }),
|
|
32
|
-
// Country code (ISO 3166-1 alpha-2)
|
|
33
|
-
countryCode: varchar('country_code', { length: 2 }),
|
|
34
|
-
// UCP readiness score (0-100)
|
|
35
|
-
ucpScore: integer('ucp_score'),
|
|
36
|
-
// UCP grade (A, B, C, D, F)
|
|
37
|
-
ucpGrade: varchar('ucp_grade', { length: 2 }),
|
|
38
|
-
// Supported transports (comma-separated: REST, MCP, A2A, Embedded)
|
|
39
|
-
transports: varchar('transports', { length: 255 }),
|
|
40
|
-
// Whether the merchant has opted into the directory
|
|
41
|
-
isPublic: boolean('is_public').default(true).notNull(),
|
|
42
|
-
// Whether the merchant has been verified
|
|
43
|
-
isVerified: boolean('is_verified').default(false).notNull(),
|
|
44
|
-
// Last validation timestamp
|
|
45
|
-
lastValidatedAt: timestamp('last_validated_at'),
|
|
46
|
-
// Record timestamps
|
|
47
|
-
createdAt: timestamp('created_at').defaultNow().notNull(),
|
|
48
|
-
updatedAt: timestamp('updated_at').defaultNow().notNull(),
|
|
49
|
-
},
|
|
50
|
-
(table) => [
|
|
51
|
-
index('idx_merchants_domain').on(table.domain),
|
|
52
|
-
index('idx_merchants_category').on(table.category),
|
|
53
|
-
index('idx_merchants_country').on(table.countryCode),
|
|
54
|
-
index('idx_merchants_score').on(table.ucpScore),
|
|
55
|
-
index('idx_merchants_public').on(table.isPublic),
|
|
56
|
-
]
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Benchmark stats table - stores aggregate validation statistics
|
|
61
|
-
* (migrated from setup script)
|
|
62
|
-
*/
|
|
63
|
-
export const benchmarkStats = pgTable('benchmark_stats', {
|
|
64
|
-
id: integer('id').primaryKey().generatedAlwaysAsIdentity(),
|
|
65
|
-
scoreBucket: integer('score_bucket').notNull().unique(),
|
|
66
|
-
count: integer('count').default(0).notNull(),
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Benchmark summary table - quick aggregate stats
|
|
71
|
-
* (migrated from setup script)
|
|
72
|
-
*/
|
|
73
|
-
export const benchmarkSummary = pgTable('benchmark_summary', {
|
|
74
|
-
id: integer('id').primaryKey().default(1),
|
|
75
|
-
totalValidations: integer('total_validations').default(0).notNull(),
|
|
76
|
-
avgScore: decimal('avg_score', { precision: 5, scale: 2 }).default('0'),
|
|
77
|
-
updatedAt: timestamp('updated_at').defaultNow().notNull(),
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// Type exports for use in application code
|
|
81
|
-
export type Merchant = typeof merchants.$inferSelect;
|
|
82
|
-
export type NewMerchant = typeof merchants.$inferInsert;
|
|
83
|
-
export type BenchmarkStat = typeof benchmarkStats.$inferSelect;
|
|
84
|
-
export type BenchmarkSummary = typeof benchmarkSummary.$inferSelect;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Product Feed Quality Analyzer Module
|
|
3
|
-
* Deep analysis of product data quality for AI agent visibility
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
analyzeProductFeed,
|
|
8
|
-
analyzeProductFeedFromHtml,
|
|
9
|
-
analyzeProduct,
|
|
10
|
-
extractProductsFromHtml,
|
|
11
|
-
validateGtin,
|
|
12
|
-
} from './feed-analyzer.js';
|
|
13
|
-
|
|
14
|
-
export type {
|
|
15
|
-
ProductData,
|
|
16
|
-
ProductOffer,
|
|
17
|
-
ProductAnalysis,
|
|
18
|
-
QualityCheck,
|
|
19
|
-
FeedAnalysisResult,
|
|
20
|
-
FeedAnalysisInput,
|
|
21
|
-
CategoryScores,
|
|
22
|
-
Recommendation,
|
|
23
|
-
FeedSummary,
|
|
24
|
-
GtinValidation,
|
|
25
|
-
IssueSeverity,
|
|
26
|
-
CheckCategory,
|
|
27
|
-
} from './types.js';
|
|
28
|
-
|
|
29
|
-
export {
|
|
30
|
-
QUALITY_CHECKS,
|
|
31
|
-
VALID_AVAILABILITY_VALUES,
|
|
32
|
-
CATEGORY_WEIGHTS,
|
|
33
|
-
GRADE_THRESHOLDS,
|
|
34
|
-
} from './types.js';
|
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Product Feed Quality Analyzer Types
|
|
3
|
-
* Deep analysis of product data quality for AI agent visibility
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Severity levels for feed issues
|
|
8
|
-
*/
|
|
9
|
-
export type IssueSeverity = 'critical' | 'warning' | 'info';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Categories of feed quality checks
|
|
13
|
-
*/
|
|
14
|
-
export type CheckCategory =
|
|
15
|
-
| 'completeness'
|
|
16
|
-
| 'identifiers'
|
|
17
|
-
| 'images'
|
|
18
|
-
| 'pricing'
|
|
19
|
-
| 'descriptions'
|
|
20
|
-
| 'categories'
|
|
21
|
-
| 'availability';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Individual product data from Schema.org JSON-LD
|
|
25
|
-
*/
|
|
26
|
-
export interface ProductData {
|
|
27
|
-
name?: string;
|
|
28
|
-
description?: string;
|
|
29
|
-
sku?: string;
|
|
30
|
-
gtin?: string;
|
|
31
|
-
gtin8?: string;
|
|
32
|
-
gtin12?: string;
|
|
33
|
-
gtin13?: string;
|
|
34
|
-
gtin14?: string;
|
|
35
|
-
mpn?: string;
|
|
36
|
-
brand?: string | { name?: string };
|
|
37
|
-
image?: string | string[] | { url?: string }[];
|
|
38
|
-
offers?: ProductOffer | ProductOffer[];
|
|
39
|
-
category?: string;
|
|
40
|
-
color?: string;
|
|
41
|
-
size?: string;
|
|
42
|
-
material?: string;
|
|
43
|
-
weight?: string | { value?: number; unitCode?: string };
|
|
44
|
-
aggregateRating?: {
|
|
45
|
-
ratingValue?: number;
|
|
46
|
-
reviewCount?: number;
|
|
47
|
-
ratingCount?: number;
|
|
48
|
-
};
|
|
49
|
-
review?: unknown[];
|
|
50
|
-
url?: string;
|
|
51
|
-
'@type'?: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Product offer/pricing data
|
|
56
|
-
*/
|
|
57
|
-
export interface ProductOffer {
|
|
58
|
-
'@type'?: string;
|
|
59
|
-
price?: number | string;
|
|
60
|
-
priceCurrency?: string;
|
|
61
|
-
availability?: string;
|
|
62
|
-
url?: string;
|
|
63
|
-
seller?: { name?: string };
|
|
64
|
-
priceValidUntil?: string;
|
|
65
|
-
itemCondition?: string;
|
|
66
|
-
shippingDetails?: unknown;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Individual quality check result
|
|
71
|
-
*/
|
|
72
|
-
export interface QualityCheck {
|
|
73
|
-
id: string;
|
|
74
|
-
name: string;
|
|
75
|
-
category: CheckCategory;
|
|
76
|
-
passed: boolean;
|
|
77
|
-
severity: IssueSeverity;
|
|
78
|
-
message: string;
|
|
79
|
-
details?: string;
|
|
80
|
-
recommendation?: string;
|
|
81
|
-
affectedProducts?: string[];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Product-level analysis result
|
|
86
|
-
*/
|
|
87
|
-
export interface ProductAnalysis {
|
|
88
|
-
name: string;
|
|
89
|
-
url?: string;
|
|
90
|
-
sku?: string;
|
|
91
|
-
score: number;
|
|
92
|
-
issues: QualityCheck[];
|
|
93
|
-
attributes: {
|
|
94
|
-
hasName: boolean;
|
|
95
|
-
hasDescription: boolean;
|
|
96
|
-
hasSku: boolean;
|
|
97
|
-
hasGtin: boolean;
|
|
98
|
-
hasBrand: boolean;
|
|
99
|
-
hasImage: boolean;
|
|
100
|
-
hasPrice: boolean;
|
|
101
|
-
hasAvailability: boolean;
|
|
102
|
-
hasCategory: boolean;
|
|
103
|
-
descriptionLength: number;
|
|
104
|
-
imageCount: number;
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Category scores breakdown
|
|
110
|
-
*/
|
|
111
|
-
export interface CategoryScores {
|
|
112
|
-
completeness: number;
|
|
113
|
-
identifiers: number;
|
|
114
|
-
images: number;
|
|
115
|
-
pricing: number;
|
|
116
|
-
descriptions: number;
|
|
117
|
-
categories: number;
|
|
118
|
-
availability: number;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Overall feed analysis result
|
|
123
|
-
*/
|
|
124
|
-
export interface FeedAnalysisResult {
|
|
125
|
-
url: string;
|
|
126
|
-
analyzedAt: string;
|
|
127
|
-
productsFound: number;
|
|
128
|
-
productsAnalyzed: number;
|
|
129
|
-
overallScore: number;
|
|
130
|
-
agentVisibilityScore: number;
|
|
131
|
-
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
132
|
-
categoryScores: CategoryScores;
|
|
133
|
-
issues: QualityCheck[];
|
|
134
|
-
topIssues: QualityCheck[];
|
|
135
|
-
products: ProductAnalysis[];
|
|
136
|
-
recommendations: Recommendation[];
|
|
137
|
-
summary: FeedSummary;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Recommendation for improving feed quality
|
|
142
|
-
*/
|
|
143
|
-
export interface Recommendation {
|
|
144
|
-
priority: 'high' | 'medium' | 'low';
|
|
145
|
-
category: CheckCategory;
|
|
146
|
-
title: string;
|
|
147
|
-
description: string;
|
|
148
|
-
impact: string;
|
|
149
|
-
affectedCount: number;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Summary statistics for the feed
|
|
154
|
-
*/
|
|
155
|
-
export interface FeedSummary {
|
|
156
|
-
totalProducts: number;
|
|
157
|
-
withName: number;
|
|
158
|
-
withDescription: number;
|
|
159
|
-
withSku: number;
|
|
160
|
-
withGtin: number;
|
|
161
|
-
withBrand: number;
|
|
162
|
-
withImages: number;
|
|
163
|
-
withPrice: number;
|
|
164
|
-
withAvailability: number;
|
|
165
|
-
withCategory: number;
|
|
166
|
-
averageDescriptionLength: number;
|
|
167
|
-
averageImageCount: number;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Input options for feed analysis
|
|
172
|
-
*/
|
|
173
|
-
export interface FeedAnalysisInput {
|
|
174
|
-
url: string;
|
|
175
|
-
maxProducts?: number;
|
|
176
|
-
includeProductDetails?: boolean;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* GTIN validation result
|
|
181
|
-
*/
|
|
182
|
-
export interface GtinValidation {
|
|
183
|
-
isValid: boolean;
|
|
184
|
-
type?: 'GTIN-8' | 'GTIN-12' | 'GTIN-13' | 'GTIN-14' | 'UPC' | 'EAN';
|
|
185
|
-
error?: string;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Quality check definitions
|
|
190
|
-
*/
|
|
191
|
-
export const QUALITY_CHECKS: Record<string, {
|
|
192
|
-
name: string;
|
|
193
|
-
category: CheckCategory;
|
|
194
|
-
severity: IssueSeverity;
|
|
195
|
-
description: string;
|
|
196
|
-
}> = {
|
|
197
|
-
// Completeness checks
|
|
198
|
-
'missing-name': {
|
|
199
|
-
name: 'Missing Product Name',
|
|
200
|
-
category: 'completeness',
|
|
201
|
-
severity: 'critical',
|
|
202
|
-
description: 'Product name is required for AI agents to identify products',
|
|
203
|
-
},
|
|
204
|
-
'missing-description': {
|
|
205
|
-
name: 'Missing Description',
|
|
206
|
-
category: 'completeness',
|
|
207
|
-
severity: 'warning',
|
|
208
|
-
description: 'Product description helps AI agents understand and recommend products',
|
|
209
|
-
},
|
|
210
|
-
'short-description': {
|
|
211
|
-
name: 'Short Description',
|
|
212
|
-
category: 'descriptions',
|
|
213
|
-
severity: 'info',
|
|
214
|
-
description: 'Longer descriptions provide better context for AI agents',
|
|
215
|
-
},
|
|
216
|
-
'missing-brand': {
|
|
217
|
-
name: 'Missing Brand',
|
|
218
|
-
category: 'completeness',
|
|
219
|
-
severity: 'warning',
|
|
220
|
-
description: 'Brand information helps with product identification and search',
|
|
221
|
-
},
|
|
222
|
-
|
|
223
|
-
// Identifier checks
|
|
224
|
-
'missing-sku': {
|
|
225
|
-
name: 'Missing SKU',
|
|
226
|
-
category: 'identifiers',
|
|
227
|
-
severity: 'warning',
|
|
228
|
-
description: 'SKU helps uniquely identify products in your catalog',
|
|
229
|
-
},
|
|
230
|
-
'missing-gtin': {
|
|
231
|
-
name: 'Missing GTIN/UPC/EAN',
|
|
232
|
-
category: 'identifiers',
|
|
233
|
-
severity: 'warning',
|
|
234
|
-
description: 'Global identifiers enable cross-platform product matching',
|
|
235
|
-
},
|
|
236
|
-
'invalid-gtin': {
|
|
237
|
-
name: 'Invalid GTIN Format',
|
|
238
|
-
category: 'identifiers',
|
|
239
|
-
severity: 'critical',
|
|
240
|
-
description: 'GTIN has invalid format or check digit',
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
// Image checks
|
|
244
|
-
'missing-image': {
|
|
245
|
-
name: 'Missing Product Image',
|
|
246
|
-
category: 'images',
|
|
247
|
-
severity: 'critical',
|
|
248
|
-
description: 'Product images are essential for AI shopping experiences',
|
|
249
|
-
},
|
|
250
|
-
'single-image': {
|
|
251
|
-
name: 'Single Image Only',
|
|
252
|
-
category: 'images',
|
|
253
|
-
severity: 'info',
|
|
254
|
-
description: 'Multiple images improve product presentation',
|
|
255
|
-
},
|
|
256
|
-
'missing-image-alt': {
|
|
257
|
-
name: 'Missing Image Alt Text',
|
|
258
|
-
category: 'images',
|
|
259
|
-
severity: 'info',
|
|
260
|
-
description: 'Alt text helps with accessibility and SEO',
|
|
261
|
-
},
|
|
262
|
-
|
|
263
|
-
// Pricing checks
|
|
264
|
-
'missing-price': {
|
|
265
|
-
name: 'Missing Price',
|
|
266
|
-
category: 'pricing',
|
|
267
|
-
severity: 'critical',
|
|
268
|
-
description: 'Price is required for AI agents to complete purchases',
|
|
269
|
-
},
|
|
270
|
-
'missing-currency': {
|
|
271
|
-
name: 'Missing Currency',
|
|
272
|
-
category: 'pricing',
|
|
273
|
-
severity: 'warning',
|
|
274
|
-
description: 'Currency must be specified for international commerce',
|
|
275
|
-
},
|
|
276
|
-
'invalid-price': {
|
|
277
|
-
name: 'Invalid Price Format',
|
|
278
|
-
category: 'pricing',
|
|
279
|
-
severity: 'critical',
|
|
280
|
-
description: 'Price must be a valid number',
|
|
281
|
-
},
|
|
282
|
-
|
|
283
|
-
// Availability checks
|
|
284
|
-
'missing-availability': {
|
|
285
|
-
name: 'Missing Availability',
|
|
286
|
-
category: 'availability',
|
|
287
|
-
severity: 'warning',
|
|
288
|
-
description: 'Availability status helps AI agents make purchase decisions',
|
|
289
|
-
},
|
|
290
|
-
'invalid-availability': {
|
|
291
|
-
name: 'Invalid Availability Value',
|
|
292
|
-
category: 'availability',
|
|
293
|
-
severity: 'warning',
|
|
294
|
-
description: 'Availability should use Schema.org ItemAvailability values',
|
|
295
|
-
},
|
|
296
|
-
|
|
297
|
-
// Category checks
|
|
298
|
-
'missing-category': {
|
|
299
|
-
name: 'Missing Category',
|
|
300
|
-
category: 'categories',
|
|
301
|
-
severity: 'info',
|
|
302
|
-
description: 'Product categorization improves discoverability',
|
|
303
|
-
},
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Valid Schema.org availability values
|
|
308
|
-
*/
|
|
309
|
-
export const VALID_AVAILABILITY_VALUES = [
|
|
310
|
-
'https://schema.org/InStock',
|
|
311
|
-
'https://schema.org/OutOfStock',
|
|
312
|
-
'https://schema.org/PreOrder',
|
|
313
|
-
'https://schema.org/PreSale',
|
|
314
|
-
'https://schema.org/SoldOut',
|
|
315
|
-
'https://schema.org/InStoreOnly',
|
|
316
|
-
'https://schema.org/OnlineOnly',
|
|
317
|
-
'https://schema.org/LimitedAvailability',
|
|
318
|
-
'https://schema.org/Discontinued',
|
|
319
|
-
'https://schema.org/BackOrder',
|
|
320
|
-
'InStock',
|
|
321
|
-
'OutOfStock',
|
|
322
|
-
'PreOrder',
|
|
323
|
-
'PreSale',
|
|
324
|
-
'SoldOut',
|
|
325
|
-
'InStoreOnly',
|
|
326
|
-
'OnlineOnly',
|
|
327
|
-
'LimitedAvailability',
|
|
328
|
-
'Discontinued',
|
|
329
|
-
'BackOrder',
|
|
330
|
-
];
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Scoring weights for different categories
|
|
334
|
-
*/
|
|
335
|
-
export const CATEGORY_WEIGHTS: Record<CheckCategory, number> = {
|
|
336
|
-
completeness: 25,
|
|
337
|
-
identifiers: 15,
|
|
338
|
-
images: 20,
|
|
339
|
-
pricing: 20,
|
|
340
|
-
descriptions: 10,
|
|
341
|
-
categories: 5,
|
|
342
|
-
availability: 5,
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Grade thresholds (aligned with all other scoring models)
|
|
347
|
-
*/
|
|
348
|
-
export const GRADE_THRESHOLDS = {
|
|
349
|
-
A: 90,
|
|
350
|
-
B: 80,
|
|
351
|
-
C: 70,
|
|
352
|
-
D: 60,
|
|
353
|
-
F: 0,
|
|
354
|
-
};
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Signing Key Generator for UCP Webhook Signing
|
|
3
|
-
* Generates EC or RSA key pairs in JWK format
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import * as jose from 'jose';
|
|
7
|
-
import { nanoid } from 'nanoid';
|
|
8
|
-
import type { JwkKey } from '../types/ucp-profile.js';
|
|
9
|
-
|
|
10
|
-
export type KeyAlgorithm = 'ES256' | 'RS256';
|
|
11
|
-
|
|
12
|
-
export interface KeyPairResult {
|
|
13
|
-
publicKey: JwkKey;
|
|
14
|
-
privateKey: string; // PEM format for merchant storage
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Generate a new signing key pair
|
|
19
|
-
*/
|
|
20
|
-
export async function generateSigningKeyPair(
|
|
21
|
-
algorithm: KeyAlgorithm = 'ES256'
|
|
22
|
-
): Promise<KeyPairResult> {
|
|
23
|
-
const keyId = `ucp-${nanoid(12)}`;
|
|
24
|
-
|
|
25
|
-
if (algorithm === 'ES256') {
|
|
26
|
-
return generateECKeyPair(keyId);
|
|
27
|
-
} else {
|
|
28
|
-
return generateRSAKeyPair(keyId);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Generate EC (P-256) key pair
|
|
34
|
-
*/
|
|
35
|
-
async function generateECKeyPair(keyId: string): Promise<KeyPairResult> {
|
|
36
|
-
const { publicKey, privateKey } = await jose.generateKeyPair('ES256', {
|
|
37
|
-
extractable: true,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Export public key as JWK
|
|
41
|
-
const publicJwk = await jose.exportJWK(publicKey);
|
|
42
|
-
|
|
43
|
-
// Export private key as PEM
|
|
44
|
-
const privatePem = await jose.exportPKCS8(privateKey);
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
publicKey: {
|
|
48
|
-
kty: 'EC',
|
|
49
|
-
kid: keyId,
|
|
50
|
-
use: 'sig',
|
|
51
|
-
alg: 'ES256',
|
|
52
|
-
crv: publicJwk.crv as string,
|
|
53
|
-
x: publicJwk.x as string,
|
|
54
|
-
y: publicJwk.y as string,
|
|
55
|
-
},
|
|
56
|
-
privateKey: privatePem,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Generate RSA (2048-bit) key pair
|
|
62
|
-
*/
|
|
63
|
-
async function generateRSAKeyPair(keyId: string): Promise<KeyPairResult> {
|
|
64
|
-
const { publicKey, privateKey } = await jose.generateKeyPair('RS256', {
|
|
65
|
-
extractable: true,
|
|
66
|
-
modulusLength: 2048,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// Export public key as JWK
|
|
70
|
-
const publicJwk = await jose.exportJWK(publicKey);
|
|
71
|
-
|
|
72
|
-
// Export private key as PEM
|
|
73
|
-
const privatePem = await jose.exportPKCS8(privateKey);
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
publicKey: {
|
|
77
|
-
kty: 'RSA',
|
|
78
|
-
kid: keyId,
|
|
79
|
-
use: 'sig',
|
|
80
|
-
alg: 'RS256',
|
|
81
|
-
n: publicJwk.n as string,
|
|
82
|
-
e: publicJwk.e as string,
|
|
83
|
-
},
|
|
84
|
-
privateKey: privatePem,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Validate a JWK public key structure
|
|
90
|
-
*/
|
|
91
|
-
export function validatePublicKey(key: JwkKey): string[] {
|
|
92
|
-
const errors: string[] = [];
|
|
93
|
-
|
|
94
|
-
if (!key.kty) {
|
|
95
|
-
errors.push('Missing required field: kty');
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (!key.kid) {
|
|
99
|
-
errors.push('Missing required field: kid');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (key.kty === 'EC') {
|
|
103
|
-
if (!key.crv) errors.push('EC key missing curve (crv)');
|
|
104
|
-
if (!key.x) errors.push('EC key missing x coordinate');
|
|
105
|
-
if (!key.y) errors.push('EC key missing y coordinate');
|
|
106
|
-
if (key.crv && !['P-256', 'P-384', 'P-521'].includes(key.crv)) {
|
|
107
|
-
errors.push(`Unsupported EC curve: ${key.crv}`);
|
|
108
|
-
}
|
|
109
|
-
} else if (key.kty === 'RSA') {
|
|
110
|
-
if (!key.n) errors.push('RSA key missing modulus (n)');
|
|
111
|
-
if (!key.e) errors.push('RSA key missing exponent (e)');
|
|
112
|
-
} else if (key.kty) {
|
|
113
|
-
errors.push(`Unsupported key type: ${key.kty}`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return errors;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Import and validate a public key from JWK
|
|
121
|
-
*/
|
|
122
|
-
export async function importPublicKey(jwk: JwkKey): Promise<jose.KeyLike | Uint8Array> {
|
|
123
|
-
return jose.importJWK(jwk as jose.JWK, jwk.alg);
|
|
124
|
-
}
|