webpeel 0.17.21 → 0.17.23

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 (47) hide show
  1. package/dist/cli.js +104 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/core/browser-fetch.d.ts +20 -0
  4. package/dist/core/browser-fetch.d.ts.map +1 -1
  5. package/dist/core/browser-fetch.js +113 -19
  6. package/dist/core/browser-fetch.js.map +1 -1
  7. package/dist/core/cloak-fetch.d.ts +1 -1
  8. package/dist/core/cloak-fetch.d.ts.map +1 -1
  9. package/dist/core/cloak-fetch.js +12 -4
  10. package/dist/core/cloak-fetch.js.map +1 -1
  11. package/dist/core/design-analysis.d.ts +71 -0
  12. package/dist/core/design-analysis.d.ts.map +1 -0
  13. package/dist/core/design-analysis.js +491 -0
  14. package/dist/core/design-analysis.js.map +1 -0
  15. package/dist/core/design-compare.d.ts +39 -0
  16. package/dist/core/design-compare.d.ts.map +1 -0
  17. package/dist/core/design-compare.js +265 -0
  18. package/dist/core/design-compare.js.map +1 -0
  19. package/dist/core/fetcher.d.ts +2 -1
  20. package/dist/core/fetcher.d.ts.map +1 -1
  21. package/dist/core/fetcher.js +1 -1
  22. package/dist/core/fetcher.js.map +1 -1
  23. package/dist/core/pipeline.d.ts +2 -0
  24. package/dist/core/pipeline.d.ts.map +1 -1
  25. package/dist/core/pipeline.js +35 -4
  26. package/dist/core/pipeline.js.map +1 -1
  27. package/dist/core/screenshot.d.ts +37 -1
  28. package/dist/core/screenshot.d.ts.map +1 -1
  29. package/dist/core/screenshot.js +34 -1
  30. package/dist/core/screenshot.js.map +1 -1
  31. package/dist/core/youtube.d.ts.map +1 -1
  32. package/dist/core/youtube.js +7 -2
  33. package/dist/core/youtube.js.map +1 -1
  34. package/dist/server/app.d.ts.map +1 -1
  35. package/dist/server/app.js +3 -0
  36. package/dist/server/app.js.map +1 -1
  37. package/dist/server/routes/demo.d.ts +25 -0
  38. package/dist/server/routes/demo.d.ts.map +1 -0
  39. package/dist/server/routes/demo.js +245 -0
  40. package/dist/server/routes/demo.js.map +1 -0
  41. package/dist/server/routes/screenshot.d.ts.map +1 -1
  42. package/dist/server/routes/screenshot.js +113 -1
  43. package/dist/server/routes/screenshot.js.map +1 -1
  44. package/dist/types.d.ts +4 -0
  45. package/dist/types.d.ts.map +1 -1
  46. package/dist/types.js.map +1 -1
  47. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3847,6 +3847,110 @@ program
3847
3847
  console.log('Usage: webpeel "https://example.com" --schema product');
3848
3848
  console.log(' webpeel "https://example.com" --schema \'{"field":"description"}\'');
3849
3849
  });
