@ucptools/validator 1.0.0 → 1.0.1

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 (236) hide show
  1. package/.claude/settings.local.json +60 -0
  2. package/.vercel/README.txt +11 -0
  3. package/.vercel/project.json +1 -0
  4. package/dist/cli/index.d.ts +6 -0
  5. package/dist/cli/index.d.ts.map +1 -0
  6. package/dist/cli/index.js +279 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/compliance/compliance-generator.d.ts +34 -0
  9. package/dist/compliance/compliance-generator.d.ts.map +1 -0
  10. package/dist/compliance/compliance-generator.js +320 -0
  11. package/dist/compliance/compliance-generator.js.map +1 -0
  12. package/dist/compliance/index.d.ts +8 -0
  13. package/dist/compliance/index.d.ts.map +1 -0
  14. package/dist/compliance/index.js +17 -0
  15. package/dist/compliance/index.js.map +1 -0
  16. package/dist/compliance/templates.d.ts +34 -0
  17. package/dist/compliance/templates.d.ts.map +1 -0
  18. package/{src/compliance/templates.ts → dist/compliance/templates.js} +117 -155
  19. package/dist/compliance/templates.js.map +1 -0
  20. package/dist/compliance/types.d.ts +64 -0
  21. package/dist/compliance/types.d.ts.map +1 -0
  22. package/dist/compliance/types.js +64 -0
  23. package/dist/compliance/types.js.map +1 -0
  24. package/dist/db/index.d.ts +11 -0
  25. package/dist/db/index.d.ts.map +1 -0
  26. package/dist/db/index.js +63 -0
  27. package/dist/db/index.js.map +1 -0
  28. package/dist/db/schema.d.ts +444 -0
  29. package/dist/db/schema.d.ts.map +1 -0
  30. package/dist/db/schema.js +65 -0
  31. package/dist/db/schema.js.map +1 -0
  32. package/dist/feed-analyzer/feed-analyzer.d.ts +26 -0
  33. package/dist/feed-analyzer/feed-analyzer.d.ts.map +1 -0
  34. package/{src/feed-analyzer/feed-analyzer.ts → dist/feed-analyzer/feed-analyzer.js} +642 -726
  35. package/dist/feed-analyzer/feed-analyzer.js.map +1 -0
  36. package/dist/feed-analyzer/index.d.ts +8 -0
  37. package/dist/feed-analyzer/index.d.ts.map +1 -0
  38. package/dist/feed-analyzer/index.js +19 -0
  39. package/dist/feed-analyzer/index.js.map +1 -0
  40. package/dist/feed-analyzer/types.d.ts +204 -0
  41. package/dist/feed-analyzer/types.d.ts.map +1 -0
  42. package/dist/feed-analyzer/types.js +162 -0
  43. package/dist/feed-analyzer/types.js.map +1 -0
  44. package/{src/generator/index.ts → dist/generator/index.d.ts} +1 -1
  45. package/dist/generator/index.d.ts.map +1 -0
  46. package/dist/generator/index.js +13 -0
  47. package/dist/generator/index.js.map +1 -0
  48. package/dist/generator/key-generator.d.ts +24 -0
  49. package/dist/generator/key-generator.d.ts.map +1 -0
  50. package/dist/generator/key-generator.js +144 -0
  51. package/dist/generator/key-generator.js.map +1 -0
  52. package/dist/generator/profile-builder.d.ts +15 -0
  53. package/dist/generator/profile-builder.d.ts.map +1 -0
  54. package/dist/generator/profile-builder.js +338 -0
  55. package/dist/generator/profile-builder.js.map +1 -0
  56. package/dist/hosting/artifacts-generator.d.ts +10 -0
  57. package/dist/hosting/artifacts-generator.d.ts.map +1 -0
  58. package/{src/hosting/artifacts-generator.ts → dist/hosting/artifacts-generator.js} +191 -241
  59. package/dist/hosting/artifacts-generator.js.map +1 -0
  60. package/{src/hosting/index.ts → dist/hosting/index.d.ts} +1 -1
  61. package/dist/hosting/index.d.ts.map +1 -0
  62. package/dist/hosting/index.js +10 -0
  63. package/dist/hosting/index.js.map +1 -0
  64. package/dist/index.d.ts +18 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +78 -0
  67. package/dist/index.js.map +1 -0
  68. package/{src/security/index.ts → dist/security/index.d.ts} +8 -15
  69. package/dist/security/index.d.ts.map +1 -0
  70. package/dist/security/index.js +12 -0
  71. package/dist/security/index.js.map +1 -0
  72. package/dist/security/security-scanner.d.ts +10 -0
  73. package/dist/security/security-scanner.d.ts.map +1 -0
  74. package/dist/security/security-scanner.js +541 -0
  75. package/dist/security/security-scanner.js.map +1 -0
  76. package/dist/security/types.d.ts +48 -0
  77. package/dist/security/types.d.ts.map +1 -0
  78. package/dist/security/types.js +21 -0
  79. package/dist/security/types.js.map +1 -0
  80. package/dist/services/directory.d.ts +104 -0
  81. package/dist/services/directory.d.ts.map +1 -0
  82. package/dist/services/directory.js +333 -0
  83. package/dist/services/directory.js.map +1 -0
  84. package/dist/simulator/agent-simulator.d.ts +69 -0
  85. package/dist/simulator/agent-simulator.d.ts.map +1 -0
  86. package/{src/simulator/agent-simulator.ts → dist/simulator/agent-simulator.js} +650 -941
  87. package/dist/simulator/agent-simulator.js.map +1 -0
  88. package/{src/simulator/index.ts → dist/simulator/index.d.ts} +7 -7
  89. package/dist/simulator/index.d.ts.map +1 -0
  90. package/dist/simulator/index.js +23 -0
  91. package/dist/simulator/index.js.map +1 -0
  92. package/{src/simulator/types.ts → dist/simulator/types.d.ts} +145 -170
  93. package/dist/simulator/types.d.ts.map +1 -0
  94. package/dist/simulator/types.js +18 -0
  95. package/dist/simulator/types.js.map +1 -0
  96. package/dist/types/generator.d.ts +106 -0
  97. package/dist/types/generator.d.ts.map +1 -0
  98. package/dist/types/generator.js +6 -0
  99. package/dist/types/generator.js.map +1 -0
  100. package/{src/types/index.ts → dist/types/index.d.ts} +1 -1
  101. package/dist/types/index.d.ts.map +1 -0
  102. package/dist/types/index.js +23 -0
  103. package/dist/types/index.js.map +1 -0
  104. package/dist/types/ucp-profile.d.ts +103 -0
  105. package/dist/types/ucp-profile.d.ts.map +1 -0
  106. package/dist/types/ucp-profile.js +45 -0
  107. package/dist/types/ucp-profile.js.map +1 -0
  108. package/dist/types/validation.d.ts +68 -0
  109. package/dist/types/validation.d.ts.map +1 -0
  110. package/dist/types/validation.js +32 -0
  111. package/dist/types/validation.js.map +1 -0
  112. package/dist/validator/index.d.ts +26 -0
  113. package/dist/validator/index.d.ts.map +1 -0
  114. package/dist/validator/index.js +161 -0
  115. package/dist/validator/index.js.map +1 -0
  116. package/dist/validator/network-validator.d.ts +28 -0
  117. package/dist/validator/network-validator.d.ts.map +1 -0
  118. package/dist/validator/network-validator.js +319 -0
  119. package/dist/validator/network-validator.js.map +1 -0
  120. package/dist/validator/rules-validator.d.ts +11 -0
  121. package/dist/validator/rules-validator.d.ts.map +1 -0
  122. package/dist/validator/rules-validator.js +257 -0
  123. package/dist/validator/rules-validator.js.map +1 -0
  124. package/dist/validator/sdk-validator.d.ts +58 -0
  125. package/dist/validator/sdk-validator.d.ts.map +1 -0
  126. package/{src/validator/sdk-validator.ts → dist/validator/sdk-validator.js} +273 -330
  127. package/dist/validator/sdk-validator.js.map +1 -0
  128. package/dist/validator/structural-validator.d.ts +11 -0
  129. package/dist/validator/structural-validator.d.ts.map +1 -0
  130. package/dist/validator/structural-validator.js +415 -0
  131. package/dist/validator/structural-validator.js.map +1 -0
  132. package/package.json +1 -1
  133. package/publish-output.txt +0 -0
  134. package/CLAUDE.md +0 -109
  135. package/api/analyze-feed.js +0 -140
  136. package/api/badge.js +0 -185
  137. package/api/benchmark.js +0 -177
  138. package/api/directory-stats.ts +0 -29
  139. package/api/directory.ts +0 -73
  140. package/api/generate-compliance.js +0 -143
  141. package/api/generate-schema.js +0 -457
  142. package/api/generate.js +0 -132
  143. package/api/security-scan.js +0 -133
  144. package/api/simulate.js +0 -187
  145. package/api/tsconfig.json +0 -10
  146. package/api/validate.js +0 -1351
  147. package/apify-actor/.actor/actor.json +0 -68
  148. package/apify-actor/.actor/input_schema.json +0 -32
  149. package/apify-actor/APIFY-STORE-LISTING.md +0 -412
  150. package/apify-actor/Dockerfile +0 -8
  151. package/apify-actor/README.md +0 -166
  152. package/apify-actor/main.ts +0 -111
  153. package/apify-actor/package.json +0 -17
  154. package/apify-actor/src/main.js +0 -199
  155. package/docs/BRAND-IDENTITY.md +0 -238
  156. package/docs/BRAND-STYLE-GUIDE.md +0 -356
  157. package/drizzle/0000_black_king_cobra.sql +0 -39
  158. package/drizzle/meta/0000_snapshot.json +0 -309
  159. package/drizzle/meta/_journal.json +0 -13
  160. package/drizzle.config.ts +0 -10
  161. package/public/.well-known/ucp +0 -25
  162. package/public/android-chrome-192x192.png +0 -0
  163. package/public/android-chrome-512x512.png +0 -0
  164. package/public/apple-touch-icon.png +0 -0
  165. package/public/brand.css +0 -321
  166. package/public/directory.html +0 -701
  167. package/public/favicon-16x16.png +0 -0
  168. package/public/favicon-32x32.png +0 -0
  169. package/public/favicon.ico +0 -0
  170. package/public/guides/bigcommerce.html +0 -743
  171. package/public/guides/fastucp.html +0 -838
  172. package/public/guides/magento.html +0 -779
  173. package/public/guides/shopify.html +0 -726
  174. package/public/guides/squarespace.html +0 -749
  175. package/public/guides/wix.html +0 -747
  176. package/public/guides/woocommerce.html +0 -733
  177. package/public/index.html +0 -3835
  178. package/public/learn.html +0 -396
  179. package/public/logo.jpeg +0 -0
  180. package/public/og-image-icon.png +0 -0
  181. package/public/og-image.png +0 -0
  182. package/public/robots.txt +0 -6
  183. package/public/site.webmanifest +0 -31
  184. package/public/sitemap.xml +0 -69
  185. package/public/social/linkedin-banner-1128x191.png +0 -0
  186. package/public/social/temp.PNG +0 -0
  187. package/public/social/x-header-1500x500.png +0 -0
  188. package/public/verify.html +0 -410
  189. package/scripts/generate-favicons.js +0 -44
  190. package/scripts/generate-ico.js +0 -23
  191. package/scripts/generate-og-image.js +0 -45
  192. package/scripts/reset-db.ts +0 -77
  193. package/scripts/seed-db.ts +0 -71
  194. package/scripts/setup-benchmark-db.js +0 -70
  195. package/src/api/server.ts +0 -266
  196. package/src/cli/index.ts +0 -302
  197. package/src/compliance/compliance-generator.ts +0 -452
  198. package/src/compliance/index.ts +0 -28
  199. package/src/compliance/types.ts +0 -170
  200. package/src/db/index.ts +0 -28
  201. package/src/db/schema.ts +0 -84
  202. package/src/feed-analyzer/index.ts +0 -34
  203. package/src/feed-analyzer/types.ts +0 -354
  204. package/src/generator/key-generator.ts +0 -124
  205. package/src/generator/profile-builder.ts +0 -402
  206. package/src/index.ts +0 -105
  207. package/src/security/security-scanner.ts +0 -604
  208. package/src/security/types.ts +0 -55
  209. package/src/services/directory.ts +0 -434
  210. package/src/types/generator.ts +0 -140
  211. package/src/types/ucp-profile.ts +0 -140
  212. package/src/types/validation.ts +0 -89
  213. package/src/validator/index.ts +0 -194
  214. package/src/validator/network-validator.ts +0 -417
  215. package/src/validator/rules-validator.ts +0 -297
  216. package/src/validator/structural-validator.ts +0 -476
  217. package/tests/fixtures/non-compliant-profile.json +0 -25
  218. package/tests/fixtures/official-sample-profile.json +0 -75
  219. package/tests/integration/benchmark.test.ts +0 -207
  220. package/tests/integration/database.test.ts +0 -163
  221. package/tests/integration/directory-api.test.ts +0 -268
  222. package/tests/integration/simulate-api.test.ts +0 -230
  223. package/tests/integration/validate-api.test.ts +0 -269
  224. package/tests/setup.ts +0 -15
  225. package/tests/unit/agent-simulator.test.ts +0 -575
  226. package/tests/unit/compliance-generator.test.ts +0 -374
  227. package/tests/unit/directory-service.test.ts +0 -272
  228. package/tests/unit/feed-analyzer.test.ts +0 -517
  229. package/tests/unit/lint-suggestions.test.ts +0 -423
  230. package/tests/unit/official-samples.test.ts +0 -211
  231. package/tests/unit/pdf-report.test.ts +0 -390
  232. package/tests/unit/sdk-validator.test.ts +0 -531
  233. package/tests/unit/security-scanner.test.ts +0 -410
  234. package/tests/unit/validation.test.ts +0 -390
  235. package/vercel.json +0 -34
  236. package/vitest.config.ts +0 -22
