@mauroandre/velojs 0.0.45 → 0.0.47

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.
@@ -106,6 +106,23 @@ refetch(); // e.g. aggregate counters
106
106
 
107
107
  > **Never mirror loader data into a module-level `export let`.** On the server, a module binding is per-process, not per-request — a value stored there belongs to whichever request wrote it last. `Loader`'s server value is an AsyncLocalStorage getter, so it is per-request by construction. That's the whole reason the handle is safe to export.
108
108
 
109
+ ## Redirecting from a loader
110
+
111
+ A loader may return a `Response` to short-circuit rendering — the common case is an auth gate that redirects instead of rendering the page:
112
+
113
+ ```typescript
114
+ export const loader = async ({ c }: LoaderArgs) => {
115
+ const user = c.get("user");
116
+ if (!user) return c.redirect("/login"); // no page render, no __PAGE_DATA__
117
+ return { projects: await listProjects(user) };
118
+ };
119
+ ```
120
+
121
+ - **Direct load / refresh:** the browser receives the `302` and navigates normally.
122
+ - **SPA navigation:** the `?_data=1` endpoint answers `{ __redirect: "/login" }` and the client does a full navigation (server state — session, cookies — may have changed, so it is not an SPA transition).
123
+
124
+ Any `Response` short-circuits, not only redirects (a `404` JSON, for example). If several loaders return one, the first in route order (layout → leaf) wins.
125
+
109
126
  ## When to use which
110
127
 
111
128
  | Scenario | Use |
