webspresso 0.0.80 → 0.0.82

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 (38) hide show
  1. package/README.md +133 -15
  2. package/bin/commands/doctor.js +83 -0
  3. package/bin/commands/favicon-generate.js +3 -1
  4. package/bin/commands/skill.js +6 -4
  5. package/core/auth/hash.js +1 -1
  6. package/core/auth/index.js +30 -0
  7. package/core/auth/manager.js +190 -0
  8. package/core/auth/tokens.js +135 -0
  9. package/core/kernel/app.js +7 -1
  10. package/index.d.ts +32 -0
  11. package/index.js +2 -0
  12. package/package.json +5 -2
  13. package/plugins/admin-panel/app.js +43 -1
  14. package/plugins/admin-panel/core/admin-module.js +156 -16
  15. package/plugins/admin-panel/core/registry.js +3 -0
  16. package/plugins/admin-panel/field-renderers/file-upload.js +48 -2
  17. package/plugins/admin-panel/index.js +17 -1
  18. package/plugins/csrf/index.js +222 -0
  19. package/plugins/email/admin-component.js +226 -0
  20. package/plugins/email/api-handlers.js +139 -0
  21. package/plugins/email/auth-bridge.js +209 -0
  22. package/plugins/email/bundled-templates.js +68 -0
  23. package/plugins/email/fs-env.js +101 -0
  24. package/plugins/email/index.js +186 -0
  25. package/plugins/email/manifest.js +25 -0
  26. package/plugins/email/migration-template.js +40 -0
  27. package/plugins/email/purge.js +28 -0
  28. package/plugins/email/render.js +154 -0
  29. package/plugins/email/service.js +244 -0
  30. package/plugins/email/template-registry.js +134 -0
  31. package/plugins/email/templates/auth-email-verify.mjml +13 -0
  32. package/plugins/email/templates/auth-password-reset.mjml +13 -0
  33. package/plugins/email/templates/auth-welcome.mjml +11 -0
  34. package/plugins/email/transport.js +71 -0
  35. package/plugins/index.js +4 -0
  36. package/src/file-router.js +75 -0
  37. package/templates/skills/webspresso-usage/REFERENCE-framework.md +1 -0
  38. package/templates/skills/webspresso-usage/SKILL.md +2 -1
@@ -644,6 +644,81 @@ function mountPages(app, options) {
644
644
 
645
645
  // Get absolute path to pages directory
646
646
  const absolutePagesDir = path.resolve(pagesDir);
647
+
648
+ // Routing and file-system checks at startup
649
+ function checkRoutesAtStartup() {
650
+ function getGenericSegment(name) {
651
+ if (name.startsWith('[') && name.endsWith(']')) {
652
+ const inner = name.slice(1, -1);
653
+ if (inner.startsWith('...')) return '*';
654
+ return ':param';
655
+ }
656
+ return name;
657
+ }
658
+
659
+ function checkDir(dirPath, relativeDir = '', isApi = false) {
660
+ if (!fs.existsSync(dirPath)) return;
661
+ const children = fs.readdirSync(dirPath);
662
+ const kept = [];
663
+
664
+ for (const child of children) {
665
+ if (child.startsWith('_') || child === 'locales') continue;
666
+ const fullPath = path.join(dirPath, child);
667
+ const relPath = relativeDir ? path.join(relativeDir, child) : child;
668
+ const stats = fs.statSync(fullPath);
669
+
670
+ // 1. Check case-sensitivity issues
671
+ if (child !== child.toLowerCase()) {
672
+ console.warn(`[webspresso] WARNING: Path "pages/${relPath.split(path.sep).join('/')}" contains uppercase letters. Use lowercase to avoid routing issues on case-sensitive filesystems.`);
673
+ }
674
+
675
+ if (stats.isDirectory()) {
676
+ if (child === 'api' && relativeDir === '') {
677
+ checkDir(fullPath, relPath, true);
678
+ } else {
679
+ checkDir(fullPath, relPath, isApi);
680
+ if (!isApi) {
681
+ kept.push({ name: child, isDir: true, original: child });
682
+ }
683
+ }
684
+ } else {
685
+ const ext = path.extname(child);
686
+ if (isApi) {
687
+ if (ext === '.js') {
688
+ const base = path.basename(child, ext);
689
+ kept.push({ name: base, isDir: false, original: child });
690
+ }
691
+ } else {
692
+ if (ext === '.njk') {
693
+ const base = path.basename(child, ext);
694
+ kept.push({ name: base, isDir: false, original: child });
695
+ }
696
+ }
697
+ }
698
+ }
699
+
700
+ // 2. Check dynamic route collisions
701
+ const groups = new Map();
702
+ for (const item of kept) {
703
+ const normalized = getGenericSegment(item.name);
704
+ if (!groups.has(normalized)) {
705
+ groups.set(normalized, []);
706
+ }
707
+ groups.get(normalized).push(item);
708
+ }
709
+
710
+ for (const [norm, items] of groups.entries()) {
711
+ if (items.length > 1) {
712
+ const namesList = items.map(item => `"${item.original}"`).join(' and ');
713
+ console.warn(`[webspresso] WARNING: Dynamic route collision in "pages/${relativeDir.split(path.sep).join('/')}": ${namesList} resolve to the same segment "${norm}" and will conflict at runtime.`);
714
+ }
715
+ }
716
+ }
717
+
718
+ checkDir(absolutePagesDir, '');
719
+ }
720
+
721
+ checkRoutesAtStartup();
647
722
 
648
723
  // Load global hooks
649
724
  const globalHooks = loadGlobalHooks(absolutePagesDir, isDev);
@@ -202,6 +202,7 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
202
202
  | `siteAnalyticsPlugin` | Self-hosted page views + admin charts |
203
203
  | `auditLogPlugin` | Admin mutation audit trail |
204
204
  | `recaptchaPlugin` | v2/v3 + middleware |
205
+ | `emailPlugin` | MJML + Nodemailer sending with optional admin UI and auth bridge |
205
206
  | `seoCheckerPlugin` | Dev SEO panel |
206
207
  | `restResourcePlugin` | Opt-in REST CRUD from models; `?include=` uses ORM eager load (single-level relations only) |
207
208
  | `ormCacheAdminPlugin` | Admin page for ORM cache metrics / purge / invalidate (`db.cache` required) |
@@ -33,7 +33,8 @@ There are **three** files in this folder; open the reference that matches the ta
33
33
  | `webspresso dev` | Dev server (watch). |
34
34
  | `webspresso db:migrate` / `db:rollback` / `db:status` | ORM migrations. |
35
35
  | `webspresso doctor` | Environment / project sanity checks. |
36
- | `webspresso skill --preset webspresso` | Copies this skill bundle under `.cursor/skills/webspresso-usage/` (`SKILL.md` + `REFERENCE-*.md`). |
36
+ | `webspresso skill --preset webspresso` | Copies this skill bundle under `.agents/skills/webspresso-usage/` (`SKILL.md` + `REFERENCE-*.md`). |
37
+
37
38
 
38
39
  ## When to use this skill
39
40