@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.
- package/CLAUDE.md +109 -0
- package/CONTRIBUTING.md +113 -0
- package/LICENSE +21 -0
- package/README.md +203 -0
- package/api/analyze-feed.js +140 -0
- package/api/badge.js +185 -0
- package/api/benchmark.js +177 -0
- package/api/directory-stats.ts +29 -0
- package/api/directory.ts +73 -0
- package/api/generate-compliance.js +143 -0
- package/api/generate-schema.js +457 -0
- package/api/generate.js +132 -0
- package/api/security-scan.js +133 -0
- package/api/simulate.js +187 -0
- package/api/tsconfig.json +10 -0
- package/api/validate.js +1351 -0
- package/apify-actor/.actor/actor.json +68 -0
- package/apify-actor/.actor/input_schema.json +32 -0
- package/apify-actor/APIFY-STORE-LISTING.md +412 -0
- package/apify-actor/Dockerfile +8 -0
- package/apify-actor/README.md +166 -0
- package/apify-actor/main.ts +111 -0
- package/apify-actor/package.json +17 -0
- package/apify-actor/src/main.js +199 -0
- package/docs/BRAND-IDENTITY.md +238 -0
- package/docs/BRAND-STYLE-GUIDE.md +356 -0
- package/drizzle/0000_black_king_cobra.sql +39 -0
- package/drizzle/meta/0000_snapshot.json +309 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +10 -0
- package/examples/full-profile.json +70 -0
- package/examples/minimal-profile.json +23 -0
- package/package.json +69 -0
- package/public/.well-known/ucp +25 -0
- 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 +321 -0
- package/public/directory.html +701 -0
- 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 +743 -0
- package/public/guides/fastucp.html +838 -0
- package/public/guides/magento.html +779 -0
- package/public/guides/shopify.html +726 -0
- package/public/guides/squarespace.html +749 -0
- package/public/guides/wix.html +747 -0
- package/public/guides/woocommerce.html +733 -0
- package/public/index.html +3835 -0
- package/public/learn.html +396 -0
- 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 +6 -0
- package/public/site.webmanifest +31 -0
- package/public/sitemap.xml +69 -0
- 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 +410 -0
- package/scripts/generate-favicons.js +44 -0
- package/scripts/generate-ico.js +23 -0
- package/scripts/generate-og-image.js +45 -0
- package/scripts/reset-db.ts +77 -0
- package/scripts/seed-db.ts +71 -0
- package/scripts/setup-benchmark-db.js +70 -0
- package/src/api/server.ts +266 -0
- package/src/cli/index.ts +302 -0
- package/src/compliance/compliance-generator.ts +452 -0
- package/src/compliance/index.ts +28 -0
- package/src/compliance/templates.ts +338 -0
- package/src/compliance/types.ts +170 -0
- package/src/db/index.ts +28 -0
- package/src/db/schema.ts +84 -0
- package/src/feed-analyzer/feed-analyzer.ts +726 -0
- package/src/feed-analyzer/index.ts +34 -0
- package/src/feed-analyzer/types.ts +354 -0
- package/src/generator/index.ts +7 -0
- package/src/generator/key-generator.ts +124 -0
- package/src/generator/profile-builder.ts +402 -0
- package/src/hosting/artifacts-generator.ts +679 -0
- package/src/hosting/index.ts +6 -0
- package/src/index.ts +105 -0
- package/src/security/index.ts +15 -0
- package/src/security/security-scanner.ts +604 -0
- package/src/security/types.ts +55 -0
- package/src/services/directory.ts +434 -0
- package/src/simulator/agent-simulator.ts +941 -0
- package/src/simulator/index.ts +7 -0
- package/src/simulator/types.ts +170 -0
- package/src/types/generator.ts +140 -0
- package/src/types/index.ts +7 -0
- package/src/types/ucp-profile.ts +140 -0
- package/src/types/validation.ts +89 -0
- package/src/validator/index.ts +194 -0
- package/src/validator/network-validator.ts +417 -0
- package/src/validator/rules-validator.ts +297 -0
- package/src/validator/sdk-validator.ts +330 -0
- package/src/validator/structural-validator.ts +476 -0
- package/tests/fixtures/non-compliant-profile.json +25 -0
- package/tests/fixtures/official-sample-profile.json +75 -0
- package/tests/integration/benchmark.test.ts +207 -0
- package/tests/integration/database.test.ts +163 -0
- package/tests/integration/directory-api.test.ts +268 -0
- package/tests/integration/simulate-api.test.ts +230 -0
- package/tests/integration/validate-api.test.ts +269 -0
- package/tests/setup.ts +15 -0
- package/tests/unit/agent-simulator.test.ts +575 -0
- package/tests/unit/compliance-generator.test.ts +374 -0
- package/tests/unit/directory-service.test.ts +272 -0
- package/tests/unit/feed-analyzer.test.ts +517 -0
- package/tests/unit/lint-suggestions.test.ts +423 -0
- package/tests/unit/official-samples.test.ts +211 -0
- package/tests/unit/pdf-report.test.ts +390 -0
- package/tests/unit/sdk-validator.test.ts +531 -0
- package/tests/unit/security-scanner.test.ts +410 -0
- package/tests/unit/validation.test.ts +390 -0
- package/tsconfig.json +20 -0
- package/vercel.json +34 -0
- 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
|
+
};
|
package/src/db/index.ts
ADDED
|
@@ -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 };
|
package/src/db/schema.ts
ADDED
|
@@ -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;
|