zero-query 0.9.7 → 0.9.9

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 (72) hide show
  1. package/README.md +55 -4
  2. package/cli/commands/build.js +50 -3
  3. package/cli/commands/create.js +58 -11
  4. package/cli/help.js +4 -0
  5. package/cli/scaffold/default/app/app.js +211 -0
  6. package/cli/scaffold/default/app/components/about.js +201 -0
  7. package/cli/scaffold/default/app/components/api-demo.js +143 -0
  8. package/cli/scaffold/default/app/components/contact-card.js +231 -0
  9. package/cli/scaffold/default/app/components/contacts/contacts.css +706 -0
  10. package/cli/scaffold/default/app/components/contacts/contacts.html +200 -0
  11. package/cli/scaffold/default/app/components/contacts/contacts.js +196 -0
  12. package/cli/scaffold/default/app/components/counter.js +127 -0
  13. package/cli/scaffold/default/app/components/home.js +249 -0
  14. package/cli/scaffold/{app → default/app}/components/not-found.js +2 -2
  15. package/cli/scaffold/default/app/components/playground/playground.css +116 -0
  16. package/cli/scaffold/default/app/components/playground/playground.html +162 -0
  17. package/cli/scaffold/default/app/components/playground/playground.js +117 -0
  18. package/cli/scaffold/default/app/components/todos.js +225 -0
  19. package/cli/scaffold/default/app/components/toolkit/toolkit.css +97 -0
  20. package/cli/scaffold/default/app/components/toolkit/toolkit.html +146 -0
  21. package/cli/scaffold/default/app/components/toolkit/toolkit.js +280 -0
  22. package/cli/scaffold/default/app/routes.js +15 -0
  23. package/cli/scaffold/{app → default/app}/store.js +15 -10
  24. package/cli/scaffold/{global.css → default/global.css} +238 -252
  25. package/cli/scaffold/{index.html → default/index.html} +35 -0
  26. package/cli/scaffold/{app → minimal/app}/app.js +37 -39
  27. package/cli/scaffold/minimal/app/components/about.js +68 -0
  28. package/cli/scaffold/minimal/app/components/counter.js +122 -0
  29. package/cli/scaffold/minimal/app/components/home.js +68 -0
  30. package/cli/scaffold/minimal/app/components/not-found.js +16 -0
  31. package/cli/scaffold/minimal/app/routes.js +9 -0
  32. package/cli/scaffold/minimal/app/store.js +36 -0
  33. package/cli/scaffold/minimal/assets/.gitkeep +0 -0
  34. package/cli/scaffold/minimal/global.css +291 -0
  35. package/cli/scaffold/minimal/index.html +44 -0
  36. package/cli/scaffold/ssr/app/app.js +30 -0
  37. package/cli/scaffold/ssr/app/components/about.js +28 -0
  38. package/cli/scaffold/ssr/app/components/home.js +37 -0
  39. package/cli/scaffold/ssr/app/components/not-found.js +15 -0
  40. package/cli/scaffold/ssr/app/routes.js +6 -0
  41. package/cli/scaffold/ssr/global.css +113 -0
  42. package/cli/scaffold/ssr/index.html +31 -0
  43. package/cli/scaffold/ssr/package.json +8 -0
  44. package/cli/scaffold/ssr/server/index.js +118 -0
  45. package/dist/zquery.dist.zip +0 -0
  46. package/dist/zquery.js +2006 -1933
  47. package/dist/zquery.min.js +2 -2
  48. package/index.d.ts +20 -1
  49. package/index.js +8 -5
  50. package/package.json +8 -2
  51. package/src/component.js +6 -3
  52. package/src/diff.js +15 -2
  53. package/src/errors.js +59 -5
  54. package/src/package.json +1 -0
  55. package/src/ssr.js +116 -22
  56. package/tests/cli.test.js +304 -0
  57. package/tests/errors.test.js +423 -145
  58. package/tests/ssr.test.js +435 -3
  59. package/types/errors.d.ts +34 -2
  60. package/types/ssr.d.ts +21 -1
  61. package/cli/scaffold/app/components/about.js +0 -131
  62. package/cli/scaffold/app/components/api-demo.js +0 -103
  63. package/cli/scaffold/app/components/contacts/contacts.css +0 -246
  64. package/cli/scaffold/app/components/contacts/contacts.html +0 -140
  65. package/cli/scaffold/app/components/contacts/contacts.js +0 -153
  66. package/cli/scaffold/app/components/counter.js +0 -85
  67. package/cli/scaffold/app/components/home.js +0 -137
  68. package/cli/scaffold/app/components/todos.js +0 -131
  69. package/cli/scaffold/app/routes.js +0 -13
  70. /package/cli/scaffold/{LICENSE → default/LICENSE} +0 -0
  71. /package/cli/scaffold/{assets → default/assets}/.gitkeep +0 -0
  72. /package/cli/scaffold/{favicon.ico → default/favicon.ico} +0 -0
