glashjs 0.13.3 → 0.13.5

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/bin/glash.mjs CHANGED
@@ -42,6 +42,20 @@ function firstPositional(args = rest) {
42
42
  return undefined;
43
43
  }
44
44
 
45
+ // A compact terminal rendering of the glashjs favicon — the metallic glash mark
46
+ // (a rounded square). Shown in the dev/serve banner so the brand favicon is
47
+ // visible right in the CLI. ANSI-colored on a TTY; plain blocks otherwise.
48
+ function glashMark() {
49
+ const tty = process.stdout.isTTY;
50
+ const hi = (s) => (tty ? `\x1b[97m${s}\x1b[0m` : s); // bright white highlight
51
+ const mid = (s) => (tty ? `\x1b[38;5;250m${s}\x1b[0m` : s); // light grey shading
52
+ return [
53
+ ' ' + hi('▟██████▙'),
54
+ ' ' + hi('██') + mid('████') + hi('██'),
55
+ ' ' + hi('▜██████▛'),
56
+ ];
57
+ }
58
+
45
59
  // LAN IPv4 addresses, so the dev server prints a Network URL you can open from
46
60
  // your phone or another device on the same network.
47
61
  function lanAddresses() {
@@ -62,7 +76,9 @@ async function serve(dev) {
62
76
  const port = await listenOnAvailablePort(listen, preferredPort);
63
77
  const pages = routes.filter((r) => !r.isApi).length;
64
78
  const apis = routes.filter((r) => r.isApi).length;
65
- console.log(`\nglashjs ${dev ? 'dev' : 'serve'} — "${cfg.name}"`);
79
+ console.log('');
80
+ for (const line of glashMark()) console.log(line);
81
+ console.log(` glashjs ${dev ? 'dev' : 'serve'} — "${cfg.name}"`);
66
82
  if (port !== preferredPort) console.log(` Port ${preferredPort} is in use; using ${port} instead.`);
67
83
  console.log(` ${pages} page route(s), ${apis} api route(s)`);
68
84
  routes.forEach((r) => console.log(` ${r.isApi ? 'api ' : 'page'} ${r.pattern}`));
@@ -157,7 +173,7 @@ async function main() {
157
173
  console.log('glashjs ' + VERSION);
158
174
  break;
159
175
  default:
160
- console.log(`glashjs — fast, offline-capable, hard-to-hack sites
176
+ console.log(`glashjs — fast, offline-capable, secure-by-default sites
161
177
 
162
178
  Usage: (run as "glashjs <cmd>"; "glash <cmd>" also works unless the glashdb deploy CLI owns that name)
163
179
  glashjs run dev Alias for glashjs dev (also: glash run dev)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glashjs",
3
- "version": "0.13.3",
3
+ "version": "0.13.5",
4
4
  "description": "glashjs — The Postgres-native full-stack framework for builders who want to ship without DevOps. Framework, hosting, database, auth, and deploy in one GlashDB-native runtime.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/create.mjs CHANGED
@@ -4,9 +4,10 @@
4
4
 
5
5
  import { spawn } from 'node:child_process';
6
6
  import { randomBytes } from 'node:crypto';
7
- import { promises as fs } from 'node:fs';
7
+ import { promises as fs, readFileSync } from 'node:fs';
8
8
  import { createInterface } from 'node:readline/promises';
9
9
  import path from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
10
11
  import { generateTypedRoutes } from './typed-routes.mjs';
11
12
 
12
13
  const CSS_CHOICES = new Set(['tailwind', 'plain', 'none']);
@@ -475,12 +476,18 @@ function tailwindInput() {
475
476
  }
476
477
 
477
478
  function faviconSvg() {
478
- return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
479
- <rect width="64" height="64" rx="14" fill="#050505"/>
480
- <circle cx="32" cy="32" r="17" fill="#f97316"/>
481
- <circle cx="32" cy="32" r="7" fill="#050505"/>
479
+ // Use the bundled glash mark (the official metallic glash favicon) so a new
480
+ // app ships the real brand favicon, not a placeholder. Single source of truth:
481
+ // glashjs/templates/favicon.svg.
482
+ try {
483
+ return readFileSync(fileURLToPath(new URL('../templates/favicon.svg', import.meta.url)), 'utf8');
484
+ } catch {
485
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
486
+ <rect width="64" height="64" rx="14" fill="#0a0a0a"/>
487
+ <rect x="13" y="13" width="38" height="38" rx="11" fill="#d4d4d4"/>
482
488
  </svg>
483
489
  `;
490
+ }
484
491
  }
485
492
 
486
493
  function gitignore() {
@@ -54,6 +54,15 @@ const REACT_ALIAS = {
54
54
  'next/headers': path.join(pkgRoot, 'next/headers.mjs'),
55
55
  };
56
56
 
57
+ // CJS deps bundled into an ESM server module (e.g. lucide-react -> require('react')
58
+ // -> aliased preact/compat, which is external) emit a dynamic require that ESM
59
+ // can't run ("Dynamic require of X is not supported"). Defining `require` via
60
+ // createRequire makes esbuild's __require shim use the real Node require, so those
61
+ // runtime requires resolve from the app's node_modules.
62
+ const NODE_ESM_REQUIRE_BANNER = {
63
+ js: "import { createRequire as __glashCreateRequire } from 'node:module';\nconst require = __glashCreateRequire(import.meta.url);",
64
+ };
65
+
57
66
  export function isComponentRoute(file) {
58
67
  return /\.(jsx|tsx)$/.test(file);
59
68
  }
@@ -76,7 +85,7 @@ export async function compileModule(file, root, dev) {
76
85
  entryPoints: [file], bundle: true, platform: 'node', format: 'esm',
77
86
  jsx: 'automatic', jsxImportSource: 'preact',
78
87
  external: ['preact', 'preact/*', 'preact-render-to-string'],
79
- alias: REACT_ALIAS, outfile: out, logLevel: 'silent',
88
+ alias: REACT_ALIAS, banner: NODE_ESM_REQUIRE_BANNER, outfile: out, logLevel: 'silent',
80
89
  });
81
90
  return import(pathToFileURL(out).href + (dev ? `?t=${Date.now()}` : ''));
82
91
  }
@@ -158,7 +167,7 @@ export async function loadComponentRoute(pageFile, layouts, root, dev, force = f
158
167
  stdin: { contents: serverEntry(pageFile, layouts), resolveDir: path.dirname(pageFile), loader: 'js', sourcefile: 'glash-server-entry.js' },
159
168
  bundle: true, platform: 'node', format: 'esm', jsx: 'automatic', jsxImportSource: 'preact',
160
169
  external: ['preact', 'preact/*', 'preact-render-to-string'],
161
- alias: REACT_ALIAS,
170
+ alias: REACT_ALIAS, banner: NODE_ESM_REQUIRE_BANNER,
162
171
  outfile: out, logLevel: 'silent',
163
172
  });
164
173
  const mod = await import(pathToFileURL(out).href + (dev ? `?t=${Date.now()}` : ''));