@ucptools/validator 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CLAUDE.md +109 -0
  2. package/CONTRIBUTING.md +113 -0
  3. package/LICENSE +21 -0
  4. package/README.md +203 -0
  5. package/api/analyze-feed.js +140 -0
  6. package/api/badge.js +185 -0
  7. package/api/benchmark.js +177 -0
  8. package/api/directory-stats.ts +29 -0
  9. package/api/directory.ts +73 -0
  10. package/api/generate-compliance.js +143 -0
  11. package/api/generate-schema.js +457 -0
  12. package/api/generate.js +132 -0
  13. package/api/security-scan.js +133 -0
  14. package/api/simulate.js +187 -0
  15. package/api/tsconfig.json +10 -0
  16. package/api/validate.js +1351 -0
  17. package/apify-actor/.actor/actor.json +68 -0
  18. package/apify-actor/.actor/input_schema.json +32 -0
  19. package/apify-actor/APIFY-STORE-LISTING.md +412 -0
  20. package/apify-actor/Dockerfile +8 -0
  21. package/apify-actor/README.md +166 -0
  22. package/apify-actor/main.ts +111 -0
  23. package/apify-actor/package.json +17 -0
  24. package/apify-actor/src/main.js +199 -0
  25. package/docs/BRAND-IDENTITY.md +238 -0
  26. package/docs/BRAND-STYLE-GUIDE.md +356 -0
  27. package/drizzle/0000_black_king_cobra.sql +39 -0
  28. package/drizzle/meta/0000_snapshot.json +309 -0
  29. package/drizzle/meta/_journal.json +13 -0
  30. package/drizzle.config.ts +10 -0
  31. package/examples/full-profile.json +70 -0
  32. package/examples/minimal-profile.json +23 -0
  33. package/package.json +69 -0
  34. package/public/.well-known/ucp +25 -0
  35. package/public/android-chrome-192x192.png +0 -0
  36. package/public/android-chrome-512x512.png +0 -0
  37. package/public/apple-touch-icon.png +0 -0
  38. package/public/brand.css +321 -0
  39. package/public/directory.html +701 -0
  40. package/public/favicon-16x16.png +0 -0
  41. package/public/favicon-32x32.png +0 -0
  42. package/public/favicon.ico +0 -0
  43. package/public/guides/bigcommerce.html +743 -0
  44. package/public/guides/fastucp.html +838 -0
  45. package/public/guides/magento.html +779 -0
  46. package/public/guides/shopify.html +726 -0
  47. package/public/guides/squarespace.html +749 -0
  48. package/public/guides/wix.html +747 -0
  49. package/public/guides/woocommerce.html +733 -0
  50. package/public/index.html +3835 -0
  51. package/public/learn.html +396 -0
  52. package/public/logo.jpeg +0 -0
  53. package/public/og-image-icon.png +0 -0
  54. package/public/og-image.png +0 -0
  55. package/public/robots.txt +6 -0
  56. package/public/site.webmanifest +31 -0
  57. package/public/sitemap.xml +69 -0
  58. package/public/social/linkedin-banner-1128x191.png +0 -0
  59. package/public/social/temp.PNG +0 -0
  60. package/public/social/x-header-1500x500.png +0 -0
  61. package/public/verify.html +410 -0
  62. package/scripts/generate-favicons.js +44 -0
  63. package/scripts/generate-ico.js +23 -0
  64. package/scripts/generate-og-image.js +45 -0
  65. package/scripts/reset-db.ts +77 -0
  66. package/scripts/seed-db.ts +71 -0
  67. package/scripts/setup-benchmark-db.js +70 -0
  68. package/src/api/server.ts +266 -0
  69. package/src/cli/index.ts +302 -0
  70. package/src/compliance/compliance-generator.ts +452 -0
  71. package/src/compliance/index.ts +28 -0
  72. package/src/compliance/templates.ts +338 -0
  73. package/src/compliance/types.ts +170 -0
  74. package/src/db/index.ts +28 -0
  75. package/src/db/schema.ts +84 -0
  76. package/src/feed-analyzer/feed-analyzer.ts +726 -0
  77. package/src/feed-analyzer/index.ts +34 -0
  78. package/src/feed-analyzer/types.ts +354 -0
  79. package/src/generator/index.ts +7 -0
  80. package/src/generator/key-generator.ts +124 -0
  81. package/src/generator/profile-builder.ts +402 -0
  82. package/src/hosting/artifacts-generator.ts +679 -0
  83. package/src/hosting/index.ts +6 -0
  84. package/src/index.ts +105 -0
  85. package/src/security/index.ts +15 -0
  86. package/src/security/security-scanner.ts +604 -0
  87. package/src/security/types.ts +55 -0
  88. package/src/services/directory.ts +434 -0
  89. package/src/simulator/agent-simulator.ts +941 -0
  90. package/src/simulator/index.ts +7 -0
  91. package/src/simulator/types.ts +170 -0
  92. package/src/types/generator.ts +140 -0
  93. package/src/types/index.ts +7 -0
  94. package/src/types/ucp-profile.ts +140 -0
  95. package/src/types/validation.ts +89 -0
  96. package/src/validator/index.ts +194 -0
  97. package/src/validator/network-validator.ts +417 -0
  98. package/src/validator/rules-validator.ts +297 -0
  99. package/src/validator/sdk-validator.ts +330 -0
  100. package/src/validator/structural-validator.ts +476 -0
  101. package/tests/fixtures/non-compliant-profile.json +25 -0
  102. package/tests/fixtures/official-sample-profile.json +75 -0
  103. package/tests/integration/benchmark.test.ts +207 -0
  104. package/tests/integration/database.test.ts +163 -0
  105. package/tests/integration/directory-api.test.ts +268 -0
  106. package/tests/integration/simulate-api.test.ts +230 -0
  107. package/tests/integration/validate-api.test.ts +269 -0
  108. package/tests/setup.ts +15 -0
  109. package/tests/unit/agent-simulator.test.ts +575 -0
  110. package/tests/unit/compliance-generator.test.ts +374 -0
  111. package/tests/unit/directory-service.test.ts +272 -0
  112. package/tests/unit/feed-analyzer.test.ts +517 -0
  113. package/tests/unit/lint-suggestions.test.ts +423 -0
  114. package/tests/unit/official-samples.test.ts +211 -0
  115. package/tests/unit/pdf-report.test.ts +390 -0
  116. package/tests/unit/sdk-validator.test.ts +531 -0
  117. package/tests/unit/security-scanner.test.ts +410 -0
  118. package/tests/unit/validation.test.ts +390 -0
  119. package/tsconfig.json +20 -0
  120. package/vercel.json +34 -0
  121. package/vitest.config.ts +22 -0
