@mauroandre/velojs 0.0.57 → 0.0.58

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
@@ -467,6 +467,7 @@ A page value that must **track server state over time** — a total another
467
467
  person's request changes, data a background scheduler mutates — declares the
468
468
  channels that keep it fresh. No extra component, no manual subscription: the
469
469
  module exports `channels` next to its `loader`.
470
+ The one-sentence model: the live loader keeps a page's state replica faithful to the server — the first payload arrives through the usual path (SSR, `__PAGE_DATA__`, the `?_data=1` refetch), and from then on every change is **addressed**, by the app's own rules, to the group of clients it concerns, **by duty or by interest**, each one receiving the state computed for its own scope.
470
471
 
471
472
  ```tsx
472
473
  // app/expenses/Expenses.tsx
@@ -768,6 +769,8 @@ partitions is internal information, and it never ships in a production build.
768
769
 
769
770
  ### The partition contract
770
771
 
772
+ **Addressed, not broadcast.** A partition is not a filter applied after a broadcast. The `emit` is addressed: the runtime resolves the partition key and writes only to the connections of that group — a client outside the group never hears about the change, not even a byte. Two reasons make a partition matter, and they compose: **by duty** (authorization — the data belongs to that team, that family, that project; others must not see it) and **by interest** (relevance — the tab watching project 9 has nothing to wake up for when project 7 changes). The same `scope` serves both; the app decides which, or both at once.
773
+
771
774
  On subscribe the `scope` receives `{ user, params }`. `user` is `c.get("user")`
772
775
  — the house key, the same one the stream/socket channel resolvers use (a
773
776
  middleware that materializes the principal elsewhere should set it in `"user"`
@@ -2025,7 +2028,7 @@ velojs build
2025
2028
 
2026
2029
  Asset filenames include content hashes for long-term browser caching. The server build reads the Vite manifest to inject the correct filenames into `<Scripts>`.
2027
2030
 
2028
- In production, `velojs start` sets `NODE_ENV=production` automatically and serves static files from `dist/client/`. HTML responses are served with `Cache-Control: no-cache` so browsers always fetch the latest HTML (which references the current hashed assets).
2031
+ In production, `velojs start` sets `NODE_ENV=production` automatically and serves static files from `dist/client/`. Assets carry content hashes and are **public by design**, so the server answers an existing file **before the app's route table** — a page route, an action endpoint or a route middleware (an auth guard redirecting to `/login`, for instance) never sees an asset path. Only the framework's own infra middlewares (trailing-slash normalization, the logger) run ahead of the asset lookup. Paths that are not files fall through to the app routes as usual (SSR pages, actions, streams, sockets, endpoints, the catch-all 404). HTML responses are served with `Cache-Control: no-cache` so browsers always fetch the latest HTML (which references the current hashed assets).
2029
2032
 
2030
2033
  ### Static assets on CDN
2031
2034
 
@@ -2035,7 +2038,7 @@ Set `STATIC_BASE_URL` to serve static assets from a CDN or S3 bucket:
2035
2038
  STATIC_BASE_URL=https://cdn.example.com/assets node dist/server.js
2036
2039
  ```
2037
2040
 
2038
- The `<Scripts />` component and CSS `url()` references will use this prefix automatically.
2041
+ The `<Scripts />` component and CSS `url()` references will use this prefix automatically. When `STATIC_BASE_URL` starts with `http`, the server mounts no local static at all — every path is an app path, and the assets' public-by-design semantics come from the bucket/CDN.
2039
2042
 
2040
2043
  ---
2041
2044
 
package/agent/AGENTS.md CHANGED
@@ -108,6 +108,8 @@ import { emit } from "@mauroandre/velojs/server";
108
108
  await emit("teamExpenses", { user: { teamId: 7 } });
109
109
  ```
110
110
 
111
+ An `emit` is addressed to the partition's group — clients outside the group never hear about it (not a broadcast the client filters); partitions exist by duty (authorization) or by interest (relevance).
112
+
111
113
  Or, when the producer already holds the new value, it pushes it as a typed slice:
112
114
 
113
115
  ```ts
@@ -5,7 +5,7 @@ description: "Keep a loader value faithful to server state in real time: declare
5
5
 
