@webjsdev/cli 0.8.6 → 0.9.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.
package/README.md CHANGED
@@ -18,7 +18,7 @@ Then scaffold a new app anywhere:
18
18
  ```sh
19
19
  webjs create my-app
20
20
  cd my-app && npm run dev
21
- # → http://localhost:3000
21
+ # → http://localhost:8080
22
22
  ```
23
23
 
24
24
  One-shot without a global install, two ways:
package/bin/webjs.js CHANGED
@@ -12,8 +12,8 @@ const [cmd, ...rest] = process.argv.slice(2);
12
12
  const TEMPLATES = ['full-stack', 'api', 'saas'];
13
13
 
14
14
  const USAGE = `webjs commands:
15
- webjs dev [--port 3000] Start dev server with live reload
16
- webjs start [--port 3000] Start production server (serves source directly, no build step)
15
+ webjs dev [--port 8080] Start dev server with live reload
16
+ webjs start [--port 8080] Start production server (serves source directly, no build step)
17
17
  webjs test [--server|--browser] Run server + browser tests
18
18
  webjs check Validate app against conventions
19
19
  webjs create <name> [--template full-stack|api|saas] [--no-install] Scaffold a new webjs app
@@ -41,7 +41,7 @@ async function main() {
41
41
  // If we're already inside the --watch child, start the server directly.
42
42
  if (process.env.__WEBJS_DEV_CHILD === '1') {
43
43
  const { startServer } = await import('@webjsdev/server');
44
- const port = Number(flag(rest, '--port', process.env.PORT || 3000));
44
+ const port = Number(flag(rest, '--port', process.env.PORT || 8080));
45
45
  await startServer({ appDir: process.cwd(), port, dev: true });
46
46
  break;
47
47
  }
@@ -81,7 +81,7 @@ async function main() {
81
81
  }
82
82
  case 'start': {
83
83
  const { startServer } = await import('@webjsdev/server');
84
- const port = Number(flag(rest, '--port', process.env.PORT || 3000));
84
+ const port = Number(flag(rest, '--port', process.env.PORT || 8080));
85
85
  await startServer({ appDir: process.cwd(), port, dev: false });
86
86
  break;
87
87
  }
package/lib/create.js CHANGED
@@ -15,6 +15,7 @@ import { mkdir, writeFile, readFile, cp } from 'node:fs/promises';
15
15
  import { join, resolve, dirname } from 'node:path';
16
16
  import { fileURLToPath } from 'node:url';
17
17
  import { existsSync } from 'node:fs';
18
+ import { createRequire } from 'node:module';
18
19
  import { spawnSync } from 'node:child_process';
19
20
 
20
21
  /**
@@ -54,14 +55,33 @@ const TEMPLATES = resolve(__dirname, '..', 'templates');
54
55
  // directly from disk at create time so the scaffolded app boots ready for
55
56
  // `webjs ui add` without an HTTP round-trip during scaffolding.
56
57
  //
57
- // Layout in the monorepo:
58
- // packages/cli/lib/create.js ← __dirname
59
- // packages/ui/packages/registry/components/*.ts
60
- // packages/ui/packages/registry/lib/utils.ts
61
- // packages/ui/packages/registry/themes/index.css
62
- const UI_REGISTRY_ROOT = resolve(
63
- __dirname, '..', '..', 'ui', 'packages', 'registry',
64
- );
58
+ // <ui-pkg-root>/packages/registry/components/*.ts
59
+ // <ui-pkg-root>/packages/registry/lib/utils.ts
60
+ // <ui-pkg-root>/packages/registry/themes/index.css
61
+ //
62
+ // Locate <ui-pkg-root> via Node's module resolver rather than path
63
+ // arithmetic off __dirname. The old `__dirname/../../ui/packages/registry`
64
+ // form assumed @webjsdev/ui was a hoisted sibling of @webjsdev/cli under
65
+ // node_modules/@webjsdev/. That holds for npm/yarn's default hoisting, but
66
+ // breaks on nested layouts (pnpm's isolated linker, `npm install
67
+ // --install-strategy=nested`, some CI setups), where @webjsdev/ui lives at
68
+ // node_modules/@webjsdev/cli/node_modules/@webjsdev/ui and the arithmetic
69
+ // resolves to a path that doesn't exist, failing `webjs create`.
70
+ //
71
+ // @webjsdev/ui's package.json isn't reachable via require.resolve (its
72
+ // `exports` map doesn't expose `./package.json`), so resolve the package
73
+ // entry and walk up to the directory that owns its package.json.
74
+ function resolveUiRegistryRoot() {
75
+ const require = createRequire(import.meta.url);
76
+ let dir = dirname(require.resolve('@webjsdev/ui'));
77
+ while (!existsSync(join(dir, 'package.json'))) {
78
+ const parent = dirname(dir);
79
+ if (parent === dir) break; // reached filesystem root; give up
80
+ dir = parent;
81
+ }
82
+ return resolve(dir, 'packages', 'registry');
83
+ }
84
+ const UI_REGISTRY_ROOT = resolveUiRegistryRoot();
65
85
 
