@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.
Files changed (330) hide show
  1. package/dist/auth/config.d.ts +20 -0
  2. package/dist/auth/config.d.ts.map +1 -0
  3. package/dist/auth/config.js +114 -0
  4. package/dist/auth/config.js.map +1 -0
  5. package/dist/auth/index.d.ts +5 -0
  6. package/dist/auth/index.d.ts.map +1 -0
  7. package/dist/auth/index.js +17 -0
  8. package/dist/auth/index.js.map +1 -0
  9. package/dist/auth/middleware.d.ts +45 -0
  10. package/dist/auth/middleware.d.ts.map +1 -0
  11. package/dist/auth/middleware.js +170 -0
  12. package/dist/auth/middleware.js.map +1 -0
  13. package/dist/auth/service.d.ts +80 -0
  14. package/dist/auth/service.d.ts.map +1 -0
  15. package/dist/auth/service.js +298 -0
  16. package/dist/auth/service.js.map +1 -0
  17. package/dist/cli/index.d.ts +6 -0
  18. package/dist/cli/index.d.ts.map +1 -0
  19. package/dist/cli/index.js +375 -0
  20. package/dist/cli/index.js.map +1 -0
  21. package/dist/cli/mock-server.d.ts +20 -0
  22. package/dist/cli/mock-server.d.ts.map +1 -0
  23. package/dist/cli/mock-server.js +261 -0
  24. package/dist/cli/mock-server.js.map +1 -0
  25. package/dist/compliance/compliance-generator.d.ts +34 -0
  26. package/dist/compliance/compliance-generator.d.ts.map +1 -0
  27. package/dist/compliance/compliance-generator.js +320 -0
  28. package/dist/compliance/compliance-generator.js.map +1 -0
  29. package/dist/compliance/index.d.ts +8 -0
  30. package/dist/compliance/index.d.ts.map +1 -0
  31. package/dist/compliance/index.js +17 -0
  32. package/dist/compliance/index.js.map +1 -0
  33. package/dist/compliance/templates.d.ts +34 -0
  34. package/dist/compliance/templates.d.ts.map +1 -0
  35. package/{src/compliance/templates.ts → dist/compliance/templates.js} +117 -155
  36. package/dist/compliance/templates.js.map +1 -0
  37. package/dist/compliance/types.d.ts +64 -0
  38. package/dist/compliance/types.d.ts.map +1 -0
  39. package/dist/compliance/types.js +64 -0
  40. package/dist/compliance/types.js.map +1 -0
  41. package/dist/db/index.d.ts +17 -0
  42. package/dist/db/index.d.ts.map +1 -0
  43. package/dist/db/index.js +80 -0
  44. package/dist/db/index.js.map +1 -0
  45. package/dist/db/schema.d.ts +3886 -0
  46. package/dist/db/schema.d.ts.map +1 -0
  47. package/dist/db/schema.js +425 -0
  48. package/dist/db/schema.js.map +1 -0
  49. package/dist/db/utils.d.ts +252 -0
  50. package/dist/db/utils.d.ts.map +1 -0
  51. package/dist/db/utils.js +295 -0
  52. package/dist/db/utils.js.map +1 -0
  53. package/dist/feed-analyzer/feed-analyzer.d.ts +26 -0
  54. package/dist/feed-analyzer/feed-analyzer.d.ts.map +1 -0
  55. package/{src/feed-analyzer/feed-analyzer.ts → dist/feed-analyzer/feed-analyzer.js} +856 -726
  56. package/dist/feed-analyzer/feed-analyzer.js.map +1 -0
  57. package/dist/feed-analyzer/index.d.ts +8 -0
  58. package/dist/feed-analyzer/index.d.ts.map +1 -0
  59. package/dist/feed-analyzer/index.js +19 -0
  60. package/dist/feed-analyzer/index.js.map +1 -0
  61. package/dist/feed-analyzer/types.d.ts +285 -0
  62. package/dist/feed-analyzer/types.d.ts.map +1 -0
  63. package/dist/feed-analyzer/types.js +175 -0
  64. package/dist/feed-analyzer/types.js.map +1 -0
  65. package/{src/generator/index.ts → dist/generator/index.d.ts} +1 -1
  66. package/dist/generator/index.d.ts.map +1 -0
  67. package/dist/generator/index.js +13 -0
  68. package/dist/generator/index.js.map +1 -0
  69. package/dist/generator/key-generator.d.ts +24 -0
  70. package/dist/generator/key-generator.d.ts.map +1 -0
  71. package/dist/generator/key-generator.js +144 -0
  72. package/dist/generator/key-generator.js.map +1 -0
  73. package/dist/generator/profile-builder.d.ts +15 -0
  74. package/dist/generator/profile-builder.d.ts.map +1 -0
  75. package/dist/generator/profile-builder.js +338 -0
  76. package/dist/generator/profile-builder.js.map +1 -0
  77. package/dist/hosting/artifacts-generator.d.ts +10 -0
  78. package/dist/hosting/artifacts-generator.d.ts.map +1 -0
  79. package/{src/hosting/artifacts-generator.ts → dist/hosting/artifacts-generator.js} +191 -241
  80. package/dist/hosting/artifacts-generator.js.map +1 -0
  81. package/{src/hosting/index.ts → dist/hosting/index.d.ts} +1 -1
  82. package/dist/hosting/index.d.ts.map +1 -0
  83. package/dist/hosting/index.js +10 -0
  84. package/dist/hosting/index.js.map +1 -0
  85. package/dist/index.d.ts +18 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +78 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/lib/analytics.d.ts +337 -0
  90. package/dist/lib/analytics.d.ts.map +1 -0
  91. package/dist/lib/analytics.js +188 -0
  92. package/dist/lib/analytics.js.map +1 -0
  93. package/{src/security/index.ts → dist/security/index.d.ts} +8 -15
  94. package/dist/security/index.d.ts.map +1 -0
  95. package/dist/security/index.js +12 -0
  96. package/dist/security/index.js.map +1 -0
  97. package/dist/security/security-scanner.d.ts +10 -0
  98. package/dist/security/security-scanner.d.ts.map +1 -0
  99. package/dist/security/security-scanner.js +669 -0
  100. package/dist/security/security-scanner.js.map +1 -0
  101. package/dist/security/types.d.ts +80 -0
  102. package/dist/security/types.d.ts.map +1 -0
  103. package/dist/security/types.js +21 -0
  104. package/dist/security/types.js.map +1 -0
  105. package/dist/services/analytics.d.ts +114 -0
  106. package/dist/services/analytics.d.ts.map +1 -0
  107. package/dist/services/analytics.js +862 -0
  108. package/dist/services/analytics.js.map +1 -0
  109. package/dist/services/badge.d.ts +31 -0
  110. package/dist/services/badge.d.ts.map +1 -0
  111. package/dist/services/badge.js +152 -0
  112. package/dist/services/badge.js.map +1 -0
  113. package/dist/services/cron.d.ts +125 -0
  114. package/dist/services/cron.d.ts.map +1 -0
  115. package/dist/services/cron.js +613 -0
  116. package/dist/services/cron.js.map +1 -0
  117. package/dist/services/directory.d.ts +106 -0
  118. package/dist/services/directory.d.ts.map +1 -0
  119. package/dist/services/directory.js +351 -0
  120. package/dist/services/directory.js.map +1 -0
  121. package/dist/services/email.d.ts +112 -0
  122. package/dist/services/email.d.ts.map +1 -0
  123. package/dist/services/email.js +772 -0
  124. package/dist/services/email.js.map +1 -0
  125. package/dist/services/hosted-profiles.d.ts +77 -0
  126. package/dist/services/hosted-profiles.d.ts.map +1 -0
  127. package/dist/services/hosted-profiles.js +433 -0
  128. package/dist/services/hosted-profiles.js.map +1 -0
  129. package/dist/services/latency.d.ts +67 -0
  130. package/dist/services/latency.d.ts.map +1 -0
  131. package/dist/services/latency.js +274 -0
  132. package/dist/services/latency.js.map +1 -0
  133. package/dist/services/manifest-compliance.d.ts +64 -0
  134. package/dist/services/manifest-compliance.d.ts.map +1 -0
  135. package/dist/services/manifest-compliance.js +271 -0
  136. package/dist/services/manifest-compliance.js.map +1 -0
  137. package/dist/services/monitoring-diff.d.ts +31 -0
  138. package/dist/services/monitoring-diff.d.ts.map +1 -0
  139. package/dist/services/monitoring-diff.js +189 -0
  140. package/dist/services/monitoring-diff.js.map +1 -0
  141. package/dist/services/notifications.d.ts +46 -0
  142. package/dist/services/notifications.d.ts.map +1 -0
  143. package/dist/services/notifications.js +88 -0
  144. package/dist/services/notifications.js.map +1 -0
  145. package/dist/services/stripe.d.ts +93 -0
  146. package/dist/services/stripe.d.ts.map +1 -0
  147. package/dist/services/stripe.js +490 -0
  148. package/dist/services/stripe.js.map +1 -0
  149. package/dist/services/validation-history.d.ts +99 -0
  150. package/dist/services/validation-history.d.ts.map +1 -0
  151. package/dist/services/validation-history.js +344 -0
  152. package/dist/services/validation-history.js.map +1 -0
  153. package/dist/services/validation-logging.d.ts +103 -0
  154. package/dist/services/validation-logging.d.ts.map +1 -0
  155. package/dist/services/validation-logging.js +210 -0
  156. package/dist/services/validation-logging.js.map +1 -0
  157. package/dist/services/validation.d.ts +119 -0
  158. package/dist/services/validation.d.ts.map +1 -0
  159. package/dist/services/validation.js +1185 -0
  160. package/dist/services/validation.js.map +1 -0
  161. package/dist/simulator/agent-simulator.d.ts +69 -0
  162. package/dist/simulator/agent-simulator.d.ts.map +1 -0
  163. package/dist/simulator/agent-simulator.js +870 -0
  164. package/dist/simulator/agent-simulator.js.map +1 -0
  165. package/{src/simulator/index.ts → dist/simulator/index.d.ts} +7 -7
  166. package/dist/simulator/index.d.ts.map +1 -0
  167. package/dist/simulator/index.js +23 -0
  168. package/dist/simulator/index.js.map +1 -0
  169. package/{src/simulator/types.ts → dist/simulator/types.d.ts} +171 -170
  170. package/dist/simulator/types.d.ts.map +1 -0
  171. package/dist/simulator/types.js +18 -0
  172. package/dist/simulator/types.js.map +1 -0
  173. package/dist/types/acp-validation.d.ts +87 -0
  174. package/dist/types/acp-validation.d.ts.map +1 -0
  175. package/dist/types/acp-validation.js +40 -0
  176. package/dist/types/acp-validation.js.map +1 -0
  177. package/dist/types/analytics.d.ts +182 -0
  178. package/dist/types/analytics.d.ts.map +1 -0
  179. package/dist/types/analytics.js +7 -0
  180. package/dist/types/analytics.js.map +1 -0
  181. package/dist/types/generator.d.ts +106 -0
  182. package/dist/types/generator.d.ts.map +1 -0
  183. package/dist/types/generator.js +6 -0
  184. package/dist/types/generator.js.map +1 -0
  185. package/{src/types/index.ts → dist/types/index.d.ts} +1 -1
  186. package/dist/types/index.d.ts.map +1 -0
  187. package/dist/types/index.js +23 -0
  188. package/dist/types/index.js.map +1 -0
  189. package/dist/types/ucp-profile.d.ts +111 -0
  190. package/dist/types/ucp-profile.d.ts.map +1 -0
  191. package/dist/types/ucp-profile.js +45 -0
  192. package/dist/types/ucp-profile.js.map +1 -0
  193. package/dist/types/validation.d.ts +76 -0
  194. package/dist/types/validation.d.ts.map +1 -0
  195. package/dist/types/validation.js +42 -0
  196. package/dist/types/validation.js.map +1 -0
  197. package/dist/validator/acp/index.d.ts +31 -0
  198. package/dist/validator/acp/index.d.ts.map +1 -0
  199. package/dist/validator/acp/index.js +574 -0
  200. package/dist/validator/acp/index.js.map +1 -0
  201. package/dist/validator/index.d.ts +26 -0
  202. package/dist/validator/index.d.ts.map +1 -0
  203. package/dist/validator/index.js +161 -0
  204. package/dist/validator/index.js.map +1 -0
  205. package/dist/validator/network-validator.d.ts +28 -0
  206. package/dist/validator/network-validator.d.ts.map +1 -0
  207. package/dist/validator/network-validator.js +319 -0
  208. package/dist/validator/network-validator.js.map +1 -0
  209. package/dist/validator/rules-validator.d.ts +19 -0
  210. package/dist/validator/rules-validator.d.ts.map +1 -0
  211. package/dist/validator/rules-validator.js +306 -0
  212. package/dist/validator/rules-validator.js.map +1 -0
  213. package/dist/validator/sdk-validator.d.ts +58 -0
  214. package/dist/validator/sdk-validator.d.ts.map +1 -0
  215. package/{src/validator/sdk-validator.ts → dist/validator/sdk-validator.js} +273 -330
  216. package/dist/validator/sdk-validator.js.map +1 -0
  217. package/dist/validator/structural-validator.d.ts +11 -0
  218. package/dist/validator/structural-validator.d.ts.map +1 -0
  219. package/dist/validator/structural-validator.js +549 -0
  220. package/dist/validator/structural-validator.js.map +1 -0
  221. package/dist/validator/utils.d.ts +51 -0
  222. package/dist/validator/utils.d.ts.map +1 -0
  223. package/dist/validator/utils.js +132 -0
  224. package/dist/validator/utils.js.map +1 -0
  225. package/package.json +44 -12
  226. package/CLAUDE.md +0 -109
  227. package/api/analyze-feed.js +0 -140
  228. package/api/badge.js +0 -185
  229. package/api/benchmark.js +0 -177
  230. package/api/directory-stats.ts +0 -29
  231. package/api/directory.ts +0 -73
  232. package/api/generate-compliance.js +0 -143
  233. package/api/generate-schema.js +0 -457
  234. package/api/generate.js +0 -132
  235. package/api/security-scan.js +0 -133
  236. package/api/simulate.js +0 -187
  237. package/api/tsconfig.json +0 -10
  238. package/api/validate.js +0 -1351
  239. package/apify-actor/.actor/actor.json +0 -68
  240. package/apify-actor/.actor/input_schema.json +0 -32
  241. package/apify-actor/APIFY-STORE-LISTING.md +0 -412
  242. package/apify-actor/Dockerfile +0 -8
  243. package/apify-actor/README.md +0 -166
  244. package/apify-actor/main.ts +0 -111
  245. package/apify-actor/package.json +0 -17
  246. package/apify-actor/src/main.js +0 -199
  247. package/docs/BRAND-IDENTITY.md +0 -238
  248. package/docs/BRAND-STYLE-GUIDE.md +0 -356
  249. package/drizzle/0000_black_king_cobra.sql +0 -39
  250. package/drizzle/meta/0000_snapshot.json +0 -309
  251. package/drizzle/meta/_journal.json +0 -13
  252. package/drizzle.config.ts +0 -10
  253. package/public/.well-known/ucp +0 -25
  254. package/public/android-chrome-192x192.png +0 -0
  255. package/public/android-chrome-512x512.png +0 -0
  256. package/public/apple-touch-icon.png +0 -0
  257. package/public/brand.css +0 -321
  258. package/public/directory.html +0 -701
  259. package/public/favicon-16x16.png +0 -0
  260. package/public/favicon-32x32.png +0 -0
  261. package/public/favicon.ico +0 -0
  262. package/public/guides/bigcommerce.html +0 -743
  263. package/public/guides/fastucp.html +0 -838
  264. package/public/guides/magento.html +0 -779
  265. package/public/guides/shopify.html +0 -726
  266. package/public/guides/squarespace.html +0 -749
  267. package/public/guides/wix.html +0 -747
  268. package/public/guides/woocommerce.html +0 -733
  269. package/public/index.html +0 -3835
  270. package/public/learn.html +0 -396
  271. package/public/logo.jpeg +0 -0
  272. package/public/og-image-icon.png +0 -0
  273. package/public/og-image.png +0 -0
  274. package/public/robots.txt +0 -6
  275. package/public/site.webmanifest +0 -31
  276. package/public/sitemap.xml +0 -69
  277. package/public/social/linkedin-banner-1128x191.png +0 -0
  278. package/public/social/temp.PNG +0 -0
  279. package/public/social/x-header-1500x500.png +0 -0
  280. package/public/verify.html +0 -410
  281. package/scripts/generate-favicons.js +0 -44
  282. package/scripts/generate-ico.js +0 -23
  283. package/scripts/generate-og-image.js +0 -45
  284. package/scripts/reset-db.ts +0 -77
  285. package/scripts/seed-db.ts +0 -71
  286. package/scripts/setup-benchmark-db.js +0 -70
  287. package/src/api/server.ts +0 -266
  288. package/src/cli/index.ts +0 -302
  289. package/src/compliance/compliance-generator.ts +0 -452
  290. package/src/compliance/index.ts +0 -28
  291. package/src/compliance/types.ts +0 -170
  292. package/src/db/index.ts +0 -28
  293. package/src/db/schema.ts +0 -84
  294. package/src/feed-analyzer/index.ts +0 -34
  295. package/src/feed-analyzer/types.ts +0 -354
  296. package/src/generator/key-generator.ts +0 -124
  297. package/src/generator/profile-builder.ts +0 -402
  298. package/src/index.ts +0 -105
  299. package/src/security/security-scanner.ts +0 -604
  300. package/src/security/types.ts +0 -55
  301. package/src/services/directory.ts +0 -434
  302. package/src/simulator/agent-simulator.ts +0 -941
  303. package/src/types/generator.ts +0 -140
  304. package/src/types/ucp-profile.ts +0 -140
  305. package/src/types/validation.ts +0 -89
  306. package/src/validator/index.ts +0 -194
  307. package/src/validator/network-validator.ts +0 -417
  308. package/src/validator/rules-validator.ts +0 -297
  309. package/src/validator/structural-validator.ts +0 -476
  310. package/tests/fixtures/non-compliant-profile.json +0 -25
  311. package/tests/fixtures/official-sample-profile.json +0 -75
  312. package/tests/integration/benchmark.test.ts +0 -207
  313. package/tests/integration/database.test.ts +0 -163
  314. package/tests/integration/directory-api.test.ts +0 -268
  315. package/tests/integration/simulate-api.test.ts +0 -230
  316. package/tests/integration/validate-api.test.ts +0 -269
  317. package/tests/setup.ts +0 -15
  318. package/tests/unit/agent-simulator.test.ts +0 -575
  319. package/tests/unit/compliance-generator.test.ts +0 -374
  320. package/tests/unit/directory-service.test.ts +0 -272
  321. package/tests/unit/feed-analyzer.test.ts +0 -517
  322. package/tests/unit/lint-suggestions.test.ts +0 -423
  323. package/tests/unit/official-samples.test.ts +0 -211
  324. package/tests/unit/pdf-report.test.ts +0 -390
  325. package/tests/unit/sdk-validator.test.ts +0 -531
  326. package/tests/unit/security-scanner.test.ts +0 -410
  327. package/tests/unit/validation.test.ts +0 -390
  328. package/tsconfig.json +0 -20
  329. package/vercel.json +0 -34
  330. package/vitest.config.ts +0 -22
