@mauroandre/velojs 0.0.50 → 0.0.51

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.
@@ -71,6 +71,45 @@ export default defineConfig({
71
71
 
72
72
  In dev, `velojs dev --port 5000` still overrides everything (it's passed straight to Vite).
73
73
 
74
+ ## Choosing the bind interface (hostname)
75
+
76
+ By default `velojs start` binds to **all interfaces** (`::`) — the norm for Node servers and what containers and cloud platforms expect (they route traffic through the network interface; loopback-only would make the container unreachable). To change it, in order of precedence:
77
+
78
+ 1. The `HOST` environment variable.
79
+ 2. The `hostname` field in `defineConfig`.
80
+ 3. The Node default (all interfaces).
81
+
82
+ ### Secure bind for local/sensitive apps
83
+
84
+ If your app is **local and single-user** — a cockpit with a terminal, file access, real user data — it must listen on loopback only. An all-interfaces bind exposes that surface to the whole network without any error: the developer finds out by scanning, not by the app telling them.
85
+
86
+ ```bash
87
+ # Deploy do app local: bind em loopback, sempre
88
+ HOST=127.0.0.1 velojs start
89
+ ```
90
+
91
+ Because "set HOST" is easy to forget, sensitive apps should also **fail fast if the bind is wrong** — check the real address after the server starts, via `onServer`:
92
+
93
+ ```typescript
94
+ // app/server.tsx
95
+ import { onServer } from "@mauroandre/velojs/server";
96
+
97
+ onServer((server) => {
98
+ const addr = server.address();
99
+ const loopback = ["127.0.0.1", "::1", "::ffff:127.0.0.1"];
100
+ if (!addr || typeof addr !== "object" || !loopback.includes(addr.address)) {
101
+ console.error(
102
+ `[${process.env.APP_NAME ?? "app"}][CRIT] ` +
103
+ `server bound on ${addr && typeof addr === "object" ? addr.address : "?"} — outside loopback. ` +
104
+ `This app runs commands on this machine: it may only listen on 127.0.0.1/::1. Aborting.`
105
+ );
106
+ process.exit(1);
107
+ }
108
+ });
109
+ ```
110
+
111
+ This pattern caught a real exposure in production: the server had bound to `::` and the guard aborted instead of serving. When deploying the same app to a VPS later, the bind changes **consciously** to `HOST=0.0.0.0` — together with authentication and its own security spec, not by accident.
112
+
74
113
  ## Static assets on CDN
75
114
 
76
115
  If you want to serve static assets (JS, CSS, images) from a CDN or S3 bucket instead of the Node.js server, set the `STATIC_BASE_URL` environment variable:
package/dist/config.d.ts CHANGED
@@ -25,6 +25,12 @@ export interface VeloConfig {
25
25
  * @default 3000
26
26
  */
27
27
  port?: number;
28
+ /**
29
+ * Interface de bind do servidor de produção. A env `HOST` tem precedência.
30
+ * Default do Node: todas as interfaces (o que Docker/cloud esperam).
31
+ * Apps locais/sensíveis devem declarar "127.0.0.1".
32
+ */
33
+ hostname?: string;
28
34
  /**
29
35
  * Padrões adicionais de URL que o dev server deve delegar ao Vite em vez
30
36
  * de interceptar como página (ex.: artefatos de geradores build-time como
package/dist/server.d.ts CHANGED
@@ -7,6 +7,12 @@ export declare function onServer(fn: ServerCallback): void;
7
7
  export interface StartServerOptions {
8
8
  routes: AppRoutes;
9
9
  port?: number;
10
+ /**
11
+ * Hostname/interface to bind. Precedence: HOST env > this option > Node
12
+ * default (all interfaces — the ecosystem norm for containers/proxies).
13
+ * Local/sensitive apps should bind "127.0.0.1".
14
+ */
15
+ hostname?: string;
10
16
  }
11
17
  export declare function addRoutes(fn: (app: Hono) => void | Promise<void>): void;
12
18
  /**
package/dist/server.js CHANGED
@@ -1,94 +1,94 @@
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";
1
+ import { jsx as v } from "preact/jsx-runtime";
2
+ import { Hono as R } from "hono";
3
+ import { logger as T } from "hono/logger";
4
+ import { trimTrailingSlash as E } from "hono/trailing-slash";
5
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
- import { getAppContext as w } from "./app-context.js";
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();
6
+ import { Router as $ } from "wouter-preact";
7
+ import { AsyncLocalStorage as k } from "node:async_hooks";
8
+ import { getAppContext as _ } from "./app-context.js";
9
+ import { flushPendingStreamRoutes as A, registerStreamHandler as D } from "./events.js";
10
+ import { registerSocketRoutes as O, injectWebSocketServer as S } from "./sockets.js";
11
+ const P = new k();
12
12
  globalThis.__veloServerData = P;
13
- let v = null;
13
+ let g = null;
14
14
  function Z(e) {
15
- if (v) {
16
- e(v);
15
+ if (g) {
16
+ e(g);
17
17
  return;
18
18
  }
19
- w().serverCallbacks.push(e);
19
+ _().serverCallbacks.push(e);
20
20
  }
21
21
  function b(e) {
22
- v = e;
23
- const t = w();
22
+ g = e;
23
+ const t = _();
24
24
  for (const s of t.serverCallbacks) s(e);
25
25
  t.serverCallbacks.length = 0;
26
26
  }
27
27
  function ee(e) {
28
- w().pendingRoutes.push(e);
28
+ _().pendingRoutes.push(e);
29
29
  }
30
- const N = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029"), O = (e, t, s, r) => {
31
- if (r && r !== 200 && e.status(r), e.req.query("_data") === "1") {
32
- const c = globalThis.__veloBuildHash || void 0, i = s ? { ...s, __buildHash: c } : { __buildHash: c };
33
- return e.json(i);
30
+ const I = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029"), N = (e, t, s, a) => {
31
+ if (a && a !== 200 && e.status(a), e.req.query("_data") === "1") {
32
+ const c = globalThis.__veloBuildHash || void 0, r = s ? { ...s, __buildHash: c } : { __buildHash: c };
33
+ return e.json(r);
34
34
  }
35
35
  const o = e.req.path, n = P.run(
36
36
  s ?? {},
37
- () => C(/* @__PURE__ */ _(k, { ssrPath: o, children: t }))
37
+ () => C(/* @__PURE__ */ v($, { ssrPath: o, children: t }))
38
38
  );
39
39
  if (e.header("Cache-Control", "no-cache"), !s)
40
40
  return e.html(n);
41
- const a = `<script>window.__PAGE_DATA__=${N(s)}<\/script>`;
42
- return e.html(n.replace("</head>", () => `${a}</head>`));
43
- }, G = async (e, t) => {
44
- const s = t.req.param(), r = t.req.query(), o = { params: s, query: r, c: t }, n = await Promise.all(
45
- e.map(async (i) => {
46
- if (!i.loader) return null;
47
- const l = await i.loader(o), d = i.metadata?.moduleId;
48
- return d ? { moduleId: d, loaderData: l } : null;
41
+ const i = `<script>window.__PAGE_DATA__=${I(s)}<\/script>`;
42
+ return e.html(n.replace("</head>", () => `${i}</head>`));
43
+ }, H = async (e, t) => {
44
+ const s = t.req.param(), a = t.req.query(), o = { params: s, query: a, c: t }, n = await Promise.all(
45
+ e.map(async (r) => {
46
+ if (!r.loader) return null;
47
+ const f = await r.loader(o), l = r.metadata?.moduleId;
48
+ return l ? { moduleId: l, loaderData: f } : null;
49
49
  })
50
50
  );
51
- let a;
52
- for (const i of n)
53
- if (i && i.loaderData instanceof Response) {
54
- a = i.loaderData;
51
+ let i;
52
+ for (const r of n)
53
+ if (r && r.loaderData instanceof Response) {
54
+ i = r.loaderData;
55
55
  break;
56
56
  }
57
57
  const c = {
58
58
  __params: s,
59
- __query: r,
59
+ __query: a,
60
60
  __pathname: t.req.path
61
61
  };
62
- for (const i of n)
63
- i && !(i.loaderData instanceof Response) && (c[i.moduleId] = i.loaderData);
62
+ for (const r of n)
63
+ r && !(r.loaderData instanceof Response) && (c[r.moduleId] = r.loaderData);
64
64
  return {
65
- components: e.map((i) => i.Component),
65
+ components: e.map((r) => r.Component),
66
66
  data: c,
67
- shortCircuit: a
67
+ shortCircuit: i
68
68
  };
69
- }, H = (e) => {
69
+ }, G = (e) => {
70
70
  if (e.length === 0) return null;
71
71
  const t = e.filter(Boolean);
72
72
  if (t.length === 0) return null;
73
73
  if (t.length === 1) {
74
74
  const o = t[0];
75
- return /* @__PURE__ */ _(o, {});
75
+ return /* @__PURE__ */ v(o, {});
76
76
  }
77
77
  const s = t[t.length - 1];
78
- return t.slice(0, -1).reduceRight((o, n) => /* @__PURE__ */ _(n, { children: o }), /* @__PURE__ */ _(s, {}));
79
- }, y = (e, t, s = [], r = []) => {
78
+ return t.slice(0, -1).reduceRight((o, n) => /* @__PURE__ */ v(n, { children: o }), /* @__PURE__ */ v(s, {}));
79
+ }, y = (e, t, s = [], a = []) => {
80
80
  for (const o of t) {
81
81
  if (o.handler && !o.module) {
82
82
  o.children && y(
83
83
  e,
84
84
  o.children,
85
85
  s,
86
- [...r, ...o.middlewares || []]
86
+ [...a, ...o.middlewares || []]
87
87
  );
88
88
  continue;
89
89
  }
90
- const n = o.module ? [...s, o.module] : s, a = [
91
- ...r,
90
+ const n = o.module ? [...s, o.module] : s, i = [
91
+ ...a,
92
92
  ...o.middlewares || []
93
93
  ];
94
94
  if (o.children)
@@ -96,104 +96,104 @@ const N = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
96
96
  e,
97
97
  o.children,
98
98
  n,
99
- a
99
+ i
100
100
  );
101
101
  else if (o.module) {
102
- const c = o.path === "*", i = o.statusCode ?? (c ? 404 : void 0), l = o.module.metadata?.fullPath;
103
- if (!l && !c) {
102
+ const c = o.path === "*", r = o.statusCode ?? (c ? 404 : void 0), f = o.module.metadata?.fullPath;
103
+ if (!f && !c) {
104
104
  console.warn(
105
105
  `Module ${o.module.metadata?.moduleId} has no fullPath`
106
106
  );
107
107
  continue;
108
108
  }
109
- const d = async (h) => {
110
- const { components: u, data: m, shortCircuit: f } = await G(n, h);
111
- if (f) {
112
- const g = f.headers.get("Location");
113
- return h.req.query("_data") === "1" && g && f.status >= 300 && f.status < 400 ? h.json({ __redirect: g }) : f;
109
+ const l = async (d) => {
110
+ const { components: u, data: h, shortCircuit: m } = await H(n, d);
111
+ if (m) {
112
+ const w = m.headers.get("Location");
113
+ return d.req.query("_data") === "1" && w && m.status >= 300 && m.status < 400 ? d.json({ __redirect: w }) : m;
114
114
  }
115
- const p = H(u);
116
- return O(h, p, m, i);
115
+ const p = G(u);
116
+ return N(d, p, h, r);
117
117
  };
118
- c ? e.notFound(d) : a.length > 0 ? e.on(["GET"], [l], ...a, d) : e.on(["GET"], [l], d);
118
+ c ? e.notFound(l) : i.length > 0 ? e.on(["GET"], [f], ...i, l) : e.on(["GET"], [f], l);
119
119
  } else
120
120
  continue;
121
121
  }
122
122
  }, q = (e, t, s = []) => {
123
- for (const r of t) {
124
- const o = r.module?.metadata?.moduleId, n = [
123
+ for (const a of t) {
124
+ const o = a.module?.metadata?.moduleId, n = [
125
125
  ...s,
126
- ...r.middlewares || []
126
+ ...a.middlewares || []
127
127
  ];
128
- if (r.module && o) {
129
- const a = Object.keys(r.module).filter(
128
+ if (a.module && o) {
129
+ const i = Object.keys(a.module).filter(
130
130
  (c) => c.startsWith("action_")
131
131
  );
132
- for (const c of a) {
133
- const i = c.replace("action_", ""), l = r.module[c];
134
- if (typeof l == "function") {
135
- const d = `/_action/${o}/${i}`, h = async (u) => {
136
- let m = {};
132
+ for (const c of i) {
133
+ const r = c.replace("action_", ""), f = a.module[c];
134
+ if (typeof f == "function") {
135
+ const l = `/_action/${o}/${r}`, d = async (u) => {
136
+ let h = {};
137
137
  try {
138
- m = await u.req.json();
138
+ h = await u.req.json();
139
139
  } catch {
140
140
  }
141
- const f = {
142
- body: m,
141
+ const m = {
142
+ body: h,
143
143
  params: u.req.param(),
144
144
  query: u.req.query(),
145
145
  c: u
146
146
  };
147
147
  try {
148
- const p = await l(f);
148
+ const p = await f(m);
149
149
  return u.json(p ?? { ok: !0 });
150
150
  } catch (p) {
151
- const g = p instanceof Error ? p.message : "Action failed";
152
- return u.json({ error: g }, 500);
151
+ const w = p instanceof Error ? p.message : "Action failed";
152
+ return u.json({ error: w }, 500);
153
153
  }
154
154
  };
155
155
  n.length > 0 ? e.on(
156
156
  ["POST"],
157
- [d],
157
+ [l],
158
158
  ...n,
159
- h
160
- ) : e.on(["POST"], [d], h);
159
+ d
160
+ ) : e.on(["POST"], [l], d);
161
161
  }
162
162
  }
163
163
  }
164
- r.children && q(e, r.children, n);
164
+ a.children && q(e, a.children, n);
165
165
  }
166
166
  }, x = async (e, t, s = []) => {
167
- const r = (o, n) => {
168
- for (const a of o) {
169
- const c = a.module?.metadata?.moduleId, i = [
167
+ const a = (o, n) => {
168
+ for (const i of o) {
169
+ const c = i.module?.metadata?.moduleId, r = [
170
170
  ...n,
171
- ...a.middlewares || []
171
+ ...i.middlewares || []
172
172
  ];
173
- if (a.module && c) {
174
- const l = Object.keys(a.module).filter(
175
- (d) => d.startsWith("stream_")
173
+ if (i.module && c) {
174
+ const f = Object.keys(i.module).filter(
175
+ (l) => l.startsWith("stream_")
176
176
  );
177
- for (const d of l) {
178
- const h = d.replace("stream_", ""), u = a.module[d];
177
+ for (const l of f) {
178
+ const d = l.replace("stream_", ""), u = i.module[l];
179
179
  if (u?.__isVeloEventStream) {
180
- const m = `/_event/${c}/${h}`;
181
- u.__path = m, $(
180
+ const h = `/_event/${c}/${d}`;
181
+ u.__path = h, D(
182
182
  e,
183
- m,
183
+ h,
184
184
  u,
185
- i
185
+ r
186
186
  );
187
187
  }
188
188
  }
189
189
  }
190
- a.children && r(a.children, i);
190
+ i.children && a(i.children, r);
191
191
  }
192
192
  };
193
- r(t, s);
193
+ a(t, s);
194
194
  }, V = (e, t) => t ? t.startsWith("/") ? e + t : e ? e + "/" + t : "/" + t : e || "", W = (e) => {
195
- const t = /* @__PURE__ */ new Set(), s = (r) => {
196
- for (const o of r) {
195
+ const t = /* @__PURE__ */ new Set(), s = (a) => {
196
+ for (const o of a) {
197
197
  if (o.module && !o.children) {
198
198
  const n = o.module.metadata?.fullPath;
199
199
  n && t.add(n);
@@ -202,68 +202,77 @@ const N = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
202
202
  }
203
203
  };
204
204
  return s(e), t;
205
- }, R = (e, t, s, r = "", o = []) => {
205
+ }, j = (e, t, s, a = "", o = []) => {
206
206
  for (const n of t) {
207
- const a = V(r, n.path), c = [
207
+ const i = V(a, n.path), c = [
208
208
  ...o,
209
209
  ...n.middlewares || []
210
- ], i = !!n.handler, l = !!n.method;
211
- if (i && !l ? console.warn(
212
- `[velojs] invalid route at "${a || "/"}" — "handler" set without "method"; endpoint skipped`
213
- ) : l && !i ? console.warn(
214
- `[velojs] invalid route at "${a || "/"}" — "method" set without "handler"; endpoint skipped`
215
- ) : i && n.module ? console.warn(
216
- `[velojs] ambiguous route at "${a || "/"}" — both "module" and "handler" set; endpoint ignored, page kept`
217
- ) : i && n.isRoot && console.warn(
218
- `[velojs] "isRoot" has no effect on endpoint at "${a || "/"}"; ignored`
219
- ), i && l && !n.module) {
220
- const h = n.method;
221
- h === "GET" && s.has(a) && console.warn(
222
- `[velojs] path "${a}" has both a page GET and an endpoint GET; the page wins and the endpoint is unreachable. Consider renaming one.`
210
+ ], r = !!n.handler, f = !!n.method;
211
+ if (r && !f ? console.warn(
212
+ `[velojs] invalid route at "${i || "/"}" — "handler" set without "method"; endpoint skipped`
213
+ ) : f && !r ? console.warn(
214
+ `[velojs] invalid route at "${i || "/"}" — "method" set without "handler"; endpoint skipped`
215
+ ) : r && n.module ? console.warn(
216
+ `[velojs] ambiguous route at "${i || "/"}" — both "module" and "handler" set; endpoint ignored, page kept`
217
+ ) : r && n.isRoot && console.warn(
218
+ `[velojs] "isRoot" has no effect on endpoint at "${i || "/"}"; ignored`
219
+ ), r && f && !n.module) {
220
+ const d = n.method;
221
+ d === "GET" && s.has(i) && console.warn(
222
+ `[velojs] path "${i}" has both a page GET and an endpoint GET; the page wins and the endpoint is unreachable. Consider renaming one.`
223
223
  );
224
- const u = n.handler, m = async (f) => await u({
225
- c: f,
226
- params: f.req.param(),
227
- query: f.req.query()
224
+ const u = n.handler, h = async (m) => await u({
225
+ c: m,
226
+ params: m.req.param(),
227
+ query: m.req.query()
228
228
  });
229
- c.length > 0 ? e.on([h], [a], ...c, m) : e.on([h], [a], m);
229
+ c.length > 0 ? e.on([d], [i], ...c, h) : e.on([d], [i], h);
230
230
  }
231
- n.children && R(
231
+ n.children && j(
232
232
  e,
233
233
  n.children,
234
234
  s,
235
- a,
235
+ i,
236
236
  c
237
237
  );
238
238
  }
239
239
  }, K = async (e) => {
240
- const t = new j();
241
- t.use(T()), process.env.NODE_ENV !== "production" && t.use("*", E());
242
- const r = w().pendingRoutes.splice(0);
243
- for (const n of r)
240
+ const t = new R();
241
+ t.use(E()), process.env.NODE_ENV !== "production" && t.use("*", T());
242
+ const a = _().pendingRoutes.splice(0);
243
+ for (const n of a)
244
244
  await n(t);
245
245
  y(t, e), q(t, e), await x(t, e);
246
246
  const o = W(e);
247
- if (R(t, e, o), await I(t, e), D(t), process.env.NODE_ENV !== "production" && !v) {
247
+ if (j(t, e, o), await O(t, e), A(t), process.env.NODE_ENV !== "production" && !g) {
248
248
  const n = globalThis.__veloDevServer;
249
249
  n && (b(n), await S(t, n));
250
250
  }
251
251
  return t;
252
252
  }, te = async (e) => {
253
- const { routes: t } = e, s = Number(process.env.PORT) || e.port || 3e3, r = await K(t);
253
+ const { routes: t } = e, s = Number(process.env.PORT) || e.port || 3e3, a = process.env.HOST || e.hostname || void 0, o = await K(t);
254
254
  if (process.env.NODE_ENV === "production" && !process.env.VELO_STATIC) {
255
- 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");
256
- (process.env.STATIC_BASE_URL || "").startsWith("http") || r.use("/*", n({ root: c })), console.log(`Server running on http://localhost:${s}`);
257
- const l = o({ fetch: r.fetch, port: s });
258
- await S(r, l), b(l);
255
+ const { serve: n } = await import("@hono/node-server"), { serveStatic: i } = await import("@hono/node-server/serve-static"), { join: c } = await import("node:path"), r = c(process.cwd(), "dist/client");
256
+ (process.env.STATIC_BASE_URL || "").startsWith("http") || o.use("/*", i({ root: r }));
257
+ const l = n({ fetch: o.fetch, port: s, ...a ? { hostname: a } : {} });
258
+ l.listening || await new Promise((u) => l.once("listening", u));
259
+ const d = l.address();
260
+ if (d && typeof d == "object") {
261
+ const h = d.address === "::" || d.address === "0.0.0.0" ? "0.0.0.0 (all interfaces)" : d.address;
262
+ console.log(`Server running on ${h}:${d.port}`);
263
+ } else
264
+ console.log(`Server running on port ${s}`);
265
+ await S(o, l), b(l), l.once("close", () => {
266
+ g === l && (g = null);
267
+ });
259
268
  }
260
- return r;
269
+ return o;
261
270
  };
262
271
  export {
263
272
  ee as addRoutes,
264
273
  K as createApp,
265
274
  K as default,
266
- N as jsonForScript,
275
+ I as jsonForScript,
267
276
  Z as onServer,
268
277
  P as serverDataStorage,
269
278
  te as startServer
package/dist/vite.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import d from "node:path";
2
2
  import g from "node:fs";
3
3
  import R from "@preact/preset-vite";
4
- import $, { defaultOptions as U } from "@hono/vite-dev-server";
5
- import { parse as h } from "@babel/parser";
4
+ import $, { defaultOptions as J } from "@hono/vite-dev-server";
5
+ import { parse as _ } from "@babel/parser";
6
6
  import j from "@babel/traverse";
7
7
  import L from "@babel/generator";
8
8
  import * as e from "@babel/types";
9
- import { buildGraph as W } from "./graph.js";
10
- const m = typeof j == "function" ? j : j.default, v = typeof L == "function" ? L : L.default;
11
- function J(u, o, n, i) {
12
- const l = h(u, {
9
+ import { buildGraph as U } from "./graph.js";
10
+ const m = typeof j == "function" ? j : j.default, h = typeof L == "function" ? L : L.default;
11
+ function W(u, o, n, i) {
12
+ const l = _(u, {
13
13
  sourceType: "module",
14
14
  plugins: ["typescript", "jsx"]
15
15
  });
@@ -22,7 +22,7 @@ function J(u, o, n, i) {
22
22
  const r = c.declarations[0];
23
23
  if (r && e.isIdentifier(r.id, { name: "metadata" }) && e.isObjectExpression(r.init)) {
24
24
  t = !0;
25
- const f = r.init.properties.filter((_) => e.isObjectProperty(_) && e.isIdentifier(_.key) ? _.key.name !== "moduleId" && _.key.name !== "fullPath" && _.key.name !== "path" : !0), y = [
25
+ const f = r.init.properties.filter((v) => e.isObjectProperty(v) && e.isIdentifier(v.key) ? v.key.name !== "moduleId" && v.key.name !== "fullPath" && v.key.name !== "path" : !0), y = [
26
26
  e.objectProperty(
27
27
  e.identifier("moduleId"),
28
28
  e.stringLiteral(o)
@@ -70,10 +70,10 @@ function J(u, o, n, i) {
70
70
  );
71
71
  l.program.body.unshift(c);
72
72
  }
73
- return v(l, { retainLines: !0 }).code;
73
+ return h(l, { retainLines: !0 }).code;
74
74
  }
75
- function B(u, o) {
76
- const n = h(u, {
75
+ function M(u, o) {
76
+ const n = _(u, {
77
77
  sourceType: "module",
78
78
  plugins: ["typescript", "jsx"]
79
79
  });
@@ -84,10 +84,10 @@ function B(u, o) {
84
84
  const c = l.node.arguments, r = e.stringLiteral(o), p = c[0];
85
85
  e.isStringLiteral(p) && p.value.includes("/") || (l.node.arguments = [r, ...c]);
86
86
  }
87
- }), v(n, { retainLines: !0 }).code;
87
+ }), h(n, { retainLines: !0 }).code;
88
88
  }
89
- function M(u, o) {
90
- const n = h(u, {
89
+ function B(u, o) {
90
+ const n = _(u, {
91
91
  sourceType: "module",
92
92
  plugins: ["typescript", "jsx"]
93
93
  });
@@ -104,7 +104,7 @@ function M(u, o) {
104
104
  const p = r.params, f = H(o, c, p);
105
105
  r.body = e.blockStatement([e.returnStatement(f)]), G(r, p);
106
106
  }
107
- }), v(n, { retainLines: !0 }).code;
107
+ }), h(n, { retainLines: !0 }).code;
108
108
  }
109
109
  function H(u, o, n) {
110
110
  const i = `/_action/${u}/${o}`;
@@ -203,7 +203,7 @@ function G(u, o) {
203
203
  }
204
204
  }
205
205
  function z(u, o) {
206
- const n = h(u, {
206
+ const n = _(u, {
207
207
  sourceType: "module",
208
208
  plugins: ["typescript", "jsx"]
209
209
  });
@@ -227,10 +227,10 @@ function z(u, o) {
227
227
  )
228
228
  ]), a.id.typeAnnotation = null;
229
229
  }
230
- }), v(n, { retainLines: !0 }).code;
230
+ }), h(n, { retainLines: !0 }).code;
231
231
  }
232
232
  function Y(u, o) {
233
- const n = h(u, {
233
+ const n = _(u, {
234
234
  sourceType: "module",
235
235
  plugins: ["typescript", "jsx"]
236
236
  });
@@ -254,10 +254,10 @@ function Y(u, o) {
254
254
  )
255
255
  ]), a.id.typeAnnotation = null;
256
256
  }
257
- }), v(n, { retainLines: !0 }).code;
257
+ }), h(n, { retainLines: !0 }).code;
258
258
  }
259
259
  function X(u) {
260
- const o = h(u, {
260
+ const o = _(u, {
261
261
  sourceType: "module",
262
262
  plugins: ["typescript", "jsx"]
263
263
  });
@@ -268,14 +268,14 @@ function X(u) {
268
268
  const t = l.declarations[0];
269
269
  !t || !e.isIdentifier(t.id) || t.id.name === "loader" && i.remove();
270
270
  }
271
- }), v(o, { retainLines: !0 }).code;
271
+ }), h(o, { retainLines: !0 }).code;
272
272
  }
273
273
  function q(u) {
274
- const o = h(u, {
274
+ const o = _(u, {
275
275
  sourceType: "module",
276
276
  plugins: ["typescript", "jsx"]
277
277
  }), n = /* @__PURE__ */ new Set();
278
- S(o.program, n);
278
+ x(o.program, n);
279
279
  let i = !1;
280
280
  return m(o, {
281
281
  ImportDeclaration(t) {
@@ -284,10 +284,10 @@ function q(u) {
284
284
  const s = a.filter((c) => n.has(c.local.name));
285
285
  s.length !== a.length && (i = !0, s.length === 0 ? t.remove() : t.node.specifiers = s);
286
286
  }
287
- }), i ? v(o, { retainLines: !0 }).code : u;
287
+ }), i ? h(o, { retainLines: !0 }).code : u;
288
288
  }
289
289
  function K(u) {
290
- const o = h(u, {
290
+ const o = _(u, {
291
291
  sourceType: "module",
292
292
  plugins: ["typescript", "jsx"]
293
293
  }), n = [];
@@ -298,9 +298,9 @@ function K(u) {
298
298
  }), n.length === 0) return u;
299
299
  const i = /* @__PURE__ */ new Set();
300
300
  for (const s of n)
301
- S(s, i);
301
+ x(s, i);
302
302
  const l = /* @__PURE__ */ new Set();
303
- S(o.program, l);
303
+ x(o.program, l);
304
304
  const t = /* @__PURE__ */ new Set();
305
305
  for (const s of i)
306
306
  l.has(s) || t.add(s);
@@ -309,9 +309,9 @@ function K(u) {
309
309
  const c = s.node.specifiers, r = c.filter((p) => !t.has(p.local.name));
310
310
  r.length === 0 ? s.remove() : r.length !== c.length && (s.node.specifiers = r);
311
311
  }
312
- }), v(o, { retainLines: !0 }).code;
312
+ }), h(o, { retainLines: !0 }).code;
313
313
  }
314
- function S(u, o) {
314
+ function x(u, o) {
315
315
  const n = (i) => {
316
316
  if (!(!i || typeof i != "object")) {
317
317
  if (Array.isArray(i)) {
@@ -354,7 +354,7 @@ function Z(u) {
354
354
  return null;
355
355
  }
356
356
  function ee(u) {
357
- const o = h(u, {
357
+ const o = _(u, {
358
358
  sourceType: "module",
359
359
  plugins: ["typescript", "jsx"]
360
360
  }), n = [], i = (c) => {
@@ -378,9 +378,9 @@ function ee(u) {
378
378
  }), n.length === 0) return u;
379
379
  const l = /* @__PURE__ */ new Set();
380
380
  for (const c of n)
381
- S(c, l);
381
+ x(c, l);
382
382
  const t = /* @__PURE__ */ new Set();
383
- S(o.program, t);
383
+ x(o.program, t);
384
384
  const a = /* @__PURE__ */ new Set();
385
385
  for (const c of l)
386
386
  t.has(c) || a.add(c);
@@ -389,10 +389,10 @@ function ee(u) {
389
389
  const r = c.node.specifiers, p = r.filter((f) => !a.has(f.local.name));
390
390
  p.length === 0 ? c.remove() : p.length !== r.length && (c.node.specifiers = p);
391
391
  }
392
- }), v(o, { retainLines: !0 }).code;
392
+ }), h(o, { retainLines: !0 }).code;
393
393
  }
394
394
  function A(u) {
395
- const o = h(u, {
395
+ const o = _(u, {
396
396
  sourceType: "module",
397
397
  plugins: ["typescript", "jsx"]
398
398
  }), n = /* @__PURE__ */ new Map();
@@ -408,7 +408,7 @@ function A(u) {
408
408
  ExportDefaultDeclaration(t) {
409
409
  const a = t.node.declaration;
410
410
  let s = null;
411
- e.isArrayExpression(a) ? s = a : (e.isTSSatisfiesExpression(a) || e.isTSAsExpression(a)) && e.isArrayExpression(a.expression) && (s = a.expression), s && D(s.elements, "", i);
411
+ e.isArrayExpression(a) ? s = a : (e.isTSSatisfiesExpression(a) || e.isTSAsExpression(a)) && e.isArrayExpression(a.expression) && (s = a.expression), s && C(s.elements, "", i);
412
412
  }
413
413
  });
414
414
  const l = /* @__PURE__ */ new Map();
@@ -421,7 +421,7 @@ function A(u) {
421
421
  }
422
422
  return l;
423
423
  }
424
- function D(u, o, n) {
424
+ function C(u, o, n) {
425
425
  for (const i of u) {
426
426
  if (!e.isObjectExpression(i)) continue;
427
427
  let l = "", t = o, a = null, s = null;
@@ -437,10 +437,10 @@ function D(u, o, n) {
437
437
  path: l
438
438
  });
439
439
  }
440
- s && D(s.elements, t, n);
440
+ s && C(s.elements, t, n);
441
441
  }
442
442
  }
443
- const E = "virtual:velo/server-entry", b = "virtual:velo/client-entry", P = "\0" + E, N = "\0" + b;
443
+ const E = "virtual:velo/server-entry", b = "virtual:velo/client-entry", N = "\0" + E, P = "\0" + b;
444
444
  function te(u, o) {
445
445
  let n = d.resolve(process.cwd(), o);
446
446
  const i = u.routesFile ?? "routes.tsx", l = /* @__PURE__ */ new Map();
@@ -470,11 +470,11 @@ function te(u, o) {
470
470
  }
471
471
  },
472
472
  resolveId(t) {
473
- return t === E || t.endsWith(E) ? P : t === b || t.endsWith(b) || t === "/__velo_client.js" ? N : null;
473
+ return t === E || t.endsWith(E) ? N : t === b || t.endsWith(b) || t === "/__velo_client.js" ? P : null;
474
474
  },
475
475
  load(t) {
476
476
  const a = u.routesFile ?? "routes.tsx", s = u.serverInit ?? "server.tsx", c = u.clientInit ?? "client.tsx", r = d.join(n, a).replace(/\.tsx?$/, ".js"), p = d.join(n, s).replace(/\.tsx?$/, ".js"), f = d.join(n, c).replace(/\.tsx?$/, ".js");
477
- return t === P ? `
477
+ return t === N ? `
478
478
  globalThis.__veloBuildHash = __VELO_BUILD_HASH__;
479
479
  globalThis.__veloClientJs = __VELO_CLIENT_JS__;
480
480
  globalThis.__veloClientCss = __VELO_CLIENT_CSS__;
@@ -483,8 +483,8 @@ import routes from "${r}";
483
483
  import { startServer } from "@mauroandre/velojs/server";
484
484
 
485
485
  export { routes };
486
- export default await startServer({ routes, port: __VELO_CONFIG_PORT__ });
487
- ` : t === N ? `
486
+ export default await startServer({ routes, port: __VELO_CONFIG_PORT__, hostname: __VELO_CONFIG_HOSTNAME__ });
487
+ ` : t === P ? `
488
488
  import "${f}";
489
489
  import routes from "${r}";
490
490
  import { startClient } from "@mauroandre/velojs/client";
@@ -498,18 +498,18 @@ startClient({ routes });
498
498
  let r = t, p = !1;
499
499
  const f = /middlewares:\s*\[/.test(t), y = /export\s+(const|function)\s+Component/.test(
500
500
  t
501
- ), _ = /export\s+(const|function)\s+loader/.test(t), C = /export\s+const\s+action_\w+/.test(t), I = /export\s+const\s+stream_\w+/.test(t), T = /export\s+const\s+socket_\w+/.test(t), w = /\bLoader\s*</.test(t) || /\bLoader\s*\(/.test(t), k = /\buseLoader\s*</.test(t) || /\buseLoader\s*\(/.test(t), F = /\bhandler\s*:/.test(t), V = d.join(n, i);
502
- if (!c && f && (r = K(r), p = !0), !c && F && a === V && (r = ee(r), p = !0), y || _ || C || I || T || w || k) {
503
- const x = d.relative(n, a).replace(/\.(tsx?|jsx?)$/, "").replace(/\\/g, "/"), O = l.get(x);
504
- r = J(r, x, O?.fullPath, O?.path), r = B(r, x), c || (r = M(
501
+ ), v = /export\s+(const|function)\s+loader/.test(t), D = /export\s+const\s+action_\w+/.test(t), I = /export\s+const\s+stream_\w+/.test(t), T = /export\s+const\s+socket_\w+/.test(t), w = /\bLoader\s*</.test(t) || /\bLoader\s*\(/.test(t), F = /\buseLoader\s*</.test(t) || /\buseLoader\s*\(/.test(t), k = /\bhandler\s*:/.test(t), V = d.join(n, i);
502
+ if (!c && f && (r = K(r), p = !0), !c && k && a === V && (r = ee(r), p = !0), y || v || D || I || T || w || F) {
503
+ const S = d.relative(n, a).replace(/\.(tsx?|jsx?)$/, "").replace(/\\/g, "/"), O = l.get(S);
504
+ r = W(r, S, O?.fullPath, O?.path), r = M(r, S), c || (r = B(
505
505
  r,
506
- x
506
+ S
507
507
  )), !c && I && (r = z(
508
508
  r,
509
- x
509
+ S
510
510
  )), !c && T && (r = Y(
511
511
  r,
512
- x
512
+ S
513
513
  )), c || (r = X(r)), c || (r = q(r)), p = !0;
514
514
  }
515
515
  return p ? {
@@ -541,7 +541,9 @@ function re(u) {
541
541
  __VELO_CLIENT_CSS__: JSON.stringify(c),
542
542
  // Baked into the server bundle as startServer's port fallback.
543
543
  // null when unset → startServer falls back to PORT env / 3000.
544
- __VELO_CONFIG_PORT__: JSON.stringify(u.port ?? null)
544
+ __VELO_CONFIG_PORT__: JSON.stringify(u.port ?? null),
545
+ // Same for the bind interface: null → HOST env / Node default.
546
+ __VELO_CONFIG_HOSTNAME__: JSON.stringify(u.hostname ?? null)
545
547
  },
546
548
  resolve: {
547
549
  alias: {
@@ -599,7 +601,7 @@ function ie(u, o) {
599
601
  if (!n) return;
600
602
  const s = d.resolve(n, o);
601
603
  if (!g.existsSync(s)) return;
602
- const c = W(s), r = d.join(n, ".velojs");
604
+ const c = U(s), r = d.join(n, ".velojs");
603
605
  g.mkdirSync(r, { recursive: !0 }), g.writeFileSync(
604
606
  d.join(r, "graph.json"),
605
607
  JSON.stringify(c)
@@ -624,7 +626,7 @@ function ie(u, o) {
624
626
  }
625
627
  function se(u) {
626
628
  return [
627
- ...U.exclude,
629
+ ...J.exclude,
628
630
  /.*\.mjs$/,
629
631
  ...u.devServerExclude ?? []
630
632
  ];
@@ -654,15 +656,15 @@ function oe() {
654
656
  }
655
657
  export {
656
658
  A as buildFullPathMap,
657
- D as collectFullPaths,
659
+ C as collectFullPaths,
658
660
  se as devServerExcludeFor,
659
- J as injectMetadata,
661
+ W as injectMetadata,
660
662
  q as pruneClientOnlyImports,
661
663
  ee as removeEndpointRoutes,
662
664
  X as removeLoaders,
663
665
  K as removeMiddlewares,
664
- M as transformActionsForClient,
665
- B as transformLoaderFunctions,
666
+ B as transformActionsForClient,
667
+ M as transformLoaderFunctions,
666
668
  Y as transformSocketsForClient,
667
669
  z as transformStreamsForClient,
668
670
  ye as veloPlugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mauroandre/velojs",
3
- "version": "0.0.50",
3
+ "version": "0.0.51",
4
4
  "type": "module",
5
5
  "description": "Fullstack web framework built on Hono + Preact with Vite-powered AST transforms",
6
6
  "keywords": [