6
6
  # Live loader
7
7
 
8
- A `loader` fetches a page's data once per request and re-fetches it on SPA navigation. That is everything a page needs when its data changes because of the user themselves — or not at all. A **value that must track server state over time** (a team total another person's request changes, data a background scheduler mutates) needs the loader to stay faithful. That is the live loader: the same `loader`, the same `useLoader()` read, plus a sibling `channels` export.
8
+ A `loader` fetches a page's data once per request and re-fetches it on SPA navigation. That is everything a page needs when its data changes because of the user themselves — or not at all. A **value that must track server state over time** (a team total another person's request changes, data a background scheduler mutates) needs the loader to stay faithful. That is the live loader: the same `loader`, the same `useLoader()` read, plus a sibling `channels` export. The one-sentence model: the live loader keeps a page's state replica faithful to the server — the first payload arrives through the usual path (SSR, `__PAGE_DATA__`, the `?_data=1` refetch), and from then on every change is **addressed**, by the app's own rules, to the group of clients it concerns, **by duty or by interest**, each one receiving the state computed for its own scope.
9
9
 
10
10
  ## The three declarations
11
11
 
@@ -284,6 +284,8 @@ On a page with no `channels` the fields exist, the record is empty and the aggre
284
284
 
285
285
  ## The partition contract
286
286
 
287
+ **Addressed, not broadcast.** A partition is not a filter applied after a broadcast. The `emit` is addressed: the runtime resolves the partition key and writes only to the connections of that group — a client outside the group never hears about the change, not even a byte. Two reasons make a partition matter, and they compose: **by duty** (authorization — the data belongs to that team, that family, that project; others must not see it) and **by interest** (relevance — the tab watching project 9 has nothing to wake up for when project 7 changes). The same `scope` serves both; the app decides which, or both at once.
288
+
287
289
  On subscribe the `scope` receives `{ user, params }`. `user` is whatever a middleware materialized under the house key `"user"` — the same key the stream/socket channel resolvers use; a middleware that materializes the principal somewhere else should set it in `"user"` too:
288
290
 
289
291
  ```ts
@@ -25,6 +25,12 @@ npx velojs start
25
25
 
26
26
  This automatically sets `NODE_ENV=production` and starts the server. In production mode, VeloJS serves static files from `dist/client/` and handles SSR for all page routes.
27
27
 
28
+ ### Assets are served before the app routes
29
+
30
+ `dist/client` assets are **public by design**: their names carry content hashes and their URLs are fetched by the browser with no session and no route logic attached. The server answers an existing file from `dist/client` **before the app's route table** — so a page route, an action endpoint or a route middleware (an auth guard redirecting to `/login`, for instance) never sees an asset path. Only the framework's own infra middlewares (trailing-slash normalization and the logger) run ahead of the asset lookup.
31
+
32
+ Paths that are not files keep the normal flow: SSR pages, actions, streams, sockets, endpoints and the app's catch-all 404. A top-level dynamic route (`/:mes`) therefore means only app paths — `/client.<hash>.js` is served as a file, while `/2026-10` goes through the route's middlewares and loaders.
33
+
28
34
  ## Dockerfile
29
35
 
30
36
  Here's a production-ready Dockerfile with multi-stage build:
@@ -124,7 +130,7 @@ If you want to serve static assets (JS, CSS, images) from a CDN or S3 bucket ins
124
130
  STATIC_BASE_URL=https://cdn.example.com/assets npx velojs start
125
131
  ```
126
132
 
127
- The `<Scripts />` component and CSS `url()` references will automatically use this prefix. The server will skip serving static files when `STATIC_BASE_URL` points to an external URL.
133
+ The `<Scripts />` component and CSS `url()` references will automatically use this prefix. When `STATIC_BASE_URL` starts with `http`, the server mounts no local static at all: every path is an app path, and the public-by-design semantics come from the bucket/CDN.
128
134
 
129
135
  ## Included dependencies
130
136
 
package/dist/server.js CHANGED
@@ -1,38 +1,38 @@
1
1
  import { jsx as w } from "preact/jsx-runtime";
