hermium 0.3.2 → 0.3.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/bin/hermium.mjs CHANGED
@@ -208,8 +208,9 @@ function cmdStatus() {
208
208
  const { apiPid, webPid } = getPids()
209
209
  if (apiPid || webPid) {
210
210
  console.log(pc.green(` ✓ Hermium is running`))
211
- if (apiPid) console.log(` API : PID ${apiPid}, port ${getApiPort()}`)
212
- if (webPid) console.log(` Web : PID ${webPid}, port ${getWebPort()}`)
211
+ console.log(` URL : http://localhost:${getApiPort()}`)
212
+ if (apiPid) console.log(` API : PID ${apiPid}`)
213
+ if (webPid) console.log(` Web : PID ${webPid}`)
213
214
  console.log(` Logs : ${LOG_FILE.replace(homedir(), '~')}`)
214
215
  } else {
215
216
  console.log(pc.yellow(` ⊘ Hermium is not running`))
@@ -282,7 +283,6 @@ async function cmdStart() {
282
283
  const interval = 500
283
284
  let waited = 0
284
285
  const apiUrl = `http://127.0.0.1:${apiPort}`
285
- const webUrl = `http://127.0.0.1:${webPort}`
286
286
 
287
287
  function poll() {
288
288
  waited += interval
@@ -300,22 +300,20 @@ async function cmdStart() {
300
300
  setTimeout(poll, interval)
301
301
  } else {
302
302
  console.log(pc.green(` ✓ Hermium started`))
303
- console.log(` API : ${apiUrl}`)
304
- console.log(` Web : ${webUrl}`)
303
+ console.log(` URL : ${apiUrl}`)
305
304
  console.log(` Logs: ${LOG_FILE.replace(homedir(), '~')}`)
306
305
  checkLatestVersion()
307
306
  }
308
307
  } else {
309
308
  console.log(pc.green(` ✓ Hermium started`))
310
- console.log(` API : ${apiUrl}`)
311
- console.log(` Web : ${webUrl}`)
309
+ console.log(` URL : ${apiUrl}`)
312
310
  console.log(` Logs: ${LOG_FILE.replace(homedir(), '~')}`)
313
311
  checkLatestVersion()
314
- // Open browser
312
+ // Open browser to the unified URL (API serves web UI too)
315
313
  const openCmd =
316
- process.platform === 'win32' ? `start ${webUrl}` :
317
- process.platform === 'darwin' ? `open ${webUrl}` :
318
- `xdg-open ${webUrl}`
314
+ process.platform === 'win32' ? `start ${apiUrl}` :
315
+ process.platform === 'darwin' ? `open ${apiUrl}` :
316
+ `xdg-open ${apiUrl}`
319
317
  try { execSync(openCmd, { stdio: 'ignore' }) } catch {}
320
318
  }
321
319
  })
@@ -398,11 +398,128 @@ var H3Core = class {
398
398
  return routeMiddleware ? [...globalMiddleware, ...routeMiddleware] : globalMiddleware;
399
399
  }
400
400
  };