66
86
  /**
67
87
  * Read a single @webjsdev/ui registry component, rewrite its relative import
@@ -622,10 +642,21 @@ export default function RootLayout({ children }: { children: unknown }) {
622
642
  <script>
623
643
  (function(){
624
644
  try {
625
- var t = localStorage.getItem('webjs_theme');
626
- if (t === 'light' || t === 'dark') {
627
- document.documentElement.dataset.theme = t;
645
+ var mq = window.matchMedia('(prefers-color-scheme: light)');
646
+ function apply(){
647
+ var t = null;
648
+ try { t = localStorage.getItem('webjs_theme'); } catch (_) {}
649
+ var el = document.documentElement;
650
+ if (t === 'light' || t === 'dark') el.dataset.theme = t;
651
+ else delete el.dataset.theme;
652
+ // Keep shadcn's .dark class in sync with the effective theme so the
653
+ // copied ui-* components (button, card, etc.) follow light/dark too.
654
+ // Dark is the default unless the OS prefers light or 'light' is set.
655
+ var dark = t === 'dark' || (t !== 'light' && !mq.matches);
656
+ el.classList.toggle('dark', dark);
628
657
  }
658
+ apply();
659
+ mq.addEventListener('change', apply);
629
660
  } catch (_) {}
630
661
  })();
631
662
  </script>
@@ -854,8 +885,13 @@ export class ThemeToggle extends WebComponent {
854
885
  if (next === 'system') localStorage.removeItem('webjs_theme');
855
886
  else localStorage.setItem('webjs_theme', next);
856
887
  } catch {}
857
- if (next === 'system') delete document.documentElement.dataset.theme;
858
- else document.documentElement.dataset.theme = next;
888
+ const el = document.documentElement;
889
+ if (next === 'system') delete el.dataset.theme;
890
+ else el.dataset.theme = next;
891
+ // Keep shadcn's .dark class in sync so the ui-* components follow the theme.
892
+ const dark = next === 'dark'
893
+ || (next === 'system' && !window.matchMedia('(prefers-color-scheme: light)').matches);
894
+ el.classList.toggle('dark', dark);
859
895
  }
860
896
 
861
897
  render() {
@@ -1008,7 +1044,7 @@ For AI agents, read this before editing scaffolded files:
1008
1044
  console.log(`
1009
1045
  Next steps:
1010
1046
  ${runCommand}
1011
- # → http://localhost:3000
1047
+ # → http://localhost:8080
1012
1048
 
1013
1049
  Optional:
1014
1050
  ${uiNote}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webjsdev/cli",
3
- "version": "0.8.6",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "description": "webjs CLI - dev, start, create, db",
6
6
  "bin": {
@@ -4,7 +4,7 @@
4
4
  # Opinionated defaults: set these and the framework auto-configures.
5
5
 
6
6
  # ── Server ──────────────────────────────────────────────────────────
7
- PORT=3000
7
+ PORT=8080
8
8
 
9
9
  # ── Auth (required for authentication) ──────────────────────────────
10
10
  # Generate: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
@@ -213,7 +213,7 @@ variables control infrastructure (no config files needed):
213
213
  | `AUTH_SECRET` | Required for auth JWT signing (32+ random chars) |
214
214
  | `AUTH_GOOGLE_ID` | Google OAuth client ID (optional) |
215
215
  | `AUTH_GITHUB_ID` | GitHub OAuth client ID (optional) |
216
- | `PORT` | Server port (default: 3000) |
216
+ | `PORT` | Server port (default: 8080) |
217
217
  | `WEBJS_PUBLIC_*` | Any env var starting with this prefix is exposed to the browser as `process.env.WEBJS_PUBLIC_X`. Components can read it directly. No build step, no transform. Use for API base URLs, Stripe publishable keys, analytics IDs, anything that is intended to be visible client-side. |
218
218
 
219
219
  **Server-only by default.** Any env var without the `WEBJS_PUBLIC_` prefix never reaches the browser. Reading `process.env.DATABASE_URL` from a component returns `undefined`, the same as a typo. The prefix is fail-closed: secrets cannot accidentally leak.
@@ -568,6 +568,17 @@ or a build-step pipeline. The framework has no hard dependency on Tailwind.
568
568
  If you mix custom CSS into a light-DOM component, apply the class-prefix
569
569
  rule (see Components section above).
570
570
 
571
+ **Dark mode uses two signals; a theme switch must set both.** The editorial
572
+ chrome tokens (`--fg`, `--bg`, `--accent`) follow a `data-theme` attribute on
573
+ `<html>`; the Webjs UI kit under `components/ui/` follows a `.dark` class
574
+ (`@custom-variant dark (&:is(.dark *))`). The scaffold's head init script and
575
+ `theme-toggle` set **both** (`data-theme` AND
576
+ `classList.toggle('dark', isDark)`). If you replace the toggle or build your
577
+ own theme switch, set both, or the `components/ui/*` render light tokens on a
578
+ dark page (white buttons and cards, invisible text) while the chrome looks
579
+ correct. Light mode hides this (both systems default to light), so **verify
580
+ dark mode in a browser, not just light.**
581
+
571
582
  ---
572
583
 
573
584
  ## Styling alternative: vanilla CSS end-to-end