2
- import { Hono as C } from "hono";
3
- import { logger as E } from "hono/logger";
2
+ import { Hono as j } from "hono";
3
+ import { logger as q } from "hono/logger";
4
4
  import { trimTrailingSlash as T } from "hono/trailing-slash";
5
5
  import { render as A } from "preact-render-to-string";
6
6
  import { Router as $ } from "wouter-preact";
7
7
  import { AsyncLocalStorage as k } from "node:async_hooks";
8
8
  import { getAppContext as _ } from "./app-context.js";
9
- import { flushPendingStreamRoutes as D, registerStreamHandler as I } from "./events.js";
10
- import { registerSocketRoutes as N, injectWebSocketServer as S } from "./sockets.js";
11
- import { inspectChannels as O, registerChannelRoute as H } from "./channels.js";
12
- import { emit as le, registerChannels as de } from "./channels.js";
9
+ import { flushPendingStreamRoutes as D, registerStreamHandler as N } from "./events.js";
10
+ import { registerSocketRoutes as O, injectWebSocketServer as S } from "./sockets.js";
11
+ import { inspectChannels as I, registerChannelRoute as H } from "./channels.js";
12
+ import { emit as de, registerChannels as ue } from "./channels.js";
13
13
  const P = new k();
14
14
  globalThis.__veloServerData = P;
15
15
  let g = null;