@@ -0,0 +1,338 @@
1
+ /**
2
+ * GDPR/Privacy Compliance Templates
3
+ * Template content for privacy policy addendums and consent language
4
+ */
5
+
6
+ import type { ComplianceRegion, LawfulBasis, DataProcessor } from './types.js';
7
+ import { LAWFUL_BASIS_DESCRIPTIONS, AI_PLATFORM_PROCESSORS } from './types.js';
8
+
9
+ /**
10
+ * Generate the AI Commerce privacy policy section
11
+ */
12
+ export function generateAiCommerceSection(
13
+ companyName: string,
14
+ platforms: DataProcessor[],
15
+ lawfulBasis: LawfulBasis,
16
+ regions: ComplianceRegion[]
17
+ ): string {
18
+ const basisInfo = LAWFUL_BASIS_DESCRIPTIONS[lawfulBasis];
19
+ const platformList = platforms.map(p => p.name).join(', ');
20
+
21
+ let section = `## AI-Powered Shopping and Agentic Commerce
22
+
23
+ ### How We Use AI Shopping Agents
24
+
25
+ ${companyName} enables customers to browse, shop, and complete purchases through AI-powered shopping agents and assistants. These include services such as ${platformList}.
26
+
27
+ When you interact with our store through an AI shopping agent:
28
+ - The AI agent may access our product catalog, pricing, and availability information
29
+ - Your order details are processed through our Universal Commerce Protocol (UCP) integration
30
+ - Transaction data is shared with the AI platform to complete your purchase
31
+
32
+ ### Legal Basis for Processing
33
+
34
+ We process your personal data in connection with AI-assisted purchases under **${basisInfo.title}** (${basisInfo.gdprArticle} GDPR).
35
+
36
+ ${basisInfo.description}
37
+
38
+ ### Data Collected Through AI Agents
39
+
40
+ When you make a purchase through an AI shopping agent, we may collect:
41
+ - Order information (products, quantities, prices)
42
+ - Delivery address and contact details
43
+ - Payment confirmation (we do not receive full payment card details)
44
+ - Transaction identifiers for order tracking
45
+ - Communication preferences
46
+ `;
47
+
48
+ if (regions.includes('eu') || regions.includes('uk')) {
49
+ section += `
50
+ ### International Data Transfers
51
+
52
+ Some AI agent providers are based outside the European Economic Area (EEA) or United Kingdom. When your data is transferred to these providers, it is protected by:
53
+ - Standard Contractual Clauses (SCCs) approved by the European Commission
54
+ - The provider's certification under applicable data protection frameworks
55
+ - Additional technical and organizational security measures
56
+ `;
57
+ }
58
+
59
+ if (regions.includes('california')) {
60
+ section += `
61
+ ### California Privacy Rights (CCPA/CPRA)
62
+
63
+ California residents have additional rights regarding personal information collected through AI shopping agents:
64
+ - **Right to Know**: You may request details about the personal information we collect and share
65
+ - **Right to Delete**: You may request deletion of your personal information, subject to certain exceptions
66
+ - **Right to Opt-Out**: You may opt out of the "sale" or "sharing" of personal information
67
+ - **Right to Non-Discrimination**: We will not discriminate against you for exercising your privacy rights
68
+
69
+ To exercise these rights, contact us at the email address provided below.
70
+ `;
71
+ }
72
+
73
+ return section;
74
+ }
75
+
76
+ /**
77
+ * Generate data processor disclosures
78
+ */
79
+ export function generateProcessorDisclosures(
80
+ processors: DataProcessor[],
81
+ regions: ComplianceRegion[]
82
+ ): string {
83
+ let disclosure = `## Third-Party Data Processors (AI Commerce)
84
+
85
+ We work with the following third-party service providers to enable AI-powered shopping:
86
+
87
+ | Provider | Purpose | Location | Privacy Policy |
88
+ |----------|---------|----------|----------------|
89
+ `;
90
+
91
+ for (const processor of processors) {
92
+ const privacyLink = processor.privacyPolicyUrl
93
+ ? `[View Policy](${processor.privacyPolicyUrl})`
94
+ : 'Contact provider';
95
+ disclosure += `| ${processor.name} | ${processor.purpose} | ${processor.country || 'Various'} | ${privacyLink} |\n`;
96
+ }
97
+
98
+ disclosure += `
99
+ These processors are contractually bound to:
100
+ - Process data only on our documented instructions
101
+ - Ensure appropriate security measures are in place
102
+ - Assist us in responding to data subject requests
103
+ - Delete or return all personal data at the end of the service relationship
104
+ `;
105
+
106
+ if (regions.includes('eu') || regions.includes('uk')) {
107
+ disclosure += `
108
+ All processors have entered into Data Processing Agreements (DPAs) that comply with Article 28 of the GDPR.
109
+ `;
110
+ }
111
+
112
+ return disclosure;
113
+ }
114
+
115
+ /**
116
+ * Generate consent language for checkout
117
+ */
118
+ export function generateConsentLanguage(
119
+ companyName: string,
120
+ lawfulBasis: LawfulBasis,
121
+ includeMarketing: boolean
122
+ ): string {
123
+ let consent = `## Consent Language for AI-Assisted Checkout
124
+
125
+ Use the following language at checkout or in order confirmations:
126
+
127
+ ### Order Processing Consent
128
+
129
+ > By completing this purchase through an AI shopping assistant, you acknowledge that:
130
+ > - Your order information will be processed by ${companyName} and the AI platform provider
131
+ > - We will use your data to fulfill your order, process payment, and provide customer support
132
+ > - Your data will be handled in accordance with our Privacy Policy
133
+ `;
134
+
135
+ if (lawfulBasis === 'consent') {
136
+ consent += `
137
+ ### Explicit Consent (for consent-based processing)
138
+
139
+ > [ ] I consent to ${companyName} processing my personal data for the purpose of completing this purchase and providing related services. I understand I can withdraw my consent at any time.
140
+ `;
141
+ }
142
+
143
+ if (includeMarketing) {
144
+ consent += `
145
+ ### Marketing Consent (Optional)
146
+
147
+ > [ ] I would like to receive marketing communications from ${companyName} about products, offers, and updates. I understand I can unsubscribe at any time.
148
+
149
+ **Note**: Marketing consent must be:
150
+ - Freely given (not a condition of purchase)
151
+ - Specific and informed
152
+ - Indicated by clear affirmative action (pre-ticked boxes are not valid consent)
153
+ `;
154
+ }
155
+
156
+ consent += `
157
+ ### Agent-Originated Orders Notice
158
+
159
+ > This order was initiated through an AI shopping assistant. The AI platform may retain conversation history in accordance with their privacy policy. Your transaction data with ${companyName} is subject to our Privacy Policy.
160
+ `;
161
+
162
+ return consent;
163
+ }
164
+
165
+ /**
166
+ * Generate marketing opt-in text
167
+ */
168
+ export function generateMarketingOptIn(companyName: string): string {
169
+ return `## Marketing Opt-In for Agent-Acquired Customers
170
+
171
+ For customers acquired through AI shopping agents, use the following opt-in language:
172
+
173
+ ### Email Opt-In
174
+
175
+ > [ ] Yes, I'd like to receive emails from ${companyName} about new products, exclusive offers, and updates. I can unsubscribe anytime using the link in each email.
176
+
177
+ ### SMS Opt-In (if applicable)
178
+
179
+ > [ ] Yes, send me SMS updates about my orders and occasional promotions from ${companyName}. Message frequency varies. Reply STOP to unsubscribe. Message and data rates may apply.
180
+
181
+ ### Post-Purchase Marketing Request
182
+
183
+ For customers who made purchases via AI agents without opting in, you may send ONE transactional follow-up:
184
+
185
+ > Thank you for your recent purchase through [AI Agent Name]! Would you like to receive updates about new products and exclusive offers from ${companyName}?
186
+ >
187
+ > [Subscribe to Updates] [No Thanks]
188
+
189
+ **Important**: Do not add customers to marketing lists without explicit consent. Agent-originated orders do not imply marketing permission.
190
+ `;
191
+ }
192
+
193
+ /**
194
+ * Generate data subject rights notice
195
+ */
196
+ export function generateDataSubjectRights(
197
+ companyName: string,
198
+ contactEmail: string,
199
+ dpoEmail: string | undefined,
200
+ regions: ComplianceRegion[]
201
+ ): string {
202
+ let rights = `## Your Data Rights (AI Commerce Transactions)
203
+
204
+ You have the following rights regarding personal data collected through AI-assisted purchases:
205
+
206
+ ### Access and Portability
207
+ - Request a copy of your personal data
208
+ - Receive your data in a portable, machine-readable format
209
+
210
+ ### Correction and Deletion
211
+ - Request correction of inaccurate data
212
+ - Request deletion of your data (subject to legal retention requirements)
213
+
214
+ ### Objection and Restriction
215
+ - Object to processing based on legitimate interests
216
+ - Request restriction of processing in certain circumstances
217
+ `;
218
+
219
+ if (regions.includes('eu') || regions.includes('uk')) {
220
+ rights += `
221
+ ### GDPR-Specific Rights
222
+ - **Right to be Forgotten**: Request erasure under Article 17
223
+ - **Right to Restrict Processing**: Under Article 18
224
+ - **Right to Data Portability**: Under Article 20
225
+ - **Right to Object**: Under Article 21
226
+ - **Lodge a Complaint**: With your local data protection authority
227
+ `;
228
+ }
229
+
230
+ if (regions.includes('california')) {
231
+ rights += `
232
+ ### CCPA/CPRA Rights
233
+ - **Right to Know**: Categories and specific pieces of personal information collected
234
+ - **Right to Delete**: Request deletion of personal information
235
+ - **Right to Correct**: Request correction of inaccurate information
236
+ - **Right to Opt-Out**: Of sale or sharing of personal information
237
+ - **Right to Limit Use**: Of sensitive personal information
238
+ `;
239
+ }
240
+
241
+ rights += `
242
+ ### How to Exercise Your Rights
243
+
244
+ To exercise any of these rights, contact us:
245
+ - **Email**: ${contactEmail}
246
+ ${dpoEmail ? `- **Data Protection Officer**: ${dpoEmail}` : ''}
247
+
248
+ We will respond to your request within:
249
+ ${regions.includes('eu') || regions.includes('uk') ? '- **EU/UK**: 30 days (extendable by 60 days for complex requests)' : ''}
250
+ ${regions.includes('california') ? '- **California**: 45 days (extendable by 45 days if necessary)' : ''}
251
+
252
+ ### Verification
253
+
254
+ To protect your privacy, we may need to verify your identity before processing your request. For orders placed through AI agents, we may ask for:
255
+ - Order number or transaction ID
256
+ - Email address used for the order
257
+ - Delivery address associated with the order
258
+ `;
259
+
260
+ return rights;
261
+ }
262
+
263
+ /**
264
+ * Generate tracking/cookie notice for agent transactions
265
+ */
266
+ export function generateTrackingNotice(
267
+ companyName: string,
268
+ regions: ComplianceRegion[]
269
+ ): string {
270
+ let notice = `## Tracking and Cookies for AI Agent Transactions
271
+
272
+ ### How Tracking Works with AI Agents
273
+
274
+ When you make a purchase through an AI shopping agent, the traditional cookie-based tracking model does not apply because:
275
+ - You may never visit our website directly
276
+ - The transaction occurs within the AI agent's interface
277
+ - Standard cookie consent banners do not load
278
+
279
+ ### What Data is Collected
280
+
281
+ For AI agent transactions, we collect data through:
282
+ - **API Calls**: Order data transmitted via Universal Commerce Protocol (UCP)
283
+ - **Transaction Logs**: Records of purchases for fulfillment and support
284
+ - **Analytics**: Aggregated, anonymized data about AI agent sales (not linked to individuals)
285
+
286
+ ### Our Commitment
287
+
288
+ - We do **not** place cookies on your device through AI agent transactions
289
+ - We do **not** build behavioral profiles based solely on AI agent purchases
290
+ - We **do** collect necessary transaction data to fulfill your order
291
+ `;
292
+
293
+ if (regions.includes('eu') || regions.includes('uk')) {
294
+ notice += `
295
+ ### ePrivacy Compliance
296
+
297
+ AI agent transactions are processed under:
298
+ - **Strictly Necessary**: Processing required to complete your requested transaction
299
+ - **Contract Performance**: Data processing necessary to deliver your order
300
+
301
+ No consent is required for strictly necessary processing of transaction data.
302
+ `;
303
+ }
304
+
305
+ notice += `
306
+ ### AI Platform Tracking
307
+
308
+ The AI shopping agent (ChatGPT, Google AI, Copilot) may have its own data collection practices. Please review their privacy policies:
309
+ - Conversation history with the AI agent
310
+ - Usage data collected by the AI platform
311
+ - Account information you've provided to the AI service
312
+
313
+ ${companyName} is not responsible for data collected directly by AI platform providers.
314
+ `;
315
+
316
+ return notice;
317
+ }
318
+
319
+ /**
320
+ * Generate the legal disclaimer
321
+ */
322
+ export function generateDisclaimer(): string {
323
+ return `---
324
+
325
+ **IMPORTANT DISCLAIMER**
326
+
327
+ This document was generated by an automated tool and is provided for informational purposes only. It does NOT constitute legal advice.
328
+
329
+ - This template should be reviewed by a qualified legal professional before use
330
+ - Privacy laws vary by jurisdiction and change frequently
331
+ - Your specific business circumstances may require additional or different provisions
332
+ - ${new Date().getFullYear()} compliance requirements may have changed since generation
333
+
334
+ We recommend consulting with a privacy lawyer or data protection specialist to ensure your privacy policy fully complies with applicable laws.
335
+
336
+ Generated by [UCP.tools](https://ucptools.dev) - AI Commerce Readiness Platform
337
+ `;
338
+ }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * GDPR/Privacy Compliance Generator Types
3
+ * Types for generating privacy policy addendums and consent language
4
+ */
5
+
6
+ // Supported regions/jurisdictions
7
+ export type ComplianceRegion = 'eu' | 'uk' | 'california' | 'global';
8
+
9
+ // GDPR Article 6 lawful bases
10
+ export type LawfulBasis =
11
+ | 'contract' // Performance of a contract
12
+ | 'consent' // Consent
13
+ | 'legitimate' // Legitimate interests
14
+ | 'legal'; // Legal obligation
15
+
16
+ // AI agent platforms
17
+ export type AgentPlatform =
18
+ | 'openai' // ChatGPT Shopping
19
+ | 'google' // Google AI Mode / Gemini
20
+ | 'microsoft' // Microsoft Copilot
21
+ | 'other';
22
+
23
+ // Input options for compliance generator
24
+ export interface ComplianceGeneratorInput {
25
+ // Company information
26
+ companyName: string;
27
+ companyEmail?: string;
28
+ companyAddress?: string;
29
+ dpoEmail?: string; // Data Protection Officer email
30
+
31
+ // Regions to comply with
32
+ regions: ComplianceRegion[];
33
+
34
+ // AI platforms being used
35
+ platforms: AgentPlatform[];
36
+
37
+ // Lawful basis for processing
38
+ lawfulBasis: LawfulBasis;
39
+
40
+ // Optional features
41
+ includeMarketingConsent?: boolean;
42
+ includeDataRetention?: boolean;
43
+ retentionPeriodYears?: number;
44
+
45
+ // Custom data processors
46
+ additionalProcessors?: DataProcessor[];
47
+ }
48
+
49
+ // Data processor information
50
+ export interface DataProcessor {
51
+ name: string;
52
+ purpose: string;
53
+ country?: string;
54
+ privacyPolicyUrl?: string;
55
+ }
56
+
57
+ // Generated compliance document
58
+ export interface ComplianceDocument {
59
+ title: string;
60
+ sections: ComplianceSection[];
61
+ disclaimer: string;
62
+ generatedAt: string;
63
+ regions: ComplianceRegion[];
64
+ }
65
+
66
+ // Section of a compliance document
67
+ export interface ComplianceSection {
68
+ id: string;
69
+ title: string;
70
+ content: string;
71
+ required: boolean;
72
+ applicableRegions: ComplianceRegion[];
73
+ }
74
+
75
+ // Complete generator output
76
+ export interface ComplianceGeneratorOutput {
77
+ // Full privacy policy addendum
78
+ privacyAddendum: ComplianceDocument;
79
+
80
+ // Individual snippets for easy copy/paste
81
+ snippets: {
82
+ // Privacy policy section for AI commerce
83
+ aiCommerceSection: string;
84
+
85
+ // Data processor disclosures
86
+ processorDisclosures: string;
87
+
88
+ // Consent language for checkout
89
+ consentLanguage: string;
90
+
91
+ // Marketing opt-in text
92
+ marketingOptIn?: string;
93
+
94
+ // Data subject rights notice
95
+ dataSubjectRights: string;
96
+
97
+ // Cookie/tracking notice for agent transactions
98
+ trackingNotice: string;
99
+ };
100
+
101
+ // Combined HTML for embedding
102
+ embedHtml: string;
103
+
104
+ // Plain text version
105
+ plainText: string;
106
+
107
+ // Metadata
108
+ generatedAt: string;
109
+ lawfulBasis: LawfulBasis;
110
+ regions: ComplianceRegion[];
111
+ }
112
+
113
+ // Predefined data processors for AI platforms
114
+ export const AI_PLATFORM_PROCESSORS: Record<AgentPlatform, DataProcessor> = {
115
+ openai: {
116
+ name: 'OpenAI, LLC',
117
+ purpose: 'AI-powered shopping assistant and checkout processing',
118
+ country: 'United States',
119
+ privacyPolicyUrl: 'https://openai.com/privacy/',
120
+ },
121
+ google: {
122
+ name: 'Google LLC',
123
+ purpose: 'AI shopping agent (Google AI Mode, Gemini) and checkout processing',
124
+ country: 'United States',
125
+ privacyPolicyUrl: 'https://policies.google.com/privacy',
126
+ },
127
+ microsoft: {
128
+ name: 'Microsoft Corporation',
129
+ purpose: 'AI shopping assistant (Copilot) and checkout processing',
130
+ country: 'United States',
131
+ privacyPolicyUrl: 'https://privacy.microsoft.com/privacystatement',
132
+ },
133
+ other: {
134
+ name: 'Third-party AI Agent Provider',
135
+ purpose: 'AI-powered shopping and checkout assistance',
136
+ country: 'Various',
137
+ },
138
+ };
139
+
140
+ // Region display names
141
+ export const REGION_NAMES: Record<ComplianceRegion, string> = {
142
+ eu: 'European Union (GDPR)',
143
+ uk: 'United Kingdom (UK GDPR)',
144
+ california: 'California (CCPA/CPRA)',
145
+ global: 'Global (General Best Practices)',
146
+ };
147
+
148
+ // Lawful basis descriptions
149
+ export const LAWFUL_BASIS_DESCRIPTIONS: Record<LawfulBasis, { title: string; description: string; gdprArticle: string }> = {
150
+ contract: {
151
+ title: 'Performance of a Contract',
152
+ description: 'Processing is necessary for the performance of a contract with the data subject or to take steps at their request prior to entering into a contract.',
153
+ gdprArticle: 'Article 6(1)(b)',
154
+ },
155
+ consent: {
156
+ title: 'Consent',
157
+ description: 'The data subject has given consent to the processing of their personal data for one or more specific purposes.',
158
+ gdprArticle: 'Article 6(1)(a)',
159
+ },
160
+ legitimate: {
161
+ title: 'Legitimate Interests',
162
+ description: 'Processing is necessary for the purposes of the legitimate interests pursued by the controller or by a third party.',
163
+ gdprArticle: 'Article 6(1)(f)',
164
+ },
165
+ legal: {
166
+ title: 'Legal Obligation',
167
+ description: 'Processing is necessary for compliance with a legal obligation to which the controller is subject.',
168
+ gdprArticle: 'Article 6(1)(c)',
169
+ },
170
+ };
@@ -0,0 +1,28 @@
1
+ import { drizzle, NeonHttpDatabase } from 'drizzle-orm/neon-http';
2
+ import { neon } from '@neondatabase/serverless';
3
+ import * as schema from './schema.js';
4
+
5
+ // Type for our database instance
6
+ type Database = NeonHttpDatabase<typeof schema>;
7
+
8
+ // Lazy-loaded database instance (for serverless cold starts)
9
+ let dbInstance: Database | null = null;
10
+
11
+ /**
12
+ * Get the Drizzle database instance.
13
+ * Lazily creates the connection on first use.
14
+ */
15
+ export function getDb(): Database {
16
+ if (!dbInstance) {
17
+ if (!process.env.DATABASE_URL) {
18
+ throw new Error('DATABASE_URL environment variable is not set');
19
+ }
20
+ const sql = neon(process.env.DATABASE_URL);
21
+ dbInstance = drizzle(sql, { schema });
22
+ }
23
+ return dbInstance;
24
+ }
25
+
26
+ // Re-export schema for convenience
27
+ export * from './schema.js';
28
+ export { schema };
@@ -0,0 +1,84 @@
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;