@@ -1,143 +0,0 @@
1
- /**
2
- * Vercel Serverless Function: GDPR/Privacy Compliance Generator
3
- * POST /api/generate-compliance
4
- *
5
- * Generates privacy policy addendums and consent language for agentic commerce.
6
- *
7
- * Request body:
8
- * {
9
- * "companyName": "Your Company",
10
- * "companyEmail": "privacy@example.com",
11
- * "dpoEmail": "dpo@example.com",
12
- * "regions": ["eu", "uk", "california"],
13
- * "platforms": ["openai", "google"],
14
- * "lawfulBasis": "contract",
15
- * "includeMarketingConsent": true,
16
- * "includeDataRetention": true,
17
- * "retentionPeriodYears": 7
18
- * }
19
- *
20
- * GET /api/generate-compliance
21
- * Returns available options for regions, platforms, and lawful bases.
22
- */
23
-
24
- export default async function handler(req, res) {
25
- // Handle CORS
26
- res.setHeader('Access-Control-Allow-Origin', '*');
27
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
28
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
29
-
30
- if (req.method === 'OPTIONS') {
31
- return res.status(200).end();
32
- }
33
-
34
- // GET: Return available options
35
- if (req.method === 'GET') {
36
- try {
37
- const {
38
- getAvailableRegions,
39
- getLawfulBasisOptions,
40
- getAiPlatformOptions,
41
- } = await import('../src/compliance/index.js');
42
-
43
- return res.status(200).json({
44
- success: true,
45
- options: {
46
- regions: getAvailableRegions(),
47
- lawfulBases: getLawfulBasisOptions(),
48
- platforms: getAiPlatformOptions(),
49
- },
50
- });
51
- } catch (error) {
52
- console.error('Error getting options:', error);
53
- return res.status(500).json({
54
- error: 'Failed to get options',
55
- message: error.message,
56
- });
57
- }
58
- }
59
-
60
- // POST: Generate compliance documents
61
- if (req.method === 'POST') {
62
- try {
63
- const {
64
- companyName,
65
- companyEmail,
66
- companyAddress,
67
- dpoEmail,
68
- regions,
69
- platforms,
70
- lawfulBasis,
71
- includeMarketingConsent,
72
- includeDataRetention,
73
- retentionPeriodYears,
74
- additionalProcessors,
75
- } = req.body || {};
76
-
77
- // Validate required fields
78
- if (!companyName || companyName.trim() === '') {
79
- return res.status(400).json({
80
- error: 'Missing company name',
81
- message: 'Please provide your company name',
82
- });
83
- }
84
-
85
- if (!regions || regions.length === 0) {
86
- return res.status(400).json({
87
- error: 'Missing regions',
88
- message: 'Please select at least one compliance region',
89
- });
90
- }
91
-
92
- if (!platforms || platforms.length === 0) {
93
- return res.status(400).json({
94
- error: 'Missing platforms',
95
- message: 'Please select at least one AI platform',
96
- });
97
- }
98
-
99
- if (!lawfulBasis) {
100
- return res.status(400).json({
101
- error: 'Missing lawful basis',
102
- message: 'Please select a lawful basis for processing',
103
- });
104
- }
105
-
106
- // Import the generator
107
- const { generateComplianceDocuments } = await import('../src/compliance/index.js');
108
-
109
- // Generate documents
110
- const result = generateComplianceDocuments({
111
- companyName: companyName.trim(),
112
- companyEmail: companyEmail || `privacy@${companyName.toLowerCase().replace(/\s+/g, '')}.com`,
113
- companyAddress,
114
- dpoEmail,
115
- regions,
116
- platforms,
117
- lawfulBasis,
118
- includeMarketingConsent: includeMarketingConsent || false,
119
- includeDataRetention: includeDataRetention || false,
120
- retentionPeriodYears: retentionPeriodYears || 7,
121
- additionalProcessors,
122
- });
123
-
124
- return res.status(200).json({
125
- success: true,
126
- ...result,
127
- });
128
-
129
- } catch (error) {
130
- console.error('Compliance generation error:', error);
131
- return res.status(500).json({
132
- error: 'Generation failed',
133
- message: error.message || 'An unexpected error occurred',
134
- });
135
- }
136
- }
137
-
138
- // Method not allowed
139
- return res.status(405).json({
140
- error: 'Method not allowed',
141
- message: 'Use GET for options or POST to generate documents',
142
- });
143
- }
@@ -1,457 +0,0 @@
1
- /**
2
- * Vercel Serverless Function: Generate Schema.org Snippets
3
- * POST /api/generate-schema
4
- *
5
- * Generates ready-to-use JSON-LD snippets for:
6
- * - MerchantReturnPolicy
7
- * - OfferShippingDetails
8
- * - Complete Product schema
9
- */
10
-
11
- // Default templates for common scenarios
12
- const RETURN_POLICY_TEMPLATES = {
13
- '30-day-free': {
14
- '@context': 'https://schema.org',
15
- '@type': 'MerchantReturnPolicy',
16
- '@id': '#return-policy',
17
- name: '30-Day Free Returns',
18
- applicableCountry: 'US',
19
- returnPolicyCategory: 'https://schema.org/MerchantReturnFiniteReturnWindow',
20
- merchantReturnDays: 30,
21
- returnMethod: 'https://schema.org/ReturnByMail',
22
- returnFees: 'https://schema.org/FreeReturn',
23
- returnShippingFeesAmount: {
24
- '@type': 'MonetaryAmount',
25
- value: 0,
26
- currency: 'USD',
27
- },
28
- },
29
- '14-day-free': {
30
- '@context': 'https://schema.org',
31
- '@type': 'MerchantReturnPolicy',
32
- '@id': '#return-policy',
33
- name: '14-Day Free Returns',
34
- applicableCountry: 'US',
35
- returnPolicyCategory: 'https://schema.org/MerchantReturnFiniteReturnWindow',
36
- merchantReturnDays: 14,
37
- returnMethod: 'https://schema.org/ReturnByMail',
38
- returnFees: 'https://schema.org/FreeReturn',
39
- },
40
- '30-day-paid': {
41
- '@context': 'https://schema.org',
42
- '@type': 'MerchantReturnPolicy',
43
- '@id': '#return-policy',
44
- name: '30-Day Returns',
45
- applicableCountry: 'US',
46
- returnPolicyCategory: 'https://schema.org/MerchantReturnFiniteReturnWindow',
47
- merchantReturnDays: 30,
48
- returnMethod: 'https://schema.org/ReturnByMail',
49
- returnFees: 'https://schema.org/ReturnShippingFees',
50
- },
51
- 'no-returns': {
52
- '@context': 'https://schema.org',
53
- '@type': 'MerchantReturnPolicy',
54
- '@id': '#return-policy',
55
- name: 'Final Sale - No Returns',
56
- applicableCountry: 'US',
57
- returnPolicyCategory: 'https://schema.org/MerchantReturnNotPermitted',
58
- },
59
- };
60
-
61
- const SHIPPING_TEMPLATES = {
62
- 'us-standard': {
63
- '@context': 'https://schema.org',
64
- '@type': 'OfferShippingDetails',
65
- '@id': '#shipping-us-standard',
66
- shippingRate: {
67
- '@type': 'MonetaryAmount',
68
- value: 5.99,
69
- currency: 'USD',
70
- },
71
- shippingDestination: {
72
- '@type': 'DefinedRegion',
73
- addressCountry: 'US',
74
- },
75
- deliveryTime: {
76
- '@type': 'ShippingDeliveryTime',
77
- handlingTime: {
78
- '@type': 'QuantitativeValue',
79
- minValue: 1,
80
- maxValue: 2,
81
- unitCode: 'd',
82
- },
83
- transitTime: {
84
- '@type': 'QuantitativeValue',
85
- minValue: 3,
86
- maxValue: 7,
87
- unitCode: 'd',
88
- },
89
- },
90
- },
91
- 'us-free': {
92
- '@context': 'https://schema.org',
93
- '@type': 'OfferShippingDetails',
94
- '@id': '#shipping-us-free',
95
- shippingRate: {
96
- '@type': 'MonetaryAmount',
97
- value: 0,
98
- currency: 'USD',
99
- },
100
- shippingDestination: {
101
- '@type': 'DefinedRegion',
102
- addressCountry: 'US',
103
- },
104
- deliveryTime: {
105
- '@type': 'ShippingDeliveryTime',
106
- handlingTime: {
107
- '@type': 'QuantitativeValue',
108
- minValue: 1,
109
- maxValue: 2,
110
- unitCode: 'd',
111
- },
112
- transitTime: {
113
- '@type': 'QuantitativeValue',
114
- minValue: 5,
115
- maxValue: 10,
116
- unitCode: 'd',
117
- },
118
- },
119
- },
120
- 'us-express': {
121
- '@context': 'https://schema.org',
122
- '@type': 'OfferShippingDetails',
123
- '@id': '#shipping-us-express',
124
- shippingRate: {
125
- '@type': 'MonetaryAmount',
126
- value: 14.99,
127
- currency: 'USD',
128
- },
129
- shippingDestination: {
130
- '@type': 'DefinedRegion',
131
- addressCountry: 'US',
132
- },
133
- deliveryTime: {
134
- '@type': 'ShippingDeliveryTime',
135
- handlingTime: {
136
- '@type': 'QuantitativeValue',
137
- minValue: 0,
138
- maxValue: 1,
139
- unitCode: 'd',
140
- },
141
- transitTime: {
142
- '@type': 'QuantitativeValue',
143
- minValue: 1,
144
- maxValue: 2,
145
- unitCode: 'd',
146
- },
147
- },
148
- },
149
- 'international': {
150
- '@context': 'https://schema.org',
151
- '@type': 'OfferShippingDetails',
152
- '@id': '#shipping-international',
153
- shippingRate: {
154
- '@type': 'MonetaryAmount',
155
- value: 19.99,
156
- currency: 'USD',
157
- },
158
- shippingDestination: {
159
- '@type': 'DefinedRegion',
160
- addressCountry: ['CA', 'GB', 'AU', 'DE', 'FR'],
161
- },
162
- deliveryTime: {
163
- '@type': 'ShippingDeliveryTime',
164
- handlingTime: {
165
- '@type': 'QuantitativeValue',
166
- minValue: 1,
167
- maxValue: 3,
168
- unitCode: 'd',
169
- },
170
- transitTime: {
171
- '@type': 'QuantitativeValue',
172
- minValue: 7,
173
- maxValue: 21,
174
- unitCode: 'd',
175
- },
176
- },
177
- },
178
- };
179
-
180
- function generateCustomReturnPolicy(options) {
181
- const {
182
- country = 'US',
183
- returnDays = 30,
184
- freeReturns = true,
185
- returnFee = 0,
186
- currency = 'USD',
187
- policyName = `${returnDays}-Day Returns`,
188
- noReturns = false,
189
- } = options;
190
-
191
- if (noReturns) {
192
- return {
193
- '@context': 'https://schema.org',
194
- '@type': 'MerchantReturnPolicy',
195
- '@id': '#return-policy',
196
- name: policyName || 'Final Sale - No Returns',
197
- applicableCountry: country,
198
- returnPolicyCategory: 'https://schema.org/MerchantReturnNotPermitted',
199
- };
200
- }
201
-
202
- const policy = {
203
- '@context': 'https://schema.org',
204
- '@type': 'MerchantReturnPolicy',
205
- '@id': '#return-policy',
206
- name: policyName,
207
- applicableCountry: country,
208
- returnPolicyCategory: 'https://schema.org/MerchantReturnFiniteReturnWindow',
209
- merchantReturnDays: returnDays,
210
- returnMethod: 'https://schema.org/ReturnByMail',
211
- };
212
-
213
- if (freeReturns) {
214
- policy.returnFees = 'https://schema.org/FreeReturn';
215
- } else {
216
- policy.returnFees = 'https://schema.org/ReturnShippingFees';
217
- if (returnFee > 0) {
218
- policy.returnShippingFeesAmount = {
219
- '@type': 'MonetaryAmount',
220
- value: returnFee,
221
- currency: currency,
222
- };
223
- }
224
- }
225
-
226
- return policy;
227
- }
228
-
229
- function generateCustomShipping(options) {
230
- const {
231
- country = 'US',
232
- rate = 5.99,
233
- currency = 'USD',
234
- freeShipping = false,
235
- handlingMin = 1,
236
- handlingMax = 2,
237
- transitMin = 3,
238
- transitMax = 7,
239
- } = options;
240
-
241
- return {
242
- '@context': 'https://schema.org',
243
- '@type': 'OfferShippingDetails',
244
- '@id': `#shipping-${country.toLowerCase()}`,
245
- shippingRate: {
246
- '@type': 'MonetaryAmount',
247
- value: freeShipping ? 0 : rate,
248
- currency: currency,
249
- },
250
- shippingDestination: {
251
- '@type': 'DefinedRegion',
252
- addressCountry: country,
253
- },
254
- deliveryTime: {
255
- '@type': 'ShippingDeliveryTime',
256
- handlingTime: {
257
- '@type': 'QuantitativeValue',
258
- minValue: handlingMin,
259
- maxValue: handlingMax,
260
- unitCode: 'd',
261
- },
262
- transitTime: {
263
- '@type': 'QuantitativeValue',
264
- minValue: transitMin,
265
- maxValue: transitMax,
266
- unitCode: 'd',
267
- },
268
- },
269
- };
270
- }
271
-
272
- function generateProductSchema(options) {
273
- const {
274
- name,
275
- description,
276
- image,
277
- sku,
278
- brand,
279
- price,
280
- currency = 'USD',
281
- availability = 'InStock',
282
- condition = 'NewCondition',
283
- includeReturnPolicy = true,
284
- includeShipping = true,
285
- returnPolicyRef = '#return-policy',
286
- shippingRef = '#shipping-us-standard',
287
- } = options;
288
-
289
- const product = {
290
- '@context': 'https://schema.org',
291
- '@type': 'Product',
292
- name: name || 'Product Name',
293
- description: description || 'Product description goes here. Aim for 150-300 characters to help AI agents understand your product.',
294
- };
295
-
296
- if (image) {
297
- product.image = image;
298
- }
299
-
300
- if (sku) {
301
- product.sku = sku;
302
- }
303
-
304
- if (brand) {
305
- product.brand = {
306
- '@type': 'Brand',
307
- name: brand,
308
- };
309
- }
310
-
311
- product.offers = {
312
- '@type': 'Offer',
313
- price: price || 29.99,
314
- priceCurrency: currency,
315
- availability: `https://schema.org/${availability}`,
316
- itemCondition: `https://schema.org/${condition}`,
317
- };
318
-
319
- if (includeReturnPolicy) {
320
- product.offers.hasMerchantReturnPolicy = { '@id': returnPolicyRef };
321
- }
322
-
323
- if (includeShipping) {
324
- product.offers.shippingDetails = { '@id': shippingRef };
325
- }
326
-
327
- return product;
328
- }
329
-
330
- function generateCompleteSchema(options) {
331
- const {
332
- returnPolicy = '30-day-free',
333
- shipping = 'us-standard',
334
- customReturn,
335
- customShipping,
336
- product,
337
- } = options;
338
-
339
- const schemas = [];
340
-
341
- // Add return policy
342
- if (customReturn) {
343
- schemas.push(generateCustomReturnPolicy(customReturn));
344
- } else if (RETURN_POLICY_TEMPLATES[returnPolicy]) {
345
- schemas.push(RETURN_POLICY_TEMPLATES[returnPolicy]);
346
- }
347
-
348
- // Add shipping
349
- if (customShipping) {
350
- schemas.push(generateCustomShipping(customShipping));
351
- } else if (SHIPPING_TEMPLATES[shipping]) {
352
- schemas.push(SHIPPING_TEMPLATES[shipping]);
353
- }
354
-
355
- // Add product if provided
356
- if (product) {
357
- schemas.push(generateProductSchema(product));
358
- }
359
-
360
- return schemas;
361
- }
362
-
363
- export default async function handler(req, res) {
364
- // CORS headers
365
- res.setHeader('Access-Control-Allow-Origin', '*');
366
- res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
367
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
368
-
369
- if (req.method === 'OPTIONS') {
370
- return res.status(200).end();
371
- }
372
-
373
- // GET: Return available templates
374
- if (req.method === 'GET') {
375
- return res.status(200).json({
376
- templates: {
377
- returnPolicy: Object.keys(RETURN_POLICY_TEMPLATES),
378
- shipping: Object.keys(SHIPPING_TEMPLATES),
379
- },
380
- description: 'Use POST to generate custom Schema.org snippets',
381
- });
382
- }
383
-
384
- if (req.method !== 'POST') {
385
- return res.status(405).json({ error: 'Method not allowed' });
386
- }
387
-
388
- const {
389
- type, // 'return-policy', 'shipping', 'product', 'complete'
390
- template, // template name for quick generation
391
- options = {}, // custom options
392
- } = req.body;
393
-
394
- try {
395
- let schema;
396
- let embedCode;
397
-
398
- switch (type) {
399
- case 'return-policy':
400
- if (template && RETURN_POLICY_TEMPLATES[template]) {
401
- schema = RETURN_POLICY_TEMPLATES[template];
402
- } else {
403
- schema = generateCustomReturnPolicy(options);
404
- }
405
- break;
406
-
407
- case 'shipping':
408
- if (template && SHIPPING_TEMPLATES[template]) {
409
- schema = SHIPPING_TEMPLATES[template];
410
- } else {
411
- schema = generateCustomShipping(options);
412
- }
413
- break;
414
-
415
- case 'product':
416
- schema = generateProductSchema(options);
417
- break;
418
-
419
- case 'complete':
420
- schema = generateCompleteSchema(options);
421
- break;
422
-
423
- default:
424
- return res.status(400).json({
425
- error: 'Invalid type. Use: return-policy, shipping, product, or complete',
426
- availableTemplates: {
427
- returnPolicy: Object.keys(RETURN_POLICY_TEMPLATES),
428
- shipping: Object.keys(SHIPPING_TEMPLATES),
429
- },
430
- });
431
- }
432
-
433
- // Generate embed code
434
- const schemaJson = JSON.stringify(schema, null, 2);
435
- embedCode = `<script type="application/ld+json">
436
- ${schemaJson}
437
- </script>`;
438
-
439
- return res.status(200).json({
440
- success: true,
441
- type,
442
- schema,
443
- embedCode,
444
- instructions: [
445
- 'Copy the embedCode and paste it into your HTML <head> section',
446
- 'For products, add the schema to each product page',
447
- 'Use the @id references to link return policy and shipping to products',
448
- 'Validate at https://validator.schema.org/',
449
- ],
450
- });
451
- } catch (error) {
452
- return res.status(500).json({
453
- error: 'Failed to generate schema',
454
- message: error.message,
455
- });
456
- }
457
- }