3850
+ // ── design-compare command ─────────────────────────────────────────────────────
3851
+ //
3852
+ // webpeel design-compare "https://subject.com" --ref "https://reference.com"
3853
+ program
3854
+ .command('design-compare <url>')
3855
+ .description('Compare the design of a subject URL against a reference URL')
3856
+ .option('--ref <url>', 'Reference URL to compare against (required)')
3857
+ .option('--width <px>', 'Viewport width in pixels (default: 1440)', parseInt)
3858
+ .option('--height <px>', 'Viewport height in pixels (default: 900)', parseInt)
3859
+ .option('-o, --output <path>', 'Save comparison report to a JSON file')
3860
+ .option('-s, --silent', 'Silent mode (no spinner)')
3861
+ .option('--json', 'Output comparison as JSON to stdout')
3862
+ .action(async (url, options) => {
3863
+ // Validate subject URL
3864
+ try {
3865
+ const parsed = new URL(url);
3866
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
3867
+ console.error('Error: Only HTTP and HTTPS protocols are allowed');
3868
+ process.exit(1);
3869
+ }
3870
+ }
3871
+ catch {
3872
+ console.error(`Error: Invalid URL format: ${url}`);
3873
+ process.exit(1);
3874
+ }
3875
+ // Validate --ref
3876
+ if (!options.ref) {
3877
+ console.error('Error: --ref <url> is required');
3878
+ process.exit(1);
3879
+ }
3880
+ try {
3881
+ const parsedRef = new URL(options.ref);
3882
+ if (!['http:', 'https:'].includes(parsedRef.protocol)) {
3883
+ console.error('Error: --ref must be an HTTP or HTTPS URL');
3884
+ process.exit(1);
3885
+ }
3886
+ }
3887
+ catch {
3888
+ console.error(`Error: Invalid --ref URL format: ${options.ref}`);
3889
+ process.exit(1);
3890
+ }
3891
+ const ora = (await import('ora')).default;
3892
+ const spinner = options.silent ? null : ora(`Comparing designs: ${url} vs ${options.ref}...`).start();
3893
+ try {
3894
+ const { takeDesignComparison } = await import('./core/screenshot.js');
3895
+ const result = await takeDesignComparison(url, options.ref, {
3896
+ width: options.width,
3897
+ height: options.height,
3898
+ });
3899
+ if (spinner)
3900
+ spinner.succeed('Design comparison complete');
3901
+ const { comparison } = result;
3902
+ const output = {
3903
+ subjectUrl: result.subjectUrl,
3904
+ referenceUrl: result.referenceUrl,
3905
+ score: comparison.score,
3906
+ summary: comparison.summary,
3907
+ gaps: comparison.gaps,
3908
+ subjectAnalysis: comparison.subjectAnalysis,
3909
+ referenceAnalysis: comparison.referenceAnalysis,
3910
+ };
3911
+ if (options.output) {
3912
+ const { writeFileSync } = await import('fs');
3913
+ writeFileSync(options.output, JSON.stringify(output, null, 2));
3914
+ if (!options.silent)
3915
+ console.error(`Report saved to: ${options.output}`);
3916
+ }
3917
+ if (options.json || !options.output) {
3918
+ const jsonStr = JSON.stringify(output, null, 2);
3919
+ await new Promise((resolve, reject) => {
3920
+ process.stdout.write(jsonStr + '\n', (err) => {
3921
+ if (err)
3922
+ reject(err);
3923
+ else
3924
+ resolve();
3925
+ });
3926
+ });
3927
+ }
3928
+ else if (!options.silent) {
3929
+ // Human-readable summary
3930
+ console.log(`\n🎨 Design Comparison`);
3931
+ console.log(`Subject: ${result.subjectUrl}`);
3932
+ console.log(`Reference: ${result.referenceUrl}`);
3933
+ console.log(`Score: ${comparison.score}/10`);
3934
+ console.log(`\n${comparison.summary}`);
3935
+ if (comparison.gaps.length > 0) {
3936
+ console.log(`\nGaps (${comparison.gaps.length}):`);
3937
+ for (const gap of comparison.gaps) {
3938
+ const sev = gap.severity === 'high' ? '🔴' : gap.severity === 'medium' ? '🟡' : '🟢';
3939
+ console.log(` ${sev} ${gap.property}: ${gap.description}`);
3940
+ console.log(` Subject: ${gap.subject}`);
3941
+ console.log(` Reference: ${gap.reference}`);
3942
+ console.log(` Suggestion: ${gap.suggestion}`);
3943
+ }
3944
+ }
3945
+ }
3946
+ }
3947
+ catch (error) {
3948
+ if (spinner)
3949
+ spinner.fail('Design comparison failed');
3950
+ console.error(`Error: ${error.message}`);
3951
+ process.exit(1);
3952
+ }
3953
+ });
3850
3954
  program.parse();
3851
3955
  // ============================================================
3852
3956
  // Time formatting helper