401
+ const PayloadMethods = /* @__PURE__ */ new Set([
402
+ "PATCH",
403
+ "POST",
404
+ "PUT",
405
+ "DELETE"
406
+ ]);
407
+ const ignoredHeaders = /* @__PURE__ */ new Set([
408
+ "transfer-encoding",
409
+ "connection",
410
+ "keep-alive",
411
+ "upgrade",
412
+ "expect",
413
+ "host",
414
+ "accept"
415
+ ]);
416
+ function rewriteCookieProperty(header, map, property) {
417
+ const _map = typeof map === "string" ? { "*": map } : map;
418
+ return header.replace(new RegExp(`(;\\s*${property}=)([^;]+)`, "gi"), (match, prefix, previousValue) => {
419
+ let newValue;
420
+ if (previousValue in _map) newValue = _map[previousValue];
421
+ else if ("*" in _map) newValue = _map["*"];
422
+ else return match;
423
+ return newValue ? prefix + newValue : "";
424
+ });
425
+ }
426
+ function mergeHeaders(defaults, ...inputs) {
427
+ const _inputs = inputs.filter(Boolean);
428
+ if (_inputs.length === 0) return defaults;
429
+ const merged = new Headers(defaults);
430
+ for (const input of _inputs) {
431
+ const entries = Array.isArray(input) ? input : typeof input.entries === "function" ? input.entries() : Object.entries(input);
432
+ for (const [key, value] of entries) if (value !== void 0) merged.set(key, value);
433
+ }
434
+ return merged;
435
+ }
436
+ async function proxyRequest(event, target, opts = {}) {
437
+ const requestBody = PayloadMethods.has(event.req.method) ? event.req.body : void 0;
438
+ const method = opts.fetchOptions?.method || event.req.method;
439
+ const fetchHeaders = mergeHeaders(getProxyRequestHeaders(event, {
440
+ host: target.startsWith("/"),
441
+ forwardHeaders: opts.forwardHeaders,
442
+ filterHeaders: opts.filterHeaders
443
+ }), opts.fetchOptions?.headers, opts.headers);
444
+ return proxy(event, target, {
445
+ ...opts,
446
+ fetchOptions: {
447
+ method,
448
+ body: requestBody,
449
+ duplex: requestBody ? "half" : void 0,
450
+ ...opts.fetchOptions,
451
+ headers: fetchHeaders
452
+ }
453
+ });
454
+ }
455
+ async function proxy(event, target, opts = {}) {
456
+ const fetchOptions = {
457
+ headers: opts.headers,
458
+ ...opts.fetchOptions
459
+ };
460
+ let response;
461
+ try {
462
+ response = target[0] === "/" ? await event.app.fetch(createSubRequest(event, target, fetchOptions)) : await fetch(target, fetchOptions);
463
+ } catch (error) {
464
+ throw new HTTPError({
465
+ status: 502,
466
+ cause: error
467
+ });
468
+ }
469
+ const headers = new Headers();
470
+ const cookies = [];
471
+ for (const [key, value] of response.headers.entries()) {
472
+ if (key === "content-encoding" || key === "content-length" || key === "transfer-encoding") continue;
473
+ if (key === "set-cookie") {
474
+ cookies.push(value);
475
+ continue;
476
+ }
477
+ headers.append(key, value);
478
+ }
479
+ if (cookies.length > 0) {
480
+ const _cookies = cookies.map((cookie) => {
481
+ if (opts.cookieDomainRewrite) cookie = rewriteCookieProperty(cookie, opts.cookieDomainRewrite, "domain");
482
+ if (opts.cookiePathRewrite) cookie = rewriteCookieProperty(cookie, opts.cookiePathRewrite, "path");
483
+ return cookie;
484
+ });
485
+ for (const cookie of _cookies) headers.append("set-cookie", cookie);
486
+ }
487
+ if (opts.onResponse) await opts.onResponse(event, response);
488
+ return new HTTPResponse(response.body, {
489
+ status: response.status,
490
+ statusText: response.statusText,
491
+ headers
492
+ });
493
+ }
494
+ function getProxyRequestHeaders(event, opts) {
495
+ const headers = new NullProtoObj();
496
+ for (const [name, value] of event.req.headers.entries()) {
497
+ if (opts?.filterHeaders?.includes(name)) continue;
498
+ if (opts?.forwardHeaders?.includes(name)) {
499
+ headers[name] = value;
500
+ continue;
501
+ }
502
+ if (!ignoredHeaders.has(name) || name === "host" && opts?.host) {
503
+ headers[name] = value;
504
+ continue;
505
+ }
506
+ }
507
+ return headers;
508
+ }
509
+ function createSubRequest(event, path, init) {
510
+ const url = new URL(path, event.url);
511
+ const req = new Request(url, init);
512
+ req.runtime = event.req.runtime;
513
+ req.waitUntil = event.req.waitUntil;
514
+ req.ip = event.req.ip;
515
+ return req;
516
+ }
401
517
  export {
402
518
  H3Core as H,
403
519
  HTTPError as a,
404
520
  defineLazyEventHandler as b,
405
521
  toRequest as c,
406
522
  defineHandler as d,
523
+ proxyRequest as p,
407
524
  toEventHandler as t
408
525
  };
@@ -1,4 +1,22 @@
1
+ const HASH_RE = /#/g;
2
+ const AMPERSAND_RE = /&/g;
3
+ const SLASH_RE = /\//g;
4
+ const EQUAL_RE = /=/g;
5
+ const PLUS_RE = /\+/g;
6
+ const ENC_CARET_RE = /%5e/gi;
7
+ const ENC_BACKTICK_RE = /%60/gi;
8
+ const ENC_PIPE_RE = /%7c/gi;
9
+ const ENC_SPACE_RE = /%20/gi;
1
10
  const ENC_SLASH_RE = /%2f/gi;