16
- function re(e) {
16
+ function se(e) {
17
17
  if (g) {
18
18
  e(g);
19
19
  return;
20
20
  }
21
21
  _().serverCallbacks.push(e);
22
22
  }
23
- function b(e) {
23
+ function C(e) {
24
24
  g = e;
25
25
  const t = _();
26
26
  for (const a of t.serverCallbacks) a(e);
27
27
  t.serverCallbacks.length = 0;
28
28
  }
29
- function x(e) {
29
+ function V(e) {
30
30
  g === e && (g = null);
31
31
  }
32
- function se(e) {
32
+ function ae(e) {
33
33
  _().pendingRoutes.push(e);
34
34
  }
35
- const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029"), V = (e, t, a, r) => {
35
+ const x = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029"), G = (e, t, a, r) => {
36
36
  if (r && r !== 200 && e.status(r), e.req.query("_data") === "1") {
37
37
  const c = globalThis.__veloBuildHash || void 0, i = a ? { ...a, __buildHash: c } : { __buildHash: c };
38
38
  return e.json(i);
@@ -43,14 +43,14 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
43
43
  );
44
44
  if (e.header("Cache-Control", "no-cache"), !a)
45
45
  return e.html(n);
46
- const s = `<script>window.__PAGE_DATA__=${G(a)}<\/script>`;
46
+ const s = `<script>window.__PAGE_DATA__=${x(a)}<\/script>`;
47
47
  return e.html(n.replace("</head>", () => `${s}</head>`));
48
- }, M = async (e, t) => {
48
+ }, L = async (e, t) => {
49
49
  const a = t.req.param(), r = t.req.query(), o = { params: a, query: r, c: t }, n = await Promise.all(
50
50
  e.map(async (i) => {
51
51
  if (!i.loader) return null;
52
- const f = await i.loader(o), l = i.metadata?.moduleId;
53
- return l ? { moduleId: l, loaderData: f } : null;
52
+ const l = await i.loader(o), d = i.metadata?.moduleId;
53
+ return d ? { moduleId: d, loaderData: l } : null;
54
54
  })
55
55
  );
56
56
  let s;
@@ -71,7 +71,7 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
71
71
  data: c,
72
72
  shortCircuit: s
73
73
  };
74
- }, W = (e) => {
74
+ }, M = (e) => {
75
75
  if (e.length === 0) return null;
76
76
  const t = e.filter(Boolean);
77
77
  if (t.length === 0) return null;
@@ -104,27 +104,27 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
104
104
  s
105
105
  );
106
106
  else if (o.module) {
107
- const c = o.path === "*", i = o.statusCode ?? (c ? 404 : void 0), f = o.module.metadata?.fullPath;
108
- if (!f && !c) {
107
+ const c = o.path === "*", i = o.statusCode ?? (c ? 404 : void 0), l = o.module.metadata?.fullPath;
108
+ if (!l && !c) {
109
109
  console.warn(
110
110
  `Module ${o.module.metadata?.moduleId} has no fullPath`
111
111
  );
112
112
  continue;
113
113
  }
114
- const l = async (d) => {
115
- const { components: u, data: h, shortCircuit: m } = await M(n, d);
116
- if (m) {
117
- const v = m.headers.get("Location");
118
- return d.req.query("_data") === "1" && v && m.status >= 300 && m.status < 400 ? d.json({ __redirect: v }) : m;
114
+ const d = async (f) => {
115
+ const { components: u, data: m, shortCircuit: h } = await L(n, f);
116
+ if (h) {
117
+ const v = h.headers.get("Location");
118
+ return f.req.query("_data") === "1" && v && h.status >= 300 && h.status < 400 ? f.json({ __redirect: v }) : h;
119
119
  }
120
- const p = W(u);
121
- return V(d, p, h, i);
120
+ const p = M(u);
121
+ return G(f, p, m, i);
122
122
  };
123
- c ? e.notFound(l) : s.length > 0 ? e.on(["GET"], [f], ...s, l) : e.on(["GET"], [f], l);
123
+ c ? e.notFound(d) : s.length > 0 ? e.on(["GET"], [l], ...s, d) : e.on(["GET"], [l], d);
124
124
  } else
125
125
  continue;
126
126
  }
127
- }, R = (e, t, a = []) => {
127
+ }, E = (e, t, a = []) => {
128
128
  for (const r of t) {
129
129
  const o = r.module?.metadata?.moduleId, n = [
130
130
  ...a,
@@ -135,22 +135,22 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
135
135
  (c) => c.startsWith("action_")
136
136
  );
137
137
  for (const c of s) {
138
- const i = c.replace("action_", ""), f = r.module[c];
139
- if (typeof f == "function") {
140
- const l = `/_action/${o}/${i}`, d = async (u) => {
141
- let h = {};
138
+ const i = c.replace("action_", ""), l = r.module[c];
139
+ if (typeof l == "function") {
140
+ const d = `/_action/${o}/${i}`, f = async (u) => {
141
+ let m = {};
142
142
  try {
143
- h = await u.req.json();
143
+ m = await u.req.json();
144
144
  } catch {
145
145
  }
146
- const m = {
147
- body: h,
146
+ const h = {
147
+ body: m,
148
148
  params: u.req.param(),
149
149
  query: u.req.query(),
150
150
  c: u
151
151
  };
152
152
  try {
153
- const p = await f(m);
153
+ const p = await l(h);
154
154
  return u.json(p ?? { ok: !0 });
155
155
  } catch (p) {
156
156
  const v = p instanceof Error ? p.message : "Action failed";
@@ -159,16 +159,16 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
159
159
  };
160
160
  n.length > 0 ? e.on(
161
161
  ["POST"],
162
- [l],
162
+ [d],
163
163
  ...n,
164
- d
165
- ) : e.on(["POST"], [l], d);
164
+ f
165
+ ) : e.on(["POST"], [d], f);
166
166
  }
167
167
  }
168
168
  }
169
- r.children && R(e, r.children, n);
169
+ r.children && E(e, r.children, n);
170
170
  }
171
- }, K = async (e, t, a = []) => {
171
+ }, W = async (e, t, a = []) => {
172
172
  const r = (o, n) => {
173
173
  for (const s of o) {
174
174
  const c = s.module?.metadata?.moduleId, i = [
@@ -176,16 +176,16 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
176
176
  ...s.middlewares || []
177
177
  ];
178
178
  if (s.module && c) {
179
- const f = Object.keys(s.module).filter(
180
- (l) => l.startsWith("stream_")
179
+ const l = Object.keys(s.module).filter(
180
+ (d) => d.startsWith("stream_")
181
181
  );
182
- for (const l of f) {
183
- const d = l.replace("stream_", ""), u = s.module[l];
182
+ for (const d of l) {
183
+ const f = d.replace("stream_", ""), u = s.module[d];
184
184
  if (u?.__isVeloEventStream) {
185
- const h = `/_event/${c}/${d}`;
186
- u.__path = h, I(
185
+ const m = `/_event/${c}/${f}`;
186
+ u.__path = m, N(
187
187
  e,
188
- h,
188
+ m,
189
189
  u,
190
190
  i
191
191
  );
@@ -196,7 +196,7 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
196
196
  }
197
197
  };
198
198
  r(t, a);
199
- }, j = (e, t, a = []) => {
199
+ }, b = (e, t, a = []) => {
200
200
  for (const r of t) {
201
201
  const o = r.module?.metadata?.moduleId, n = [
202
202
  ...a,
@@ -215,9 +215,9 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
215
215
  n
216
216
  );
217
217
  }
218
- r.children && j(e, r.children, n);
218
+ r.children && b(e, r.children, n);
219
219
  }
220
- }, L = (e, t) => t ? t.startsWith("/") ? e + t : e ? e + "/" + t : "/" + t : e || "", B = (e) => {
220
+ }, K = (e, t) => t ? t.startsWith("/") ? e + t : e ? e + "/" + t : "/" + t : e || "", B = (e) => {
221
221
  const t = /* @__PURE__ */ new Set(), a = (r) => {
222
222
  for (const o of r) {
223
223
  if (o.module && !o.children) {
@@ -228,33 +228,33 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
228
228
  }
229
229
  };
230
230
  return a(e), t;
231
- }, q = (e, t, a, r = "", o = []) => {
231
+ }, R = (e, t, a, r = "", o = []) => {
232
232
  for (const n of t) {
233
- const s = L(r, n.path), c = [
233
+ const s = K(r, n.path), c = [
234
234
  ...o,
235
235
  ...n.middlewares || []
236
- ], i = !!n.handler, f = !!n.method;
237
- if (i && !f ? console.warn(
236
+ ], i = !!n.handler, l = !!n.method;
237
+ if (i && !l ? console.warn(
238
238
  `[velojs] invalid route at "${s || "/"}" — "handler" set without "method"; endpoint skipped`
239
- ) : f && !i ? console.warn(
239
+ ) : l && !i ? console.warn(
240
240
  `[velojs] invalid route at "${s || "/"}" — "method" set without "handler"; endpoint skipped`
241
241
  ) : i && n.module ? console.warn(
242
242
  `[velojs] ambiguous route at "${s || "/"}" — both "module" and "handler" set; endpoint ignored, page kept`
243
243
  ) : i && n.isRoot && console.warn(
244
244
  `[velojs] "isRoot" has no effect on endpoint at "${s || "/"}"; ignored`
245
- ), i && f && !n.module) {
246
- const d = n.method;
247
- d === "GET" && a.has(s) && console.warn(
245
+ ), i && l && !n.module) {
246
+ const f = n.method;
247
+ f === "GET" && a.has(s) && console.warn(
248
248
  `[velojs] path "${s}" has both a page GET and an endpoint GET; the page wins and the endpoint is unreachable. Consider renaming one.`
249
249
  );
250
- const u = n.handler, h = async (m) => await u({
251
- c: m,
252
- params: m.req.param(),
253
- query: m.req.query()
250
+ const u = n.handler, m = async (h) => await u({
251
+ c: h,
252
+ params: h.req.param(),
253
+ query: h.req.query()
254
254
  });
255
- c.length > 0 ? e.on([d], [s], ...c, h) : e.on([d], [s], h);
255
+ c.length > 0 ? e.on([f], [s], ...c, m) : e.on([f], [s], m);
256
256
  }
257
- n.children && q(
257
+ n.children && R(
258
258
  e,
259
259
  n.children,
260
260
  a,
@@ -263,48 +263,50 @@ const G = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u00
263
263
  );
264
264
  }
265
265
  }, F = async (e) => {
266
- const t = new C();
267
- t.use(T()), process.env.NODE_ENV !== "production" && t.use("*", E());
266
+ if (process.env.NODE_ENV !== "production" || process.env.VELO_STATIC || (process.env.STATIC_BASE_URL || "").startsWith("http")) return;
267
+ const { serveStatic: a } = await import("@hono/node-server/serve-static"), { join: r } = await import("node:path");
268
+ e.use("/*", a({ root: r(process.cwd(), "dist/client") }));
269
+ }, U = async (e) => {
270
+ const t = new j();
271
+ t.use(T()), process.env.NODE_ENV !== "production" && t.use("*", q()), await F(t);
268
272
  const r = _().pendingRoutes.splice(0);
269
273
  for (const n of r)
270
274
  await n(t);
271
- y(t, e), R(t, e), await K(t, e), j(t, e), process.env.NODE_ENV !== "production" && t.get("/_channel-inspect", (n) => n.json(O()));
275
+ y(t, e), E(t, e), await W(t, e), b(t, e), process.env.NODE_ENV !== "production" && t.get("/_channel-inspect", (n) => n.json(I()));
272
276
  const o = B(e);
273
- if (q(t, e, o), await N(t, e), D(t), process.env.NODE_ENV !== "production" && !g) {
277
+ if (R(t, e, o), await O(t, e), D(t), process.env.NODE_ENV !== "production" && !g) {
274
278
  const n = globalThis.__veloDevServer;
275
- n && (b(n), await S(t, n));
279
+ n && (C(n), await S(t, n));
276
280
  }
277
281
  return t;
278
- }, ae = async (e) => {
279
- const { routes: t } = e, a = Number(process.env.PORT) || e.port || 3e3, r = process.env.HOST || e.hostname || void 0, o = await F(t);
282
+ }, ie = async (e) => {
283
+ const { routes: t } = e, a = Number(process.env.PORT) || e.port || 3e3, r = process.env.HOST || e.hostname || void 0, o = await U(t);
280
284
  if (process.env.NODE_ENV === "production" && !process.env.VELO_STATIC) {
281
- const { serve: n } = await import("@hono/node-server"), { serveStatic: s } = await import("@hono/node-server/serve-static"), { join: c } = await import("node:path"), i = c(process.cwd(), "dist/client");
282
- (process.env.STATIC_BASE_URL || "").startsWith("http") || o.use("/*", s({ root: i }));
283
- const l = n({ fetch: o.fetch, port: a, ...r ? { hostname: r } : {} });
284
- l.listening || await new Promise((u) => l.once("listening", u));
285
- const d = l.address();
286
- if (d && typeof d == "object") {
287
- const h = d.address === "::" || d.address === "0.0.0.0" ? "0.0.0.0 (all interfaces)" : d.address;
288
- console.log(`Server running on ${h}:${d.port}`);
285
+ const { serve: n } = await import("@hono/node-server"), s = n({ fetch: o.fetch, port: a, ...r ? { hostname: r } : {} });
286
+ s.listening || await new Promise((i) => s.once("listening", i));
287
+ const c = s.address();
288
+ if (c && typeof c == "object") {
289
+ const l = c.address === "::" || c.address === "0.0.0.0" ? "0.0.0.0 (all interfaces)" : c.address;
290
+ console.log(`Server running on ${l}:${c.port}`);
289
291
  } else
290
292
  console.log(`Server running on port ${a}`);
291
- await S(o, l), b(l), l.once("close", () => {
292
- x(l);
293
+ await S(o, s), C(s), s.once("close", () => {
294
+ V(s);
293
295
  });
294
296
  }
295
297
  return o;
296
298
  };
297
299
  export {
298
- se as addRoutes,
299
- x as clearActiveServer,
300
- F as createApp,
301
- F as default,
302
- le as emit,
303
- b as flushServerCallbacks,
304
- O as inspectChannels,
305
- G as jsonForScript,
306
- re as onServer,
307
- de as registerChannels,
300
+ ae as addRoutes,
301
+ V as clearActiveServer,
302
+ U as createApp,
303
+ U as default,
304
+ de as emit,
305
+ C as flushServerCallbacks,
306
+ I as inspectChannels,
307
+ x as jsonForScript,
308
+ se as onServer,
309
+ ue as registerChannels,
308
310
  P as serverDataStorage,
309
- ae as startServer
311
+ ie as startServer
310
312
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mauroandre/velojs",
3
- "version": "0.0.57",
3
+ "version": "0.0.58",
4
4
  "type": "module",
5
5
  "description": "Fullstack web framework built on Hono + Preact with Vite-powered AST transforms",
6
6
  "keywords": [