@@ -0,0 +1,118 @@
1
+ // server/index.js — SSR HTTP server
2
+ //
3
+ // Renders routes to HTML with zQuery SSR and serves them over HTTP.
4
+ // Components are imported from app/components/ — the same definitions
5
+ // the client uses.
6
+ //
7
+ // Usage:
8
+ // node server/index.js
9
+ // PORT=8080 node server/index.js
10
+
11
+ import { createServer } from 'node:http';
12
+ import { readFile } from 'node:fs/promises';
13
+ import { join, extname, resolve } from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { createSSRApp } from 'zero-query/ssr';
16
+
17
+ // Shared component definitions — same ones the client registers
18
+ import { homePage } from '../app/components/home.js';
19
+ import { aboutPage } from '../app/components/about.js';
20
+ import { notFound } from '../app/components/not-found.js';
21
+ import { routes } from '../app/routes.js';
22
+
23
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
24
+ const ROOT = join(__dirname, '..');
25
+ const PORT = parseInt(process.env.PORT || '3000', 10);
26
+
27
+ // --- SSR app ----------------------------------------------------------------
28
+
29
+ const app = createSSRApp();
30
+ app.component('home-page', homePage);
31
+ app.component('about-page', aboutPage);
32
+ app.component('not-found', notFound);
33
+
34
+ // --- Route matching ---------------------------------------------------------
35
+
36
+ function matchRoute(pathname) {
37
+ const route = routes.find(r => r.path === pathname);
38
+ return route ? route.component : 'not-found';
39
+ }
40
+
41
+ // --- Render a full HTML page ------------------------------------------------
42
+
43
+ async function render(pathname) {
44
+ const component = matchRoute(pathname);
45
+ const body = await app.renderToString(component);
46
+
47
+ return `<!DOCTYPE html>
48
+ <html lang="en">
49
+ <head>
50
+ <meta charset="UTF-8">
51
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
52
+ <title>{{NAME}}</title>
53
+ <link rel="stylesheet" href="/global.css">
54
+ </head>
55
+ <body>
56
+ <nav class="navbar">
57
+ <span class="brand">⚡ {{NAME}}</span>
58
+ <div class="nav-links">
59
+ ${routes.map(r =>
60
+ ` <a href="${r.path}" class="nav-link${r.path === pathname ? ' active' : ''}">${
61
+ r.path === '/' ? 'Home' : r.path.slice(1)[0].toUpperCase() + r.path.slice(2)
62
+ }</a>`).join('\n')}
63
+ </div>
64
+ </nav>
65
+ <main id="app">${body}</main>
66
+ <footer class="footer"><small>Built with zQuery · SSR</small></footer>
67
+ </body>
68
+ </html>`;
69
+ }
70
+
71
+ // --- Static files -----------------------------------------------------------
72
+
73
+ const MIME = {
74
+ '.css': 'text/css', '.js': 'text/javascript', '.json': 'application/json',
75
+ '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml',
76
+ '.ico': 'image/x-icon', '.woff2': 'font/woff2',
77
+ };
78
+
79
+ async function serveStatic(res, pathname) {
80
+ const ext = extname(pathname);
81
+ if (!MIME[ext]) return false;
82
+
83
+ const filePath = join(ROOT, pathname);
84
+ if (!resolve(filePath).startsWith(resolve(ROOT))) return false;
85
+
86
+ try {
87
+ const data = await readFile(filePath);
88
+ res.writeHead(200, { 'Content-Type': MIME[ext] });
89
+ res.end(data);
90
+ return true;
91
+ } catch { return false; }
92
+ }
93
+
94
+ // --- HTTP server ------------------------------------------------------------
95
+
96
+ createServer(async (req, res) => {
97
+ const { pathname } = new URL(req.url, `http://localhost:${PORT}`);
98
+
99
+ // Static assets (CSS, images, etc.)
100
+ if (pathname !== '/' && await serveStatic(res, pathname)) return;
101
+
102
+ // SSR route
103
+ try {
104
+ const html = await render(pathname);
105
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
106
+ res.end(html);
107
+ } catch (err) {
108
+ console.error('SSR error:', err);
109
+ if (!res.headersSent) {
110
+ res.writeHead(500, { 'Content-Type': 'text/plain' });
111
+ }
112
+ res.end('Internal Server Error');
113
+ }
114
+ }).listen(PORT, () => {
115
+ console.log(`\n ⚡ SSR server → http://localhost:${PORT}\n`);
116
+ routes.forEach(r => console.log(` ${r.path.padEnd(10)} → ${r.component}`));
117
+ console.log(` * → not-found\n`);
118
+ });
Binary file