11
+ function encode(text) {
12
+ return encodeURI("" + text).replace(ENC_PIPE_RE, "|");
13
+ }
14
+ function encodeQueryValue(input) {
15
+ return encode(typeof input === "string" ? input : JSON.stringify(input)).replace(PLUS_RE, "%2B").replace(ENC_SPACE_RE, "+").replace(HASH_RE, "%23").replace(AMPERSAND_RE, "%26").replace(ENC_BACKTICK_RE, "`").replace(ENC_CARET_RE, "^").replace(SLASH_RE, "%2F");
16
+ }
17
+ function encodeQueryKey(text) {
18
+ return encodeQueryValue(text).replace(EQUAL_RE, "%3D");
19
+ }
2
20
  function decode(text = "") {
3
21
  try {
4
22
  return decodeURIComponent("" + text);
@@ -9,7 +27,67 @@ function decode(text = "") {
9
27
  function decodePath(text) {
10
28
  return decode(text.replace(ENC_SLASH_RE, "%252F"));
11
29
  }
30
+ function decodeQueryKey(text) {
31
+ return decode(text.replace(PLUS_RE, " "));
32
+ }
33
+ function decodeQueryValue(text) {
34
+ return decode(text.replace(PLUS_RE, " "));
35
+ }
36
+ function parseQuery(parametersString = "") {
37
+ const object = /* @__PURE__ */ Object.create(null);
38
+ if (parametersString[0] === "?") {
39
+ parametersString = parametersString.slice(1);
40
+ }
41
+ for (const parameter of parametersString.split("&")) {
42
+ const s = parameter.match(/([^=]+)=?(.*)/) || [];
43
+ if (s.length < 2) {
44
+ continue;
45
+ }
46
+ const key = decodeQueryKey(s[1]);
47
+ if (key === "__proto__" || key === "constructor") {
48
+ continue;
49
+ }
50
+ const value = decodeQueryValue(s[2] || "");
51
+ if (object[key] === void 0) {
52
+ object[key] = value;
53
+ } else if (Array.isArray(object[key])) {
54
+ object[key].push(value);
55
+ } else {
56
+ object[key] = [object[key], value];
57
+ }
58
+ }
59
+ return object;
60
+ }
61
+ function encodeQueryItem(key, value) {
62
+ if (typeof value === "number" || typeof value === "boolean") {
63
+ value = String(value);
64
+ }
65
+ if (!value) {
66
+ return encodeQueryKey(key);
67
+ }
68
+ if (Array.isArray(value)) {
69
+ return value.map(
70
+ (_value) => `${encodeQueryKey(key)}=${encodeQueryValue(_value)}`
71
+ ).join("&");
72
+ }
73
+ return `${encodeQueryKey(key)}=${encodeQueryValue(value)}`;
74
+ }
75
+ function stringifyQuery(query) {
76
+ return Object.keys(query).filter((k) => query[k] !== void 0).map((k) => encodeQueryItem(k, query[k])).filter(Boolean).join("&");
77
+ }
78
+ const PROTOCOL_STRICT_REGEX = /^[\s\w\0+.-]{2,}:([/\\]{1,2})/;
79
+ const PROTOCOL_REGEX = /^[\s\w\0+.-]{2,}:([/\\]{2})?/;
80
+ const PROTOCOL_RELATIVE_REGEX = /^([/\\]\s*){2,}[^/\\]/;
12
81
  const JOIN_LEADING_SLASH_RE = /^\.?\//;
82
+ function hasProtocol(inputString, opts = {}) {
83
+ if (typeof opts === "boolean") {
84
+ opts = { acceptRelative: opts };
85
+ }
86
+ if (opts.strict) {
87
+ return PROTOCOL_STRICT_REGEX.test(inputString);
88
+ }
89
+ return PROTOCOL_REGEX.test(inputString) || (opts.acceptRelative ? PROTOCOL_RELATIVE_REGEX.test(inputString) : false);
90
+ }
13
91
  function hasTrailingSlash(input = "", respectQueryAndFragment) {
14
92
  {
15
93
  return input.endsWith("/");
@@ -31,6 +109,30 @@ function hasLeadingSlash(input = "") {
31
109
  function withLeadingSlash(input = "") {
32
110
  return hasLeadingSlash(input) ? input : "/" + input;
33
111
  }
112
+ function withoutBase(input, base) {
113
+ if (isEmptyURL(base)) {
114
+ return input;
115
+ }
116
+ const _base = withoutTrailingSlash(base);
117
+ if (!input.startsWith(_base)) {
118
+ return input;
119
+ }
120
+ const nextChar = input[_base.length];
121
+ if (nextChar && nextChar !== "/" && nextChar !== "?") {
122
+ return input;
123
+ }
124
+ const trimmed = input.slice(_base.length).replace(/^\/+/, "");
125
+ return "/" + trimmed;
126
+ }
127
+ function withQuery(input, query) {
128
+ const parsed = parseURL(input);
129
+ const mergedQuery = { ...parseQuery(parsed.search), ...query };
130
+ parsed.search = stringifyQuery(mergedQuery);
131
+ return stringifyParsedURL(parsed);
132
+ }
133
+ function isEmptyURL(url) {
134
+ return !url || url === "/";
135
+ }
34
136
  function isNonEmptyURL(url) {
35
137
  return url && url !== "/";
36
138
  }
@@ -46,8 +148,63 @@ function joinURL(base, ...input) {
46
148
  }
47
149
  return url;
48
150
  }
151
+ const protocolRelative = /* @__PURE__ */ Symbol.for("ufo:protocolRelative");
152
+ function parseURL(input = "", defaultProto) {
153
+ const _specialProtoMatch = input.match(
154
+ /^[\s\0]*(blob:|data:|javascript:|vbscript:)(.*)/i
155
+ );
156
+ if (_specialProtoMatch) {
157
+ const [, _proto, _pathname = ""] = _specialProtoMatch;
158
+ return {
159
+ protocol: _proto.toLowerCase(),
160
+ pathname: _pathname,
161
+ href: _proto + _pathname,
162
+ auth: "",
163
+ host: "",
164
+ search: "",
165
+ hash: ""
166
+ };
167
+ }
168
+ if (!hasProtocol(input, { acceptRelative: true })) {
169
+ return parsePath(input);
170
+ }
171
+ const [, protocol = "", auth, hostAndPath = ""] = input.replace(/\\/g, "/").match(/^[\s\0]*([\w+.-]{2,}:)?\/\/([^/@]+@)?(.*)/) || [];
172
+ let [, host = "", path = ""] = hostAndPath.match(/([^#/?]*)(.*)?/) || [];
173
+ if (protocol === "file:") {
174
+ path = path.replace(/\/(?=[A-Za-z]:)/, "");
175
+ }
176
+ const { pathname, search, hash } = parsePath(path);
177
+ return {
178
+ protocol: protocol.toLowerCase(),
179
+ auth: auth ? auth.slice(0, Math.max(0, auth.length - 1)) : "",
180
+ host,
181
+ pathname,
182
+ search,
183
+ hash,
184
+ [protocolRelative]: !protocol
185
+ };
186
+ }
187
+ function parsePath(input = "") {
188
+ const [pathname = "", search = "", hash = ""] = (input.match(/([^#?]*)(\?[^#]*)?(#.*)?/) || []).splice(1);
189
+ return {
190
+ pathname,
191
+ search,
192
+ hash
193
+ };
194
+ }
195
+ function stringifyParsedURL(parsed) {
196
+ const pathname = parsed.pathname || "";
197
+ const search = parsed.search ? (parsed.search.startsWith("?") ? "" : "?") + parsed.search : "";
198
+ const hash = parsed.hash || "";
199
+ const auth = parsed.auth ? parsed.auth + "@" : "";
200
+ const host = parsed.host || "";
201
+ const proto = parsed.protocol || parsed[protocolRelative] ? (parsed.protocol || "") + "//" : "";
202
+ return proto + auth + host + pathname + search + hash;
203
+ }
49
204
  export {
50
- withoutTrailingSlash as a,
205
+ withQuery as a,
206
+ withoutBase as b,
207
+ withoutTrailingSlash as c,
51
208
  decodePath as d,
52
209
  joinURL as j,
53
210
  withLeadingSlash as w
@@ -1,7 +1,7 @@
1
1
  globalThis.__nitro_main__ = import.meta.url;
2
2
  import { N as NodeResponse, s as serve } from "./_libs/srvx.mjs";
3
- import { a as HTTPError, d as defineHandler, t as toEventHandler, b as defineLazyEventHandler, H as H3Core } from "./_libs/h3.mjs";
4
- import { d as decodePath, w as withLeadingSlash, a as withoutTrailingSlash, j as joinURL } from "./_libs/ufo.mjs";
3
+ import { a as HTTPError, p as proxyRequest, d as defineHandler, t as toEventHandler, b as defineLazyEventHandler, H as H3Core } from "./_libs/h3.mjs";
4
+ import { b as withoutBase, j as joinURL, a as withQuery, d as decodePath, w as withLeadingSlash, c as withoutTrailingSlash } from "./_libs/ufo.mjs";
5
5
  import { promises } from "node:fs";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { dirname, resolve } from "node:path";
@@ -84,172 +84,204 @@ const headers = ((m) => function headersRouteRule(event) {
84
84
  event.res.headers.set(key2, value);
85
85
  }
86
86
  });
87
+ const proxy = ((m) => function proxyRouteRule(event) {
88
+ let target = m.options?.to;
89
+ if (!target) {
90
+ return;
91
+ }
92
+ if (target.endsWith("/**")) {
93
+ let targetPath = event.url.pathname + event.url.search;
94
+ const strpBase = m.options._proxyStripBase;
95
+ if (strpBase) {
96
+ if (!isPathInScope(event.url.pathname, strpBase)) {
97
+ throw new HTTPError({ status: 400 });
98
+ }
99
+ targetPath = withoutBase(targetPath, strpBase);
100
+ } else if (targetPath.startsWith("//")) {
101
+ targetPath = targetPath.replace(/^\/+/, "/");
102
+ }
103
+ target = joinURL(target.slice(0, -3), targetPath);
104
+ } else if (event.url.search) {
105
+ target = withQuery(target, Object.fromEntries(event.url.searchParams));
106
+ }
107
+ return proxyRequest(event, target, { ...m.options });
108
+ });
109
+ function isPathInScope(pathname, base) {
110
+ let canonical;
111
+ try {
112
+ const pre = pathname.replace(/%2f/gi, "/").replace(/%5c/gi, "\\");
113
+ canonical = new URL(pre, "http://_").pathname;
114
+ } catch {
115
+ return false;
116
+ }
117
+ return !base || canonical === base || canonical.startsWith(base + "/");
118
+ }
87
119
  const assets = {
88
- "/favicon.ico": {
89
- "type": "image/vnd.microsoft.icon",
90
- "etag": '"f1e-ESBTjHetHyiokkO0tT/irBbMO8Y"',
91
- "mtime": "2026-05-17T07:35:57.053Z",
92
- "size": 3870,
93
- "path": "../public/favicon.ico"
120
+ "/robots.txt": {
121
+ "type": "text/plain; charset=utf-8",
122
+ "etag": '"43-BEzmj4PuhUNHX+oW9uOnPSihxtU"',
123
+ "mtime": "2026-05-17T07:43:16.450Z",
124
+ "size": 67,
125
+ "path": "../public/robots.txt"
94
126
  },
95
127
  "/manifest.json": {
96
128
  "type": "application/json",
97
129
  "etag": '"1f2-Oqn/x1R1hBTtEjA8nFhpBeFJJNg"',
98
- "mtime": "2026-05-17T07:35:57.053Z",
130
+ "mtime": "2026-05-17T07:43:16.450Z",
99
131
  "size": 498,
100
132
  "path": "../public/manifest.json"
101
133
  },
102
- "/robots.txt": {
103
- "type": "text/plain; charset=utf-8",
104
- "etag": '"43-BEzmj4PuhUNHX+oW9uOnPSihxtU"',
105
- "mtime": "2026-05-17T07:35:57.053Z",
106
- "size": 67,
107
- "path": "../public/robots.txt"
108
- },
109
134
  "/assets/css/index-Dfs9RUU9.css": {
110
135
  "type": "text/css; charset=utf-8",
111
136
  "etag": '"429-auB1gSdvHWOpUkgakyObE/IliVA"',
112
- "mtime": "2026-05-17T07:35:54.999Z",
137
+ "mtime": "2026-05-17T07:43:14.153Z",
113
138
  "size": 1065,
114
139
  "path": "../public/assets/css/index-Dfs9RUU9.css"
115
140
  },
141
+ "/assets/woff2/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2": {
142
+ "type": "font/woff2",
143
+ "etag": '"1cfc-yYSDXNlt/tTRaj6rJo8ZMqvY7pQ"',
144
+ "mtime": "2026-05-17T07:43:14.153Z",
145
+ "size": 7420,
146
+ "path": "../public/assets/woff2/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2"
147
+ },
148
+ "/assets/woff2/geist-cyrillic-wght-normal-BEAKL7Jp.woff2": {
149
+ "type": "font/woff2",
150
+ "etag": '"3aec-5kpQSZEtAzzU5kdiuro3Zr2YR54"',
151
+ "mtime": "2026-05-17T07:43:14.150Z",
152
+ "size": 15084,
153
+ "path": "../public/assets/woff2/geist-cyrillic-wght-normal-BEAKL7Jp.woff2"
154
+ },
155
+ "/assets/woff2/geist-latin-ext-wght-normal-DC-KSUi6.woff2": {
156
+ "type": "font/woff2",
157
+ "etag": '"4080-mZu3Z7sOWqglha+kefNbUA9Pp+Q"',
158
+ "mtime": "2026-05-17T07:43:14.153Z",
159
+ "size": 16512,
160
+ "path": "../public/assets/woff2/geist-latin-ext-wght-normal-DC-KSUi6.woff2"
161
+ },
116
162
  "/assets/css/styles-B8p6jk5Z.css": {
117
163
  "type": "text/css; charset=utf-8",
118
164
  "etag": '"1a414-AEgDOOmvAte00dxPjn+Fb3xg2cQ"',
119
- "mtime": "2026-05-17T07:35:54.999Z",
165
+ "mtime": "2026-05-17T07:43:14.151Z",
120
166
  "size": 107540,
121
167
  "path": "../public/assets/css/styles-B8p6jk5Z.css"
122
168
  },
169
+ "/assets/woff2/geist-vietnamese-wght-normal-6IgcOCM7.woff2": {
170
+ "type": "font/woff2",
171
+ "etag": '"1f44-6MZ7/PEEOeDVF0eHI650KpwKQV8"',
172
+ "mtime": "2026-05-17T07:43:14.153Z",
173
+ "size": 8004,
174
+ "path": "../public/assets/woff2/geist-vietnamese-wght-normal-6IgcOCM7.woff2"
175
+ },
176
+ "/assets/woff2/geist-latin-wght-normal-BgDaEnEv.woff2": {
177
+ "type": "font/woff2",
178
+ "etag": '"72d8-9J+D7/6th5UzRxIgoFX9awJv47A"',
179
+ "mtime": "2026-05-17T07:43:14.153Z",
180
+ "size": 29400,
181
+ "path": "../public/assets/woff2/geist-latin-wght-normal-BgDaEnEv.woff2"
182
+ },
123
183
  "/assets/js/ChatInputBlock-D4CYR2D_.js": {
124
184
  "type": "text/javascript; charset=utf-8",
125
185
  "etag": '"1364-FqE9f33IgJsAhrf7P27HlZyRsLY"',
126
- "mtime": "2026-05-17T07:35:54.999Z",
186
+ "mtime": "2026-05-17T07:43:14.153Z",
127
187
  "size": 4964,
128
188
  "path": "../public/assets/js/ChatInputBlock-D4CYR2D_.js"
129
189
  },
130
190
  "/assets/js/MarkdownMessage-Bu4diQAT.js": {
131
191
  "type": "text/javascript; charset=utf-8",
132
192
  "etag": '"a21-8XU81Ttyh9KATGGVuJmH8rLr4CM"',
133
- "mtime": "2026-05-17T07:35:54.999Z",
193
+ "mtime": "2026-05-17T07:43:14.153Z",
134
194
  "size": 2593,
135
195
  "path": "../public/assets/js/MarkdownMessage-Bu4diQAT.js"
136
196
  },
137
- "/assets/js/base-ui-DKZpRETY.js": {
138
- "type": "text/javascript; charset=utf-8",
139
- "etag": '"23136-hvhmcqpJi+hXFszkcRaG5uSB360"',
140
- "mtime": "2026-05-17T07:35:54.999Z",
141
- "size": 143670,
142
- "path": "../public/assets/js/base-ui-DKZpRETY.js"
143
- },
144
197
  "/assets/js/chat._sessionId-IyYhnI65.js": {
145
198
  "type": "text/javascript; charset=utf-8",
146
199
  "etag": '"276a-zya7fXsy6AJo+RKujq+ZBEwag+o"',
147
- "mtime": "2026-05-17T07:35:54.999Z",
200
+ "mtime": "2026-05-17T07:43:14.153Z",
148
201
  "size": 10090,
149
202
  "path": "../public/assets/js/chat._sessionId-IyYhnI65.js"
150
203
  },
151
- "/assets/js/index-CYDXRqze.js": {
152
- "type": "text/javascript; charset=utf-8",
153
- "etag": '"29c-5jlykBIu4k2dH58NXxfjPvwjR5U"',
154
- "mtime": "2026-05-17T07:35:54.999Z",
155
- "size": 668,
156
- "path": "../public/assets/js/index-CYDXRqze.js"
157
- },
158
204
  "/assets/js/chat.index-CdO1bi1g.js": {
159
205
  "type": "text/javascript; charset=utf-8",
160
206
  "etag": '"2bc-JOtCuJmZFviPoFwrT24DCXcHwQY"',
161
- "mtime": "2026-05-17T07:35:54.999Z",
207
+ "mtime": "2026-05-17T07:43:14.153Z",
162
208
  "size": 700,
163
209
  "path": "../public/assets/js/chat.index-CdO1bi1g.js"
164
210
  },
211
+ "/assets/js/base-ui-DKZpRETY.js": {
212
+ "type": "text/javascript; charset=utf-8",
213
+ "etag": '"23136-hvhmcqpJi+hXFszkcRaG5uSB360"',
214
+ "mtime": "2026-05-17T07:43:14.153Z",
215
+ "size": 143670,
216
+ "path": "../public/assets/js/base-ui-DKZpRETY.js"
217
+ },
218
+ "/assets/js/index-CYDXRqze.js": {
219
+ "type": "text/javascript; charset=utf-8",
220
+ "etag": '"29c-5jlykBIu4k2dH58NXxfjPvwjR5U"',
221
+ "mtime": "2026-05-17T07:43:14.153Z",
222
+ "size": 668,
223
+ "path": "../public/assets/js/index-CYDXRqze.js"
224
+ },
165
225
  "/assets/js/memory-BC-tVM26.js": {
166
226
  "type": "text/javascript; charset=utf-8",
167
227
  "etag": '"129f-XO5LtGKoOtbs1TL9mQL+p0jcpkg"',
168
- "mtime": "2026-05-17T07:35:54.999Z",
228
+ "mtime": "2026-05-17T07:43:14.153Z",
169
229
  "size": 4767,
170
230
  "path": "../public/assets/js/memory-BC-tVM26.js"
171
231
  },
172
232
  "/assets/js/router-Cdi9aGOg.js": {
173
233
  "type": "text/javascript; charset=utf-8",
174
234
  "etag": '"5560-V72toq6u4rGXRMfd59VgiC/qr7s"',
175
- "mtime": "2026-05-17T07:35:54.999Z",
235
+ "mtime": "2026-05-17T07:43:14.153Z",
176
236
  "size": 21856,
177
237
  "path": "../public/assets/js/router-Cdi9aGOg.js"
178
238
  },
179
239
  "/assets/js/settings-CthZPCPZ.js": {
180
240
  "type": "text/javascript; charset=utf-8",
181
241
  "etag": '"16c-nkhcKPeOwanukwmWEZrl1U1L8TQ"',
182
- "mtime": "2026-05-17T07:35:54.999Z",
242
+ "mtime": "2026-05-17T07:43:14.153Z",
183
243
  "size": 364,
184
244
  "path": "../public/assets/js/settings-CthZPCPZ.js"
185
245
  },
186
246
  "/assets/js/skills-COr12qk7.js": {
187
247
  "type": "text/javascript; charset=utf-8",
188
248
  "etag": '"2bd9-oxq5eb4s7J3fGlrepereGxcr8Pw"',
189
- "mtime": "2026-05-17T07:35:54.999Z",
249
+ "mtime": "2026-05-17T07:43:14.153Z",
190
250
  "size": 11225,
191
251
  "path": "../public/assets/js/skills-COr12qk7.js"
192
252
  },
193
253
  "/assets/js/theme-CPkdkpaj.js": {
194
254
  "type": "text/javascript; charset=utf-8",
195
255
  "etag": '"245-JWXBP1zFNJpiVT0wBqxD0nTaUio"',
196
- "mtime": "2026-05-17T07:35:55.000Z",
256
+ "mtime": "2026-05-17T07:43:14.153Z",
197
257
  "size": 581,
198
258
  "path": "../public/assets/js/theme-CPkdkpaj.js"
199
259
  },
200
260
  "/assets/js/usage-oWmLZ5Lt.js": {
201
261
  "type": "text/javascript; charset=utf-8",
202
262
  "etag": '"2541-nrqiwsbK3hgSQKh9COEMgVFprDg"',
203
- "mtime": "2026-05-17T07:35:54.999Z",
263
+ "mtime": "2026-05-17T07:43:14.153Z",
204
264
  "size": 9537,
205
265
  "path": "../public/assets/js/usage-oWmLZ5Lt.js"
206
266
  },
207
- "/assets/woff2/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2": {
208
- "type": "font/woff2",
209
- "etag": '"1cfc-yYSDXNlt/tTRaj6rJo8ZMqvY7pQ"',
210
- "mtime": "2026-05-17T07:35:54.999Z",
211
- "size": 7420,
212
- "path": "../public/assets/woff2/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2"
213
- },
214
- "/assets/woff2/geist-cyrillic-wght-normal-BEAKL7Jp.woff2": {
215
- "type": "font/woff2",
216
- "etag": '"3aec-5kpQSZEtAzzU5kdiuro3Zr2YR54"',
217
- "mtime": "2026-05-17T07:35:54.999Z",
218
- "size": 15084,
219
- "path": "../public/assets/woff2/geist-cyrillic-wght-normal-BEAKL7Jp.woff2"
220
- },
221
- "/assets/woff2/geist-vietnamese-wght-normal-6IgcOCM7.woff2": {
222
- "type": "font/woff2",
223
- "etag": '"1f44-6MZ7/PEEOeDVF0eHI650KpwKQV8"',
224
- "mtime": "2026-05-17T07:35:54.999Z",
225
- "size": 8004,
226
- "path": "../public/assets/woff2/geist-vietnamese-wght-normal-6IgcOCM7.woff2"
227
- },
228
- "/assets/woff2/geist-latin-ext-wght-normal-DC-KSUi6.woff2": {
229
- "type": "font/woff2",
230
- "etag": '"4080-mZu3Z7sOWqglha+kefNbUA9Pp+Q"',
231
- "mtime": "2026-05-17T07:35:54.999Z",
232
- "size": 16512,
233
- "path": "../public/assets/woff2/geist-latin-ext-wght-normal-DC-KSUi6.woff2"
234
- },
235
- "/assets/woff2/geist-latin-wght-normal-BgDaEnEv.woff2": {
236
- "type": "font/woff2",
237
- "etag": '"72d8-9J+D7/6th5UzRxIgoFX9awJv47A"',
238
- "mtime": "2026-05-17T07:35:54.999Z",
239
- "size": 29400,
240
- "path": "../public/assets/woff2/geist-latin-wght-normal-BgDaEnEv.woff2"
267
+ "/favicon.ico": {
268
+ "type": "image/vnd.microsoft.icon",
269
+ "etag": '"f1e-ESBTjHetHyiokkO0tT/irBbMO8Y"',
270
+ "mtime": "2026-05-17T07:43:16.450Z",
271
+ "size": 3870,
272
+ "path": "../public/favicon.ico"
241
273
  },
242
274
  "/assets/js/index-CGq67I5U.js": {
243
275
  "type": "text/javascript; charset=utf-8",
244
276
  "etag": '"b48f5-JUWg8bwUt85x7vPgnOtDF2gjGGk"',
245
- "mtime": "2026-05-17T07:35:56.819Z",
277
+ "mtime": "2026-05-17T07:43:14.153Z",
246
278
  "size": 739573,
247
279
  "path": "../public/assets/js/index-CGq67I5U.js"
248
280
  },
249
281
  "/logo.png": {
250
282
  "type": "image/png",
251
283
  "etag": '"142435-x+cWIod8BP5RPjbiISayulI5r7I"',
252
- "mtime": "2026-05-17T07:35:57.053Z",
284
+ "mtime": "2026-05-17T07:43:16.450Z",
253
285
  "size": 1319989,
254
286
  "path": "../public/logo.png"
255
287
  }
@@ -338,14 +370,23 @@ const _uHHM1p = defineHandler((event) => {
338
370
  return readAsset(id);
339
371
  });
340
372
  const findRouteRules = /* @__PURE__ */ (() => {
341
- const $0 = [{ name: "headers", route: "/assets/**", handler: headers, options: { "cache-control": "public, max-age=31536000, immutable" } }];
373
+ const $0 = [{ name: "proxy", route: "/health", handler: proxy, options: { "to": "http://127.0.0.1:47474/health" } }], $1 = [{ name: "proxy", route: "/webhook", handler: proxy, options: { "to": "http://127.0.0.1:47474/webhook" } }], $2 = [{ name: "proxy", route: "/api/**", handler: proxy, options: { "to": "http://127.0.0.1:47474/api/**", "_proxyStripBase": "/api" } }], $3 = [{ name: "proxy", route: "/upload/**", handler: proxy, options: { "to": "http://127.0.0.1:47474/upload/**", "_proxyStripBase": "/upload" } }], $4 = [{ name: "headers", route: "/assets/**", handler: headers, options: { "cache-control": "public, max-age=31536000, immutable" } }];
342
374
  return (m, p) => {
343
375
  let r = [];
344
376
  if (p.charCodeAt(p.length - 1) === 47) p = p.slice(0, -1) || "/";
377
+ if (p === "/health") {
378
+ r.unshift({ data: $0 });
379
+ } else if (p === "/webhook") {
380
+ r.unshift({ data: $1 });
381
+ }
345
382
  let s = p.split("/"), l = s.length;
346
383
  if (l > 1) {
347
- if (s[1] === "assets") {
348
- r.unshift({ data: $0, params: { "_": s.slice(2).join("/") } });
384
+ if (s[1] === "api") {
385
+ r.unshift({ data: $2, params: { "_": s.slice(2).join("/") } });
386
+ } else if (s[1] === "upload") {
387
+ r.unshift({ data: $3, params: { "_": s.slice(2).join("/") } });
388
+ } else if (s[1] === "assets") {
389
+ r.unshift({ data: $4, params: { "_": s.slice(2).join("/") } });
349
390
  }
350
391
  }
351
392
  return r;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hermium",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Hermium CLI — self-hosted AI chat dashboard for Hermes Agent",
5
5
  "repository": {
6
6
  "type": "git",