@@ -141,3 +141,20 @@ export const action_save = async ({ body, c }: ActionArgs<{ name: string }>) =>
141
141
  ```
142
142
 
143
143
  This is the recommended pattern for passing authentication data (current user, permissions, etc) from middleware to your page code.
144
+
145
+ ### Typing `c.get()` — ContextVariableMap
146
+
147
+ `c.get("user")` does not compile out of the box: Hono's `Context` only accepts keys declared in `ContextVariableMap`. Augment it once in your app (e.g. in `app/types.d.ts`) and every `c.get`/`c.set` becomes typed — no casts, no helper functions:
148
+
149
+ ```typescript
150
+ import type { Usuario } from "./modules/auth/auth.types.js";
151
+
152
+ declare module "hono" {
153
+ interface ContextVariableMap {
154
+ user: Usuario;
155
+ }
156
+ }
157
+ ```
158
+
159
+ After this, `c.get("user")` returns `Usuario` in middlewares, loaders, and actions, and `c.get("anythingElse")` fails at compile time.
160
+
package/dist/hooks.js CHANGED
@@ -1,39 +1,39 @@
1
- import { signal as w, useSignal as c } from "@preact/signals";
2
- import { useEffect as E, useRef as S } from "preact/hooks";
3
- import { useLocation as b, useParams as A } from "wouter-preact";
4
- import { refetchModule as m, loaderLoading as L, loaderEntry as N } from "./loader-store.js";
5
- import { __veloUpdatePending as Q } from "./loader-store.js";
6
- function R(e) {
1
+ import { signal as S, useSignal as c } from "@preact/signals";
2
+ import { useEffect as E, useRef as w } from "preact/hooks";
3
+ import { useLocation as D, useParams as $, useSearch as C } from "wouter-preact";
4
+ import { refetchModule as L, loaderLoading as m, loaderEntry as N } from "./loader-store.js";
5
+ import { __veloUpdatePending as z } from "./loader-store.js";
6
+ function U(e) {
7
7
  const n = e.value;
8
8
  n === null || typeof n != "object" || (e.value = Array.isArray(n) ? [...n] : { ...n });
9
9
  }
10
- function U(e) {
10
+ function W(e) {
11
11
  return typeof window > "u" ? {
12
12
  data: {
13
13
  get value() {
14
14
  return e ? globalThis.__veloServerData?.getStore?.()?.[e] ?? null : null;
15
15
  }
16
16
  },
17
- loading: w(!1),
17
+ loading: S(!1),
18
18
  refetch: () => {
19
19
  }
20
20
  } : e ? {
21
21
  data: N(e),
22
- loading: L(e),
23
- refetch: () => m(e)
24
- } : { data: w(null), loading: w(!1), refetch: () => {
22
+ loading: m(e),
23
+ refetch: () => L(e)
24
+ } : { data: S(null), loading: S(!1), refetch: () => {
25
25
  } };
26
26
  }
27
- function W(e, n) {
27
+ function j(e, n) {
28
28
  let t, r;
29
29
  if (Array.isArray(e) ? r = e : (t = e, r = n), typeof window > "u") {
30
- let _ = null;
30
+ let g = null;
31
31
  if (t) {
32
32
  const h = globalThis.__veloServerData?.getStore?.();
33
- h?.[t] && (_ = h[t]);
33
+ h?.[t] && (g = h[t]);
34
34
  }
35
35
  return {
36
- data: c(_),
36
+ data: c(g),
37
37
  loading: c(!1),
38
38
  refetch: () => {
39
39
  }
@@ -42,108 +42,105 @@ function W(e, n) {
42
42
  if (!t)
43
43
  return { data: c(null), loading: c(!1), refetch: () => {
44
44
  } };
45
- const a = N(t), o = L(t), u = () => m(t), d = S(!0);
45
+ const o = N(t), a = m(t), u = () => L(t), d = w(!0);
46
46
  return E(() => {
47
- d.current && (d.current = !1, a.value !== null) || u();
48
- }, r ?? []), { data: a, loading: o, refetch: u };
47
+ d.current && (d.current = !1, o.value !== null) || u();
48
+ }, r ?? []), { data: o, loading: a, refetch: u };
49
49
  }
50
- function q() {
51
- const [, e] = b();
50
+ function J() {
51
+ const [, e] = D();
52
52
  return e;
53
53
  }
54
- function j() {
55
- return typeof window > "u" ? globalThis.__veloServerData?.getStore?.()?.__params ?? {} : A();
54
+ function M() {
55
+ return typeof window > "u" ? globalThis.__veloServerData?.getStore?.()?.__params ?? {} : $();
56
56
  }
57
- function G() {
57
+ function q() {
58
58
  if (typeof window > "u")
59
59
  return globalThis.__veloServerData?.getStore?.()?.__query ?? {};
60
- const e = window.__PAGE_DATA__;
61
- if (e?.__query)
62
- return e.__query;
63
- const n = new URLSearchParams(window.location.search), t = {};
64
- return n.forEach((r, a) => {
65
- t[a] = r;
66
- }), t;
60
+ const e = C(), n = {};
61
+ return new URLSearchParams(e).forEach((t, r) => {
62
+ n[r] = t;
63
+ }), n;
67
64
  }
68
- function J() {
69
- return typeof window > "u" ? globalThis.__veloServerData?.getStore?.()?.__pathname ?? "/" : (b(), window.location.pathname);
65
+ function x() {
66
+ return typeof window > "u" ? globalThis.__veloServerData?.getStore?.()?.__pathname ?? "/" : (D(), window.location.pathname);
70
67
  }
71
- function M(e, n = {}) {
72
- const t = c(null), r = c(null), a = c(!1), o = c(null), { channel: u, enabled: d = !0 } = n;
68
+ function G(e, n = {}) {
69
+ const t = c(null), r = c(null), o = c(!1), a = c(null), { channel: u, enabled: d = !0 } = n;
73
70
  return E(() => {
74
71
  if (typeof window > "u" || !d) return;
75
72
  if (!e.__path) {
76
73
  console.warn("[velojs] useEventStream: stream has no __path");
77
74
  return;
78
75
  }
79
- t.value = null, r.value = null, a.value = !1, o.value = null;
80
- const _ = u ? `${e.__path}?channel=${encodeURIComponent(u)}` : e.__path, s = new EventSource(_);
76
+ t.value = null, r.value = null, o.value = !1, a.value = null;
77
+ const g = u ? `${e.__path}?channel=${encodeURIComponent(u)}` : e.__path, s = new EventSource(g);
81
78
  return s.addEventListener("snapshot", (h) => {
82
79
  try {
83
80
  r.value = JSON.parse(h.data);
84
- } catch (y) {
85
- o.value = y;
81
+ } catch (_) {
82
+ a.value = _;
86
83
  }
87
84
  }), s.addEventListener("message", (h) => {
88
85
  try {
89
86
  t.value = JSON.parse(h.data);
90
- } catch (y) {
91
- o.value = y;
87
+ } catch (_) {
88
+ a.value = _;
92
89
  }
93
90
  }), s.addEventListener("heartbeat", () => {
94
91
  }), s.addEventListener("close", () => {
95
- a.value = !0, s.close();
92
+ o.value = !0, s.close();
96
93
  }), s.addEventListener("error", () => {
97
- s.readyState === EventSource.CLOSED && (a.value = !0);
94
+ s.readyState === EventSource.CLOSED && (o.value = !0);
98
95
  }), () => {
99
96
  s.close();
100
97
  };
101
- }, [e, u, d]), { data: t, snapshot: r, closed: a, error: o };
98
+ }, [e, u, d]), { data: t, snapshot: r, closed: o, error: a };
102
99
  }
103
- function x(e, n = {}) {
104
- const t = c("connecting"), r = c(null), a = c(null), o = S(null), u = S([]), { channel: d, onMessage: _, onOpen: s, onClose: h, onError: y, enabled: D = !0 } = n;
100
+ function B(e, n = {}) {
101
+ const t = c("connecting"), r = c(null), o = c(null), a = w(null), u = w([]), { channel: d, onMessage: g, onOpen: s, onClose: h, onError: _, enabled: b = !0 } = n;
105
102
  return E(() => {
106
- if (typeof window > "u" || !D) return;
103
+ if (typeof window > "u" || !b) return;
107
104
  if (!e.__path) {
108
105
  console.warn("[velojs] useSocket: stub has no __path");
109
106
  return;
110
107
  }
111
- t.value = "connecting", r.value = null, a.value = null;
108
+ t.value = "connecting", r.value = null, o.value = null;
112
109
  const v = `${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}`, i = d ? `${v}${e.__path}?channel=${encodeURIComponent(d)}` : `${v}${e.__path}`, f = new WebSocket(i);
113
- return f.binaryType = "arraybuffer", o.current = f, f.addEventListener("open", () => {
110
+ return f.binaryType = "arraybuffer", a.current = f, f.addEventListener("open", () => {
114
111
  t.value = "open";
115
112
  const l = u.current;
116
113
  u.current = [];
117
- for (const g of l)
114
+ for (const y of l)
118
115
  try {
119
- f.send(g);
116
+ f.send(y);
120
117
  } catch {
121
118
  }
122
119
  s?.();
123
120
  }), f.addEventListener("message", (l) => {
124
- let g;
121
+ let y;
125
122
  if (typeof l.data == "string")
126
- g = l.data;
123
+ y = l.data;
127
124
  else if (l.data instanceof ArrayBuffer)
128
- g = new Uint8Array(l.data);
125
+ y = new Uint8Array(l.data);
129
126
  else
130
127
  return;
131
- r.value = g, _?.(g);
128
+ r.value = y, g?.(y);
132
129
  }), f.addEventListener("close", (l) => {
133
- t.value = "closed", o.current = null, h?.(l);
130
+ t.value = "closed", a.current = null, h?.(l);
134
131
  }), f.addEventListener("error", (l) => {
135
- a.value = l, y?.(l);
132
+ o.value = l, _?.(l);
136
133
  }), () => {
137
- o.current = null;
134
+ a.current = null;
138
135
  try {
139
136
  (f.readyState === WebSocket.OPEN || f.readyState === WebSocket.CONNECTING) && f.close();
140
137
  } catch {
141
138
  }
142
139
  };
143
- }, [e.__path, d, D]), { send: (p) => {
140
+ }, [e.__path, d, b]), { send: (p) => {
144
141
  let v;
145
142
  typeof p == "string" || p instanceof Uint8Array ? v = p : v = JSON.stringify(p);
146
- const i = o.current;
143
+ const i = a.current;
147
144
  if (i && i.readyState === WebSocket.OPEN)
148
145
  try {
149
146
  i.send(v);
@@ -151,23 +148,23 @@ function x(e, n = {}) {
151
148
  }
152
149
  else i && i.readyState === WebSocket.CONNECTING && u.current.push(v);
153
150
  }, close: (p, v) => {
154
- const i = o.current;
151
+ const i = a.current;
155
152
  if (i)
156
153
  try {
157
154
  i.close(p, v);
158
155
  } catch {
159
156
  }
160
- }, status: t, lastMessage: r, error: a };
157
+ }, status: t, lastMessage: r, error: o };
161
158
  }
162
159
  export {
163
- U as Loader,
164
- Q as __veloUpdatePending,
165
- R as touch,
166
- M as useEventStream,
167
- W as useLoader,
168
- q as useNavigate,
169
- j as useParams,
170
- J as usePathname,
171
- G as useQuery,
172
- x as useSocket
160
+ W as Loader,
161
+ z as __veloUpdatePending,
162
+ U as touch,
163
+ G as useEventStream,
164
+ j as useLoader,
165
+ J as useNavigate,
166
+ M as useParams,
167
+ x as usePathname,
168
+ q as useQuery,
169
+ B as useSocket
173
170
  };
@@ -1,16 +1,16 @@
1
- import { signal as d } from "@preact/signals";
2
- const S = d(!1), c = /* @__PURE__ */ new Map(), _ = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Map();
3
- let u = /* @__PURE__ */ new Set();
4
- const l = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new WeakSet();
1
+ import { signal as u } from "@preact/signals";
2
+ const S = u(!1), c = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(), _ = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Map();
3
+ let d = /* @__PURE__ */ new Set();
4
+ const l = /* @__PURE__ */ new Map(), g = /* @__PURE__ */ new WeakSet();
5
5
  let w = !1;
6
6
  function E(t) {
7
7
  v();
8
8
  let e = c.get(t);
9
- return e || (e = d(null), c.set(t, e)), e;
9
+ return e || (e = u(null), c.set(t, e)), e;
10
10
  }
11
- function g(t) {
12
- let e = _.get(t);
13
- return e || (e = d(!1), _.set(t, e)), e;
11
+ function y(t) {
12
+ let e = h.get(t);
13
+ return e || (e = u(!1), h.set(t, e)), e;
14
14
  }
15
15
  function v() {
16
16
  if (w || typeof window > "u") return;
@@ -20,22 +20,22 @@ function v() {
20
20
  for (const e of Object.keys(t)) {
21
21
  if (e.startsWith("__")) continue;
22
22
  let n = c.get(e);
23
- n || (n = d(null), c.set(e, n)), n.value = t[e];
23
+ n || (n = u(null), c.set(e, n)), n.value = t[e];
24
24
  }
25
25
  }
26
26
  function x(t) {
27
- if (y.has(t)) return;
28
- y.add(t);
27
+ if (g.has(t)) return;
28
+ g.add(t);
29
29
  const e = (n) => {
30
30
  for (const o of n) {
31
31
  const i = o.module?.metadata;
32
- i?.moduleId && i.fullPath !== void 0 && (f.set(i.moduleId, i.fullPath), (!o.children || o.children.length === 0) && h.add(i.moduleId)), o.children && e(o.children);
32
+ i?.moduleId && i.fullPath !== void 0 && (f.set(i.moduleId, i.fullPath), (!o.children || o.children.length === 0) && _.add(i.moduleId)), o.children && e(o.children);
33
33
  }
34
34
  };
35
35
  if (e(t), typeof window < "u") {
36
36
  v();
37
37
  for (const n of c.keys()) M(n, window.location.pathname);
38
- u = L(window.location.pathname);
38
+ d = L(window.location.pathname);
39
39
  }
40
40
  }
41
41
  const P = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -51,7 +51,7 @@ function m(t, e, n = !1) {
51
51
  }
52
52
  function O(t, e) {
53
53
  const n = f.get(t);
54
- return n === void 0 ? !1 : m(n, e, h.has(t)) !== null;
54
+ return n === void 0 ? !1 : m(n, e, _.has(t)) !== null;
55
55
  }
56
56
  function L(t) {
57
57
  const e = /* @__PURE__ */ new Set();
@@ -62,7 +62,7 @@ function L(t) {
62
62
  function k(t, e) {
63
63
  const n = f.get(t);
64
64
  if (n === void 0) return null;
65
- const o = m(n, e, h.has(t));
65
+ const o = m(n, e, _.has(t));
66
66
  return o === null ? null : JSON.stringify(o);
67
67
  }
68
68
  function M(t, e) {
@@ -77,18 +77,22 @@ function H(t) {
77
77
  async function $(t, e, n) {
78
78
  if (typeof window > "u" || t.length === 0) return;
79
79
  const o = H(e);
80
- for (const a of t) g(a).value = !0;
80
+ for (const a of t) y(a).value = !0;
81
81
  let i = n ? l.get(o) : void 0;
82
82
  i || (i = fetch(o, { cache: "no-cache" }).then((a) => a.json()), n && (l.set(o, i), i.catch(() => {
83
83
  }).then(() => l.delete(o))));
84
84
  try {
85
85
  const a = await i;
86
+ if (a.__redirect) {
87
+ window.location.href = String(a.__redirect);
88
+ return;
89
+ }
86
90
  typeof __VELO_BUILD_HASH__ < "u" && a.__buildHash && a.__buildHash !== __VELO_BUILD_HASH__ && (S.value = !0);
87
91
  for (const r of t)
88
92
  r in a && (E(r).value = a[r], M(r, e));
89
93
  } catch {
90
94
  } finally {
91
- for (const a of t) g(a).value = !1;
95
+ for (const a of t) y(a).value = !1;
92
96
  }
93
97
  }
94
98
  function T(t) {
@@ -97,22 +101,22 @@ function T(t) {
97
101
  for (const o of c.keys()) {
98
102
  if (!n.has(o)) continue;
99
103
  const i = k(o, t);
100
- p.get(o) === i && u.has(o) || e.push(o);
104
+ p.get(o) === i && d.has(o) || e.push(o);
101
105
  }
102
- u = n, $(e, t, !0);
106
+ d = n, $(e, t, !0);
103
107
  }
104
108
  function U(t) {
105
109
  typeof window > "u" || $([t], window.location.pathname, !1);
106
110
  }
107
111
  function D() {
108
- c.clear(), _.clear(), f.clear(), h.clear(), p.clear(), u = /* @__PURE__ */ new Set(), l.clear(), w = !1, S.value = !1;
112
+ c.clear(), h.clear(), f.clear(), _.clear(), p.clear(), d = /* @__PURE__ */ new Set(), l.clear(), w = !1, S.value = !1;
109
113
  }
110
114
  export {
111
115
  D as __resetLoaderStore,
112
116
  S as __veloUpdatePending,
113
117
  m as extractParams,
114
118
  E as loaderEntry,
115
- g as loaderLoading,
119
+ y as loaderLoading,
116
120
  U as refetchModule,
117
121
  x as registerRoutePatterns,
118
122
  T as syncLocation
package/dist/server.js CHANGED
@@ -1,15 +1,15 @@
1
- import { jsx as g } from "preact/jsx-runtime";
2
- import { Hono as R } from "hono";
3
- import { logger as T } from "hono/logger";
4
- import { trimTrailingSlash as j } from "hono/trailing-slash";
5
- import { render as A } from "preact-render-to-string";
6
- import { Router as C } from "wouter-preact";
7
- import { AsyncLocalStorage as k } from "node:async_hooks";
1
+ import { jsx as _ } from "preact/jsx-runtime";
2
+ import { Hono as j } from "hono";
3
+ import { logger as E } from "hono/logger";
4
+ import { trimTrailingSlash as T } from "hono/trailing-slash";
5
+ import { render as C } from "preact-render-to-string";
6
+ import { Router as k } from "wouter-preact";
7
+ import { AsyncLocalStorage as A } from "node:async_hooks";
8
8
  import { getAppContext as w } from "./app-context.js";
9
- import { flushPendingStreamRoutes as $, registerStreamHandler as D } from "./events.js";
10
- import { registerSocketRoutes as I, injectWebSocketServer as y } from "./sockets.js";
11
- const S = new k();
12
- globalThis.__veloServerData = S;
9
+ import { flushPendingStreamRoutes as D, registerStreamHandler as $ } from "./events.js";
10
+ import { registerSocketRoutes as I, injectWebSocketServer as S } from "./sockets.js";
11
+ const P = new A();
12
+ globalThis.__veloServerData = P;
13
13
  let v = null;
14
14
  function Y(e) {
15
15
  if (v) {
@@ -18,7 +18,7 @@ function Y(e) {
18
18
  }
19
19
  w().serverCallbacks.push(e);
20
20
  }
21
- function P(e) {
21
+ function b(e) {
22
22
  v = e;
23
23
  const t = w();
24
24
  for (const s of t.serverCallbacks) s(e);
@@ -29,12 +29,12 @@ function Z(e) {
29
29
  }
30
30
  const N = (e, t, s, r) => {
31
31
  if (r && r !== 200 && e.status(r), e.req.query("_data") === "1") {
32
- const i = globalThis.__veloBuildHash || void 0, l = s ? { ...s, __buildHash: i } : { __buildHash: i };
33
- return e.json(l);
32
+ const c = globalThis.__veloBuildHash || void 0, i = s ? { ...s, __buildHash: c } : { __buildHash: c };
33
+ return e.json(i);
34
34
  }
35
- const o = e.req.path, n = S.run(
35
+ const o = e.req.path, n = P.run(
36
36
  s ?? {},
37
- () => A(/* @__PURE__ */ g(C, { ssrPath: o, children: t }))
37
+ () => C(/* @__PURE__ */ _(k, { ssrPath: o, children: t }))
38
38
  );
39
39
  if (e.header("Cache-Control", "no-cache"), !s)
40
40
  return e.html(n);
@@ -46,19 +46,27 @@ const N = (e, t, s, r) => {
46
46
  const s = t.req.param(), r = t.req.query(), o = { params: s, query: r, c: t }, n = await Promise.all(
47
47
  e.map(async (i) => {
48
48
  if (!i.loader) return null;
49
- const l = await i.loader(o), c = i.metadata?.moduleId;
50
- return c ? { moduleId: c, loaderData: l } : null;
49
+ const l = await i.loader(o), d = i.metadata?.moduleId;
50
+ return d ? { moduleId: d, loaderData: l } : null;
51
51
  })
52
- ), a = {
52
+ );
53
+ let a;
54
+ for (const i of n)
55
+ if (i && i.loaderData instanceof Response) {
56
+ a = i.loaderData;
57
+ break;
58
+ }
59
+ const c = {
53
60
  __params: s,
54
61
  __query: r,
55
62
  __pathname: t.req.path
56
63
  };
57
64
  for (const i of n)
58
- i && (a[i.moduleId] = i.loaderData);
65
+ i && !(i.loaderData instanceof Response) && (c[i.moduleId] = i.loaderData);
59
66
  return {
60
67
  components: e.map((i) => i.Component),
61
- data: a
68
+ data: c,
69
+ shortCircuit: a
62
70
  };
63
71
  }, G = (e) => {
64
72
  if (e.length === 0) return null;
@@ -66,14 +74,14 @@ const N = (e, t, s, r) => {
66
74
  if (t.length === 0) return null;
67
75
  if (t.length === 1) {
68
76
  const o = t[0];
69
- return /* @__PURE__ */ g(o, {});
77
+ return /* @__PURE__ */ _(o, {});
70
78
  }
71
79
  const s = t[t.length - 1];
72
- return t.slice(0, -1).reduceRight((o, n) => /* @__PURE__ */ g(n, { children: o }), /* @__PURE__ */ g(s, {}));
73
- }, _ = (e, t, s = [], r = []) => {
80
+ return t.slice(0, -1).reduceRight((o, n) => /* @__PURE__ */ _(n, { children: o }), /* @__PURE__ */ _(s, {}));
81
+ }, y = (e, t, s = [], r = []) => {
74
82
  for (const o of t) {
75
83
  if (o.handler && !o.module) {
76
- o.children && _(
84
+ o.children && y(
77
85
  e,
78
86
  o.children,
79
87
  s,
@@ -86,29 +94,34 @@ const N = (e, t, s, r) => {
86
94
  ...o.middlewares || []
87
95
  ];
88
96
  if (o.children)
89
- _(
97
+ y(
90
98
  e,
91
99
  o.children,
92
100
  n,
93
101
  a
94
102
  );
95
103
  else if (o.module) {
96
- const i = o.path === "*", l = o.statusCode ?? (i ? 404 : void 0), c = o.module.metadata?.fullPath;
97
- if (!c && !i) {
104
+ const c = o.path === "*", i = o.statusCode ?? (c ? 404 : void 0), l = o.module.metadata?.fullPath;
105
+ if (!l && !c) {
98
106
  console.warn(
99
107
  `Module ${o.module.metadata?.moduleId} has no fullPath`
100
108
  );
101
109
  continue;
102
110
  }
103
- const u = async (h) => {
104
- const { components: d, data: m } = await O(n, h), f = G(d);
105
- return N(h, f, m, l);
111
+ const d = async (h) => {
112
+ const { components: u, data: m, shortCircuit: f } = await O(n, h);
113
+ if (f) {
114
+ const g = f.headers.get("Location");
115
+ return h.req.query("_data") === "1" && g && f.status >= 300 && f.status < 400 ? h.json({ __redirect: g }) : f;
116
+ }
117
+ const p = G(u);
118
+ return N(h, p, m, i);
106
119
  };
107
- i ? e.notFound(u) : a.length > 0 ? e.on(["GET"], [c], ...a, u) : e.on(["GET"], [c], u);
120
+ c ? e.notFound(d) : a.length > 0 ? e.on(["GET"], [l], ...a, d) : e.on(["GET"], [l], d);
108
121
  } else
109
122
  continue;
110
123
  }
111
- }, b = (e, t, s = []) => {
124
+ }, q = (e, t, s = []) => {
112
125
  for (const r of t) {
113
126
  const o = r.module?.metadata?.moduleId, n = [
114
127
  ...s,
@@ -116,67 +129,67 @@ const N = (e, t, s, r) => {
116
129
  ];
117
130
  if (r.module && o) {
118
131
  const a = Object.keys(r.module).filter(
119
- (i) => i.startsWith("action_")
132
+ (c) => c.startsWith("action_")
120
133
  );
121
- for (const i of a) {
122
- const l = i.replace("action_", ""), c = r.module[i];
123
- if (typeof c == "function") {
124
- const u = `/_action/${o}/${l}`, h = async (d) => {
134
+ for (const c of a) {
135
+ const i = c.replace("action_", ""), l = r.module[c];
136
+ if (typeof l == "function") {
137
+ const d = `/_action/${o}/${i}`, h = async (u) => {
125
138
  let m = {};
126
139
  try {
127
- m = await d.req.json();
140
+ m = await u.req.json();
128
141
  } catch {
129
142
  }
130
143
  const f = {
131
144
  body: m,
132
- params: d.req.param(),
133
- query: d.req.query(),
134
- c: d
145
+ params: u.req.param(),
146
+ query: u.req.query(),
147
+ c: u
135
148
  };
136
149
  try {
137
- const p = await c(f);
138
- return d.json(p ?? { ok: !0 });
150
+ const p = await l(f);
151
+ return u.json(p ?? { ok: !0 });
139
152
  } catch (p) {
140
- const E = p instanceof Error ? p.message : "Action failed";
141
- return d.json({ error: E }, 500);
153
+ const g = p instanceof Error ? p.message : "Action failed";
154
+ return u.json({ error: g }, 500);
142
155
  }
143
156
  };
144
157
  n.length > 0 ? e.on(
145
158
  ["POST"],
146
- [u],
159
+ [d],
147
160
  ...n,
148
161
  h
149
- ) : e.on(["POST"], [u], h);
162
+ ) : e.on(["POST"], [d], h);
150
163
  }
151
164
  }
152
165
  }
153
- r.children && b(e, r.children, n);
166
+ r.children && q(e, r.children, n);
154
167
  }
155
168
  }, H = async (e, t, s = []) => {
156
169
  const r = (o, n) => {
157
170
  for (const a of o) {
158
- const i = a.module?.metadata?.moduleId, l = [
171
+ const c = a.module?.metadata?.moduleId, i = [
159
172
  ...n,
160
173
  ...a.middlewares || []
161
174
  ];
162
- if (a.module && i) {
163
- const c = Object.keys(a.module).filter(
164
- (u) => u.startsWith("stream_")
175
+ if (a.module && c) {
176
+ const l = Object.keys(a.module).filter(
177
+ (d) => d.startsWith("stream_")
165
178
  );
166
- for (const u of c) {
167
- const h = u.replace("stream_", ""), d = a.module[u];
168
- if (d?.__isVeloEventStream) {
169
- const m = `/_event/${i}/${h}`;
170
- d.__path = m, D(
179
+ for (const d of l) {
180
+ const h = d.replace("stream_", ""), u = a.module[d];
181
+ if (u?.__isVeloEventStream) {
182
+ const m = `/_event/${c}/${h}`;
183
+ u.__path = m, $(
171
184
  e,
172
185
  m,
173
- d,
174
- l
186
+ u,
187
+ i
175
188
  );
176
189
  }
177
190
  }
178
191
  }
179
- a.children && r(a.children, l);
192
+ a.children && r(a.children, i);
180
193
  }
181
194
  };
182
195
  r(t, s);
@@ -191,60 +204,60 @@ const N = (e, t, s, r) => {
191
204
  }
192
205
  };
193
206
  return s(e), t;
194
- }, q = (e, t, s, r = "", o = []) => {
207
+ }, R = (e, t, s, r = "", o = []) => {
195
208
  for (const n of t) {
196
- const a = x(r, n.path), i = [
209
+ const a = x(r, n.path), c = [
197
210
  ...o,
198
211
  ...n.middlewares || []
199
- ], l = !!n.handler, c = !!n.method;
200
- if (l && !c ? console.warn(
212
+ ], i = !!n.handler, l = !!n.method;
213
+ if (i && !l ? console.warn(
201
214
  `[velojs] invalid route at "${a || "/"}" — "handler" set without "method"; endpoint skipped`
202
- ) : c && !l ? console.warn(
215
+ ) : l && !i ? console.warn(
203
216
  `[velojs] invalid route at "${a || "/"}" — "method" set without "handler"; endpoint skipped`
204
- ) : l && n.module ? console.warn(
217
+ ) : i && n.module ? console.warn(
205
218
  `[velojs] ambiguous route at "${a || "/"}" — both "module" and "handler" set; endpoint ignored, page kept`
206
- ) : l && n.isRoot && console.warn(
219
+ ) : i && n.isRoot && console.warn(
207
220
  `[velojs] "isRoot" has no effect on endpoint at "${a || "/"}"; ignored`
208
- ), l && c && !n.module) {
221
+ ), i && l && !n.module) {
209
222
  const h = n.method;
210
223
  h === "GET" && s.has(a) && console.warn(
211
224
  `[velojs] path "${a}" has both a page GET and an endpoint GET; the page wins and the endpoint is unreachable. Consider renaming one.`
212
225
  );
213
- const d = n.handler, m = async (f) => await d({
226
+ const u = n.handler, m = async (f) => await u({
214
227
  c: f,
215
228
  params: f.req.param(),
216
229
  query: f.req.query()
217
230
  });
218
- i.length > 0 ? e.on([h], [a], ...i, m) : e.on([h], [a], m);
231
+ c.length > 0 ? e.on([h], [a], ...c, m) : e.on([h], [a], m);
219
232
  }
220
- n.children && q(
233
+ n.children && R(
221
234
  e,
222
235
  n.children,
223
236
  s,
224
237
  a,
225
- i
238
+ c
226
239
  );
227
240
  }
228
241
  }, W = async (e) => {
229
- const t = new R();
230
- t.use(j()), process.env.NODE_ENV !== "production" && t.use("*", T());
242
+ const t = new j();
243
+ t.use(T()), process.env.NODE_ENV !== "production" && t.use("*", E());
231
244
  const r = w().pendingRoutes.splice(0);
232
245
  for (const n of r)
233
246
  await n(t);
234
- _(t, e), b(t, e), await H(t, e);
247
+ y(t, e), q(t, e), await H(t, e);
235
248
  const o = V(e);
236
- if (q(t, e, o), await I(t, e), $(t), process.env.NODE_ENV !== "production" && !v) {
249
+ if (R(t, e, o), await I(t, e), D(t), process.env.NODE_ENV !== "production" && !v) {
237
250
  const n = globalThis.__veloDevServer;
238
- n && (P(n), await y(t, n));
251
+ n && (b(n), await S(t, n));
239
252
  }
240
253
  return t;
241
254
  }, ee = async (e) => {
242
255
  const { routes: t } = e, s = Number(process.env.PORT) || e.port || 3e3, r = await W(t);
243
256
  if (process.env.NODE_ENV === "production" && !process.env.VELO_STATIC) {
244
- const { serve: o } = await import("@hono/node-server"), { serveStatic: n } = await import("@hono/node-server/serve-static"), { join: a } = await import("node:path"), i = a(process.cwd(), "dist/client");
245
- (process.env.STATIC_BASE_URL || "").startsWith("http") || r.use("/*", n({ root: i })), console.log(`Server running on http://localhost:${s}`);
246
- const c = o({ fetch: r.fetch, port: s });
247
- await y(r, c), P(c);
257
+ const { serve: o } = await import("@hono/node-server"), { serveStatic: n } = await import("@hono/node-server/serve-static"), { join: a } = await import("node:path"), c = a(process.cwd(), "dist/client");
258
+ (process.env.STATIC_BASE_URL || "").startsWith("http") || r.use("/*", n({ root: c })), console.log(`Server running on http://localhost:${s}`);
259
+ const l = o({ fetch: r.fetch, port: s });
260
+ await S(r, l), b(l);
248
261
  }
249
262
  return r;
250
263
  };
@@ -253,6 +266,6 @@ export {
253
266
  W as createApp,
254
267
  W as default,
255
268
  Y as onServer,
256
- S as serverDataStorage,
269
+ P as serverDataStorage,
257
270
  ee as startServer
258
271
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mauroandre/velojs",
3
- "version": "0.0.45",
3
+ "version": "0.0.47",
4
4
  "type": "module",
5
5
  "description": "Fullstack web framework built on Hono + Preact with Vite-powered AST transforms",
6
6
  "keywords": [