glashjs 0.13.1 → 0.13.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glashjs",
3
- "version": "0.13.1",
3
+ "version": "0.13.3",
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": {
@@ -0,0 +1,16 @@
1
+ // Minimal next/dynamic compatibility for migrated client components.
2
+ import { h } from 'preact';
3
+ import { lazy, Suspense } from 'preact/compat';
4
+
5
+ export default function dynamic(loader, options = {}) {
6
+ const Lazy = lazy(async () => {
7
+ const mod = await loader();
8
+ return { default: mod.default || mod };
9
+ });
10
+ const Loading = options.loading;
11
+
12
+ return function DynamicComponent(props) {
13
+ const fallback = Loading ? h(Loading, props) : null;
14
+ return h(Suspense, { fallback }, h(Lazy, props));
15
+ };
16
+ }
@@ -0,0 +1,23 @@
1
+ // Minimal next/headers compatibility for migrated API helpers.
2
+ // Glash handlers should prefer ctx.headers/cookies, but these no-op shims keep
3
+ // shared Next-era utilities importable during migration.
4
+
5
+ function emptyCookieStore() {
6
+ return {
7
+ get: () => undefined,
8
+ getAll: () => [],
9
+ has: () => false,
10
+ set: () => {},
11
+ delete: () => {},
12
+ clear: () => {},
13
+ toString: () => '',
14
+ };
15
+ }
16
+
17
+ export function cookies() {
18
+ return emptyCookieStore();
19
+ }
20
+
21
+ export function headers() {
22
+ return new Headers();
23
+ }
@@ -0,0 +1,50 @@
1
+ // Minimal Next navigation compatibility for migrated Glash routes.
2
+ // These browser-first shims keep common client components running without
3
+ // dragging the Next runtime into the Glash server bundle.
4
+
5
+ function hrefOf(href) {
6
+ if (typeof href === 'string') return href;
7
+ if (href && typeof href === 'object') {
8
+ const pathname = href.pathname || '';
9
+ const query = href.query ? `?${new URLSearchParams(href.query).toString()}` : '';
10
+ const hash = href.hash || '';
11
+ return `${pathname}${query}${hash}`;
12
+ }
13
+ return '/';
14
+ }
15
+
16
+ export function useRouter() {
17
+ return {
18
+ push: (href) => { if (typeof window !== 'undefined') window.location.assign(hrefOf(href)); },
19
+ replace: (href) => { if (typeof window !== 'undefined') window.location.replace(hrefOf(href)); },
20
+ refresh: () => { if (typeof window !== 'undefined') window.location.reload(); },
21
+ back: () => { if (typeof window !== 'undefined') window.history.back(); },
22
+ forward: () => { if (typeof window !== 'undefined') window.history.forward(); },
23
+ prefetch: () => Promise.resolve(),
24
+ };
25
+ }
26
+
27
+ export function usePathname() {
28
+ return typeof window === 'undefined' ? '/' : window.location.pathname;
29
+ }
30
+
31
+ export function useSearchParams() {
32
+ return new URLSearchParams(typeof window === 'undefined' ? '' : window.location.search);
33
+ }
34
+
35
+ export function useParams() {
36
+ return {};
37
+ }
38
+
39
+ export function redirect(href) {
40
+ if (typeof window !== 'undefined') window.location.replace(hrefOf(href));
41
+ const error = new Error(`NEXT_REDIRECT:${hrefOf(href)}`);
42
+ error.digest = `NEXT_REDIRECT;replace;${hrefOf(href)};307;`;
43
+ throw error;
44
+ }
45
+
46
+ export function notFound() {
47
+ const error = new Error('NEXT_NOT_FOUND');
48
+ error.status = 404;
49
+ throw error;
50
+ }
@@ -16,7 +16,7 @@
16
16
  import { promises as fs, existsSync } from 'node:fs';
17
17
  import path from 'node:path';
18
18
  import { createHash } from 'node:crypto';
19
- import { pathToFileURL } from 'node:url';
19
+ import { fileURLToPath, pathToFileURL } from 'node:url';
20
20
 
21
21
  const MISSING = 'JSX/TSX routes need the optional peers: npm i esbuild preact preact-render-to-string';
22
22
 
@@ -38,13 +38,20 @@ async function preactRuntime() {
38
38
  return { h: _h, renderToString: _renderToString };
39
39
  }
40
40
 
41
- // Make migrated React/Next components compile + run under Preact.
41
+ const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
42
+
43
+ // Make migrated React/Next components compile + run under Preact/Glash.
42
44
  const REACT_ALIAS = {
43
45
  react: 'preact/compat',
44
46
  'react-dom': 'preact/compat',
45
47
  'react-dom/client': 'preact/compat',
46
48
  'react/jsx-runtime': 'preact/jsx-runtime',
47
49
  'react/jsx-dev-runtime': 'preact/jsx-runtime',
50
+ 'next/link': path.join(pkgRoot, 'components/link.mjs'),
51
+ 'next/image': path.join(pkgRoot, 'components/image.mjs'),
52
+ 'next/navigation': path.join(pkgRoot, 'next/navigation.mjs'),
53
+ 'next/dynamic': path.join(pkgRoot, 'next/dynamic.mjs'),
54
+ 'next/headers': path.join(pkgRoot, 'next/headers.mjs'),
48
55
  };
49
56
 
50
57
  export function isComponentRoute(file) {
@@ -34,6 +34,7 @@ export async function createGlashServer({ root = process.cwd(), dev = false } =
34
34
  const cfg = await loadConfig(root);
35
35
  const routesDir = path.resolve(root, cfg.routesDir || 'routes');
36
36
  const outDir = path.resolve(root, cfg.outDir);
37
+ const publicDir = path.resolve(root, cfg.publicDir || 'public');
37
38
  const secHeaders = securityHeaders(cfg.security);
38
39
  let routes = await discoverRoutes(routesDir);
39
40
 
@@ -72,6 +73,7 @@ export async function createGlashServer({ root = process.cwd(), dev = false } =
72
73
  // Static first: in production this serves prebuilt /_glash/<id>.js bundles
73
74
  // (written by `glash build`) — no runtime esbuild needed.
74
75
  if (await serveStatic(res, outDir, pathname, req, secHeaders)) return;
76
+ if (dev && publicDir !== outDir && await serveStatic(res, publicDir, pathname, req, secHeaders)) return;
75
77
  // Dynamic hydration bundles (dev, or when not prebuilt): /_glash/<routeId>.js
76
78
  if (pathname.startsWith('/_glash/')) {
77
79
  const id = pathname.slice('/_glash/'.length).replace(/\.js$/, '');
@@ -134,7 +136,7 @@ export async function createGlashServer({ root = process.cwd(), dev = false } =
134
136
  server.listen(port, host);
135
137
  });
136
138
 
137
- return { server, listen, cfg, routes, routesDir, outDir };
139
+ return { server, listen, cfg, routes, routesDir, outDir, publicDir };
138
140
  }
139
141
 
140
142
  async function handleApi(res, mod, req, ctx, secHeaders) {