@@ -1,70 +0,0 @@
1
- /**
2
- * Setup script for benchmark database tables
3
- * Run with: node scripts/setup-benchmark-db.js
4
- */
5
-
6
- import pg from 'pg';
7
-
8
- const { Pool } = pg;
9
-
10
- async function setup() {
11
- const pool = new Pool({
12
- connectionString: process.env.DATABASE_URL,
13
- ssl: { rejectUnauthorized: false }
14
- });
15
-
16
- try {
17
- console.log('Creating benchmark tables...');
18
-
19
- // Create benchmark_stats table for aggregate statistics
20
- await pool.query(`
21
- CREATE TABLE IF NOT EXISTS benchmark_stats (
22
- id SERIAL PRIMARY KEY,
23
- score_bucket INT NOT NULL CHECK (score_bucket >= 0 AND score_bucket <= 100),
24
- count INT DEFAULT 0,
25
- UNIQUE(score_bucket)
26
- );
27
- `);
28
-
29
- // Initialize score buckets (0-10, 10-20, ..., 90-100)
30
- for (let bucket = 0; bucket <= 100; bucket += 10) {
31
- await pool.query(`
32
- INSERT INTO benchmark_stats (score_bucket, count)
33
- VALUES ($1, 0)
34
- ON CONFLICT (score_bucket) DO NOTHING;
35
- `, [bucket]);
36
- }
37
-
38
- // Create summary table for quick stats
39
- await pool.query(`
40
- CREATE TABLE IF NOT EXISTS benchmark_summary (
41
- id INT PRIMARY KEY DEFAULT 1,
42
- total_validations INT DEFAULT 0,
43
- avg_score DECIMAL(5,2) DEFAULT 0,
44
- updated_at TIMESTAMP DEFAULT NOW(),
45
- CHECK (id = 1)
46
- );
47
- `);
48
-
49
- // Initialize summary row
50
- await pool.query(`
51
- INSERT INTO benchmark_summary (id, total_validations, avg_score)
52
- VALUES (1, 0, 0)
53
- ON CONFLICT (id) DO NOTHING;
54
- `);
55
-
56
- console.log('✓ Benchmark tables created successfully');
57
-
58
- // Verify setup
59
- const result = await pool.query('SELECT * FROM benchmark_stats ORDER BY score_bucket');
60
- console.log('Score buckets:', result.rows.length);
61
-
62
- } catch (error) {
63
- console.error('Error setting up database:', error);
64
- process.exit(1);
65
- } finally {
66
- await pool.end();
67
- }
68
- }
69
-
70
- setup();
package/src/api/server.ts DELETED
@@ -1,266 +0,0 @@
1
- /**
2
- * UCP Profile Manager API Server
3
- */
4
-
5
- import express from 'express';
6
- import type { Request, Response, NextFunction } from 'express';
7
- import { nanoid } from 'nanoid';
8
- import pino from 'pino';
9
- import { buildProfile, generateMinimalProfile } from '../generator/index.js';
10
- import { validateProfile, validateRemote, validateQuick, validateJsonString } from '../validator/index.js';
11
- import { generateHostingArtifacts } from '../hosting/index.js';
12
- import type { GeneratorInput, HostingConfig } from '../types/generator.js';
13
- import type { ValidationOptions } from '../types/validation.js';
14
-
15
- // Logger
16
- const logger = pino({
17
- level: process.env.LOG_LEVEL || 'info',
18
- transport: process.env.NODE_ENV !== 'production' ? { target: 'pino-pretty' } : undefined,
19
- });
20
-
21
- const app = express();
22
- app.use(express.json({ limit: '1mb' }));
23
-
24
- // Request logging middleware
25
- app.use((req: Request, res: Response, next: NextFunction) => {
26
- const requestId = nanoid(8);
27
- (req as any).requestId = requestId;
28
- logger.info({ requestId, method: req.method, path: req.path }, 'Request received');
29
- next();
30
- });
31
-
32
- // CORS middleware
33
- app.use((req: Request, res: Response, next: NextFunction) => {
34
- res.header('Access-Control-Allow-Origin', '*');
35
- res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
36
- res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
37
- if (req.method === 'OPTIONS') {
38
- return res.sendStatus(204);
39
- }
40
- next();
41
- });
42
-
43
- // Health check
44
- app.get('/health', (req: Request, res: Response) => {
45
- res.json({ status: 'ok', version: '1.0.0' });
46
- });
47
-
48
- // API version prefix
49
- const api = express.Router();
50
-
51
- /**
52
- * Generate a UCP profile
53
- * POST /v1/profiles/generate
54
- */
55
- api.post('/profiles/generate', async (req: Request, res: Response) => {
56
- try {
57
- const input: GeneratorInput = req.body;
58
-
59
- // Validate required fields
60
- if (!input.merchant?.merchantId || !input.merchant?.primaryDomain) {
61
- return res.status(400).json({
62
- error: 'Missing required fields: merchant.merchantId and merchant.primaryDomain',
63
- });
64
- }
65
-
66
- if (!input.transport?.rest?.endpoint) {
67
- return res.status(400).json({
68
- error: 'Missing required field: transport.rest.endpoint',
69
- });
70
- }
71
-
72
- // Set defaults
73
- input.capabilities = input.capabilities || { checkout: true, order: false, fulfillment: false, discount: false };
74
-
75
- const result = await buildProfile(input);
76
-
77
- res.json({
78
- profile: result.profile,
79
- signing_key_pair: result.signingKeyPair ? {
80
- public_key: result.signingKeyPair.publicKey,
81
- private_key_pem: result.signingKeyPair.privateKey,
82
- } : undefined,
83
- });
84
- } catch (error) {
85
- logger.error({ error }, 'Profile generation failed');
86
- res.status(500).json({ error: 'Failed to generate profile' });
87
- }
88
- });
89
-
90
- /**
91
- * Generate minimal profile
92
- * POST /v1/profiles/generate-minimal
93
- */
94
- api.post('/profiles/generate-minimal', (req: Request, res: Response) => {
95
- try {
96
- const { endpoint, version } = req.body;
97
-
98
- if (!endpoint) {
99
- return res.status(400).json({ error: 'Missing required field: endpoint' });
100
- }
101
-
102
- const profile = generateMinimalProfile(endpoint, version);
103
- res.json({ profile });
104
- } catch (error) {
105
- logger.error({ error }, 'Minimal profile generation failed');
106
- res.status(500).json({ error: 'Failed to generate minimal profile' });
107
- }
108
- });
109
-
110
- /**
111
- * Validate a profile (from request body)
112
- * POST /v1/profiles/validate
113
- */
114
- api.post('/profiles/validate', async (req: Request, res: Response) => {
115
- try {
116
- const { profile, options } = req.body as {
117
- profile: unknown;
118
- options?: ValidationOptions;
119
- };
120
-
121
- if (!profile) {
122
- return res.status(400).json({ error: 'Missing required field: profile' });
123
- }
124
-
125
- const report = await validateProfile(profile, options || {});
126
- res.json(report);
127
- } catch (error) {
128
- logger.error({ error }, 'Profile validation failed');
129
- res.status(500).json({ error: 'Validation failed' });
130
- }
131
- });
132
-
133
- /**
134
- * Quick validate (structural + rules only)
135
- * POST /v1/profiles/validate-quick
136
- */
137
- api.post('/profiles/validate-quick', (req: Request, res: Response) => {
138
- try {
139
- const { profile } = req.body;
140
-
141
- if (!profile) {
142
- return res.status(400).json({ error: 'Missing required field: profile' });
143
- }
144
-
145
- const report = validateQuick(profile);
146
- res.json(report);
147
- } catch (error) {
148
- logger.error({ error }, 'Quick validation failed');
149
- res.status(500).json({ error: 'Validation failed' });
150
- }
151
- });
152
-
153
- /**
154
- * Validate remote profile
155
- * POST /v1/profiles/validate-remote
156
- */
157
- api.post('/profiles/validate-remote', async (req: Request, res: Response) => {
158
- try {
159
- const { domain, options } = req.body as {
160
- domain: string;
161
- options?: ValidationOptions;
162
- };
163
-
164
- if (!domain) {
165
- return res.status(400).json({ error: 'Missing required field: domain' });
166
- }
167
-
168
- const report = await validateRemote(domain, options || {});
169
- res.json(report);
170
- } catch (error) {
171
- logger.error({ error }, 'Remote validation failed');
172
- res.status(500).json({ error: 'Remote validation failed' });
173
- }
174
- });
175
-
176
- /**
177
- * Validate JSON string
178
- * POST /v1/profiles/validate-json
179
- */
180
- api.post('/profiles/validate-json', async (req: Request, res: Response) => {
181
- try {
182
- const { json, options } = req.body as {
183
- json: string;
184
- options?: ValidationOptions;
185
- };
186
-
187
- if (!json) {
188
- return res.status(400).json({ error: 'Missing required field: json' });
189
- }
190
-
191
- const report = await validateJsonString(json, options || {});
192
- res.json(report);
193
- } catch (error) {
194
- logger.error({ error }, 'JSON validation failed');
195
- res.status(500).json({ error: 'Validation failed' });
196
- }
197
- });
198
-
199
- /**
200
- * Generate hosting artifacts
201
- * POST /v1/hosting/artifacts
202
- */
203
- api.post('/hosting/artifacts', (req: Request, res: Response) => {
204
- try {
205
- const { config, profile_json } = req.body as {
206
- config: HostingConfig;
207
- profile_json: string;
208
- };
209
-
210
- if (!config?.merchantId || !config?.merchantDomain || !config?.mode) {
211
- return res.status(400).json({
212
- error: 'Missing required config fields: merchantId, merchantDomain, mode',
213
- });
214
- }
215
-
216
- if (!profile_json) {
217
- return res.status(400).json({ error: 'Missing required field: profile_json' });
218
- }
219
-
220
- const artifacts = generateHostingArtifacts(config, profile_json);
221
- res.json({ artifacts });
222
- } catch (error) {
223
- logger.error({ error }, 'Artifact generation failed');
224
- res.status(500).json({ error: 'Failed to generate artifacts' });
225
- }
226
- });
227
-
228
- /**
229
- * Hosted profile endpoint (for edge worker proxying)
230
- * GET /hosted/:merchantId/ucp.json
231
- */
232
- api.get('/hosted/:merchantId/ucp.json', async (req: Request, res: Response) => {
233
- const { merchantId } = req.params;
234
-
235
- // TODO: Implement database lookup for stored profiles
236
- // For now, return 404 as this requires database integration
237
- res.status(404).json({
238
- error: 'Profile not found',
239
- hint: 'This endpoint requires database integration. Use /v1/profiles/generate to create profiles.',
240
- });
241
- });
242
-
243
- // Mount API routes
244
- app.use('/v1', api);
245
-
246
- // Error handler
247
- app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
248
- logger.error({ error: err }, 'Unhandled error');
249
- res.status(500).json({ error: 'Internal server error' });
250
- });
251
-
252
- // 404 handler
253
- app.use((req: Request, res: Response) => {
254
- res.status(404).json({ error: 'Not found' });
255
- });
256
-
257
- // Start server
258
- const PORT = process.env.PORT || 3000;
259
-
260
- if (process.env.NODE_ENV !== 'test') {
261
- app.listen(PORT, () => {
262
- logger.info({ port: PORT }, 'UCP Profile Manager API started');
263
- });
264
- }
265
-
266
- export { app };
package/src/cli/index.ts DELETED
@@ -1,302 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * UCP Profile Validator CLI
4
- */
5
-
6
- import { program } from 'commander';
7
- import { readFileSync, writeFileSync, existsSync } from 'fs';
8
- import { resolve } from 'path';
9
- import { validateProfile, validateRemote, validateQuick } from '../validator/index.js';
10
- import { buildProfile, generateMinimalProfile } from '../generator/index.js';
11
- import { generateHostingArtifacts } from '../hosting/index.js';
12
- import type { ValidationReport } from '../types/validation.js';
13
- import type { GeneratorInput, HostingConfig, HostingMode, HostingPlatform } from '../types/generator.js';
14
-
15
- // Colors for terminal output (simple implementation without chalk for ESM)
16
- const colors = {
17
- red: (s: string) => `\x1b[31m${s}\x1b[0m`,
18
- green: (s: string) => `\x1b[32m${s}\x1b[0m`,
19
- yellow: (s: string) => `\x1b[33m${s}\x1b[0m`,
20
- blue: (s: string) => `\x1b[34m${s}\x1b[0m`,
21
- gray: (s: string) => `\x1b[90m${s}\x1b[0m`,
22
- bold: (s: string) => `\x1b[1m${s}\x1b[0m`,
23
- };
24
-
25
- program
26
- .name('ucp-validate')
27
- .description('UCP Profile Validator and Generator CLI')
28
- .version('1.0.0');
29
-
30
- /**
31
- * Validate command
32
- */
33
- program
34
- .command('validate')
35
- .description('Validate a UCP profile')
36
- .option('-f, --file <path>', 'Path to local JSON file')
37
- .option('-r, --remote <domain>', 'Remote domain to fetch profile from')
38
- .option('-q, --quick', 'Quick validation (no network checks)')
39
- .option('-o, --output <path>', 'Output report to file')
40
- .option('--json', 'Output as JSON')
41
- .action(async (options) => {
42
- try {
43
- let report: ValidationReport;
44
-
45
- if (options.remote) {
46
- console.log(colors.blue(`Fetching profile from https://${options.remote}/.well-known/ucp...`));
47
- report = await validateRemote(options.remote, {
48
- skipNetworkChecks: options.quick,
49
- });
50
- } else if (options.file) {
51
- const filePath = resolve(options.file);
52
- if (!existsSync(filePath)) {
53
- console.error(colors.red(`File not found: ${filePath}`));
54
- process.exit(1);
55
- }
56
- const content = readFileSync(filePath, 'utf-8');
57
- const profile = JSON.parse(content);
58
-
59
- if (options.quick) {
60
- report = validateQuick(profile);
61
- } else {
62
- report = await validateProfile(profile);
63
- }
64
- } else {
65
- console.error(colors.red('Please specify --file or --remote'));
66
- process.exit(1);
67
- }
68
-
69
- // Output
70
- if (options.json) {
71
- console.log(JSON.stringify(report, null, 2));
72
- } else {
73
- printValidationReport(report);
74
- }
75
-
76
- if (options.output) {
77
- writeFileSync(options.output, JSON.stringify(report, null, 2));
78
- console.log(colors.gray(`\nReport saved to: ${options.output}`));
79
- }
80
-
81
- process.exit(report.ok ? 0 : 1);
82
- } catch (error) {
83
- console.error(colors.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
84
- process.exit(1);
85
- }
86
- });
87
-
88
- /**
89
- * Generate command
90
- */
91
- program
92
- .command('generate')
93
- .description('Generate a new UCP profile')
94
- .requiredOption('-d, --domain <domain>', 'Primary domain (e.g., merchant.com)')
95
- .requiredOption('-e, --endpoint <url>', 'REST API endpoint URL')
96
- .option('-i, --id <id>', 'Merchant ID (auto-generated if not provided)')
97
- .option('--order', 'Enable Order capability')
98
- .option('--fulfillment', 'Enable Fulfillment capability')
99
- .option('--discount', 'Enable Discount capability')
100
- .option('-o, --output <path>', 'Output file path', 'ucp.json')
101
- .option('--json', 'Output to stdout as JSON')
102
- .action(async (options) => {
103
- try {
104
- const input: GeneratorInput = {
105
- merchant: {
106
- merchantId: options.id || `merchant-${Date.now()}`,
107
- primaryDomain: options.domain,
108
- },
109
- transport: {
110
- rest: {
111
- endpoint: options.endpoint,
112
- },
113
- },
114
- capabilities: {
115
- checkout: true,
116
- order: options.order || false,
117
- fulfillment: options.fulfillment || false,
118
- discount: options.discount || false,
119
- },
120
- security: {
121
- generateSigningKeys: options.order || false,
122
- },
123
- };
124
-
125
- const result = await buildProfile(input);
126
-
127
- if (options.json) {
128
- console.log(result.profileJson);
129
- } else {
130
- writeFileSync(options.output, result.profileJson);
131
- console.log(colors.green(`✓ Profile generated: ${options.output}`));
132
-
133
- if (result.signingKeyPair) {
134
- const keyFile = options.output.replace('.json', '-private-key.pem');
135
- writeFileSync(keyFile, result.signingKeyPair.privateKey);
136
- console.log(colors.yellow(`⚠ Private key saved: ${keyFile}`));
137
- console.log(colors.gray(' Keep this file secure! Do not commit to version control.'));
138
- }
139
-
140
- console.log(colors.blue('\nNext steps:'));
141
- console.log(' 1. Review the generated profile');
142
- console.log(' 2. Run: ucp-validate validate -f ' + options.output);
143
- console.log(' 3. Deploy to https://' + options.domain + '/.well-known/ucp');
144
- }
145
- } catch (error) {
146
- console.error(colors.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
147
- process.exit(1);
148
- }
149
- });
150
-
151
- /**
152
- * Generate minimal profile
153
- */
154
- program
155
- .command('generate-minimal')
156
- .description('Generate a minimal starter profile')
157
- .requiredOption('-e, --endpoint <url>', 'REST API endpoint URL')
158
- .option('-o, --output <path>', 'Output file path', 'ucp.json')
159
- .action((options) => {
160
- try {
161
- const profile = generateMinimalProfile(options.endpoint);
162
- const json = JSON.stringify(profile, null, 2);
163
-
164
- writeFileSync(options.output, json);
165
- console.log(colors.green(`✓ Minimal profile generated: ${options.output}`));
166
- } catch (error) {
167
- console.error(colors.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
168
- process.exit(1);
169
- }
170
- });
171
-
172
- /**
173
- * Generate hosting artifacts
174
- */
175
- program
176
- .command('hosting')
177
- .description('Generate hosting configuration files')
178
- .requiredOption('-f, --file <path>', 'Path to profile JSON file')
179
- .requiredOption('-d, --domain <domain>', 'Merchant domain')
180
- .requiredOption('-m, --mode <mode>', 'Hosting mode: static, edge-worker, reverse-proxy')
181
- .option('-p, --platform <platform>', 'Platform: nginx, apache, vercel, netlify, cloudflare-worker, s3-cloudfront')
182
- .option('-i, --id <id>', 'Merchant ID')
183
- .option('-o, --output <dir>', 'Output directory', './ucp-hosting')
184
- .action((options) => {
185
- try {
186
- const filePath = resolve(options.file);
187
- if (!existsSync(filePath)) {
188
- console.error(colors.red(`File not found: ${filePath}`));
189
- process.exit(1);
190
- }
191
-
192
- const profileJson = readFileSync(filePath, 'utf-8');
193
-
194
- const config: HostingConfig = {
195
- mode: options.mode as HostingMode,
196
- platform: options.platform as HostingPlatform,
197
- merchantId: options.id || `merchant-${Date.now()}`,
198
- merchantDomain: options.domain,
199
- };
200
-
201
- const artifacts = generateHostingArtifacts(config, profileJson);
202
-
203
- // Create output directory
204
- const outputDir = resolve(options.output);
205
- if (!existsSync(outputDir)) {
206
- const { mkdirSync } = require('fs');
207
- mkdirSync(outputDir, { recursive: true });
208
- }
209
-
210
- // Write artifacts
211
- for (const artifact of artifacts) {
212
- const artifactPath = resolve(outputDir, artifact.filename);
213
- // Create subdirectories if needed
214
- const dir = artifactPath.substring(0, artifactPath.lastIndexOf('/'));
215
- if (dir && !existsSync(dir)) {
216
- const { mkdirSync } = require('fs');
217
- mkdirSync(dir, { recursive: true });
218
- }
219
- writeFileSync(artifactPath, artifact.content);
220
- console.log(colors.green(`✓ ${artifact.filename}`));
221
- }
222
-
223
- console.log(colors.blue(`\nArtifacts generated in: ${outputDir}`));
224
- console.log(colors.gray('See README.md for installation instructions.'));
225
- } catch (error) {
226
- console.error(colors.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
227
- process.exit(1);
228
- }
229
- });
230
-
231
- /**
232
- * Print validation report to console
233
- */
234
- function printValidationReport(report: ValidationReport): void {
235
- console.log('\n' + colors.bold('UCP Profile Validation Report'));
236
- console.log('═'.repeat(50));
237
-
238
- if (report.profile_url) {
239
- console.log(colors.gray(`Profile: ${report.profile_url}`));
240
- }
241
- if (report.ucp_version) {
242
- console.log(colors.gray(`UCP Version: ${report.ucp_version}`));
243
- }
244
- console.log(colors.gray(`Validated: ${report.validated_at}`));
245
- console.log(colors.gray(`Mode: ${report.validation_mode}`));
246
- console.log('');
247
-
248
- // Summary
249
- if (report.ok) {
250
- console.log(colors.green('✓ Validation PASSED'));
251
- } else {
252
- console.log(colors.red('✗ Validation FAILED'));
253
- }
254
-
255
- // Issue counts
256
- const errors = report.issues.filter(i => i.severity === 'error');
257
- const warnings = report.issues.filter(i => i.severity === 'warn');
258
- const info = report.issues.filter(i => i.severity === 'info');
259
-
260
- if (report.issues.length === 0) {
261
- console.log(colors.green('\nNo issues found!'));
262
- } else {
263
- console.log(`\n${errors.length} error(s), ${warnings.length} warning(s), ${info.length} info`);
264
- }
265
-
266
- // Print issues
267
- if (errors.length > 0) {
268
- console.log('\n' + colors.red('Errors:'));
269
- for (const issue of errors) {
270
- printIssue(issue);
271
- }
272
- }
273
-
274
- if (warnings.length > 0) {
275
- console.log('\n' + colors.yellow('Warnings:'));
276
- for (const issue of warnings) {
277
- printIssue(issue);
278
- }
279
- }
280
-
281
- if (info.length > 0) {
282
- console.log('\n' + colors.blue('Info:'));
283
- for (const issue of info) {
284
- printIssue(issue);
285
- }
286
- }
287
-
288
- console.log('');
289
- }
290
-
291
- function printIssue(issue: { severity: string; code: string; path: string; message: string; hint?: string }): void {
292
- const icon = issue.severity === 'error' ? '✗' : issue.severity === 'warn' ? '⚠' : 'ℹ';
293
- const color = issue.severity === 'error' ? colors.red : issue.severity === 'warn' ? colors.yellow : colors.blue;
294
-
295
- console.log(` ${color(icon)} [${issue.code}] ${issue.message}`);
296
- console.log(colors.gray(` Path: ${issue.path}`));
297
- if (issue.hint) {
298
- console.log(colors.gray(` Hint: ${issue.hint}`));
299
- }
300
- }
301
-
302
- program.parse();