heliumts 0.5.2 → 0.5.4

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
@@ -296,6 +296,9 @@ const config: HeliumConfig = {
296
296
  rateLimitWindowMs: 60000,
297
297
  tokenValidityMs: 30000,
298
298
  },
299
+ maxWsPayload: 10_485_760, // 10 MB max WebSocket message size
300
+ maxBodySize: 10_485_760, // 10 MB max HTTP RPC body
301
+ maxBatchSize: 50,
299
302
  },
300
303
  };
301
304
 
@@ -61,8 +61,9 @@ export type LinkProps = React.PropsWithChildren<Omit<React.AnchorHTMLAttributes<
61
61
  * Client-side navigation link.
62
62
  *
63
63
  * Intercepts left-clicks and uses the router's navigation helpers for SPA
64
- * navigation. Keeps normal anchor behaviour when modifier keys are used
65
- * or when the link is external.
64
+ * navigation. Keeps normal anchor behaviour when modifier keys are used,
65
+ * when the link is external, or when `target` / `download` attributes
66
+ * are present.
66
67
  *
67
68
  * Automatically prefetches page chunks on hover for faster navigation.
68
69
  */
@@ -1 +1 @@
1
- {"version":3,"file":"Router.d.ts","sourceRoot":"","sources":["../../src/client/Router.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAuD,MAAM,OAAO,CAAC;AAM5E,KAAK,WAAW,GAAG,YAAY,GAAG,mBAAmB,CAAC;AACtD,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,KAAK,IAAI,CAAC;AAgKhG,kDAAkD;AAClD,MAAM,WAAW,uBAAuB;IACpC,qDAAqD;IACrD,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAGD,KAAK,aAAa,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,YAAY,EAAE,eAAe,CAAC;IAC9B,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAChE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACnE,EAAE,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,KAAK,MAAM,IAAI,CAAC;IAChE,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,8GAA8G;IAC9G,SAAS,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,aAAa,qCAAkD,CAAC;AAE7E;;;;;;;;GAQG;AACH,wBAAgB,SAAS,kBAmCxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,EAAE,OAAe,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,QAyBlF;AA2CD,MAAM,MAAM,SAAS,GAAG,KAAK,CAAC,iBAAiB,CAC3C,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,GAAG;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qDAAqD;IACrD,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB,CACJ,CAAC;AA+BF;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,2CA6CpC;AAGD;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAC9F,SAAS,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACrC,SAAS,EAAE,UAAU,CAAC;CACzB,CAAC;AAGF,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;CAAE,2CAoFlF"}
1
+ {"version":3,"file":"Router.d.ts","sourceRoot":"","sources":["../../src/client/Router.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAuD,MAAM,OAAO,CAAC;AAM5E,KAAK,WAAW,GAAG,YAAY,GAAG,mBAAmB,CAAC;AACtD,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,KAAK,IAAI,CAAC;AAgKhG,kDAAkD;AAClD,MAAM,WAAW,uBAAuB;IACpC,qDAAqD;IACrD,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAGD,KAAK,aAAa,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,YAAY,EAAE,eAAe,CAAC;IAC9B,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAChE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACnE,EAAE,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,KAAK,MAAM,IAAI,CAAC;IAChE,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,8GAA8G;IAC9G,SAAS,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,aAAa,qCAAkD,CAAC;AAE7E;;;;;;;;GAQG;AACH,wBAAgB,SAAS,kBAmCxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,EAAE,OAAe,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,QAyBlF;AA6CD,MAAM,MAAM,SAAS,GAAG,KAAK,CAAC,iBAAiB,CAC3C,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,GAAG;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qDAAqD;IACrD,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB,CACJ,CAAC;AA+BF;;;;;;;;;GASG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,2CA4DpC;AAGD;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAC9F,SAAS,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACrC,SAAS,EAAE,UAAU,CAAC;CACzB,CAAC;AAGF,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;CAAE,2CAoFlF"}
@@ -231,17 +231,17 @@ function navigate(href, options = {}) {
231
231
  else {
232
232
  window.history.pushState(null, "", href);
233
233
  }
234
- // Update location and clear navigating state after navigation
235
- // Use requestAnimationFrame to allow the new page to start rendering
236
- requestAnimationFrame(() => {
237
- updateLocation(false);
238
- // Scroll to top if enabled
239
- if (scrollToTop) {
240
- window.scrollTo({ top: 0, left: 0, behavior: "smooth" });
241
- }
242
- // Emit navigation event after navigation completes
243
- routerEventEmitter.emit("navigation", { from, to });
244
- });
234
+ // Scroll to top immediately after pushState, before React re-renders.
235
+ // Using instant scroll avoids race conditions where smooth scrolling
236
+ // gets interrupted by React DOM updates, especially on Safari mobile.
237
+ if (scrollToTop) {
238
+ window.scrollTo({ top: 0, left: 0, behavior: "instant" });
239
+ }
240
+ // Update location state synchronously so there is no stale-state window
241
+ // between pushState and the next render.
242
+ updateLocation(false);
243
+ // Emit navigation event after state is consistent
244
+ routerEventEmitter.emit("navigation", { from, to });
245
245
  }
246
246
  /**
247
247
  * Check if a URL is external (different origin).
@@ -275,46 +275,49 @@ else {
275
275
  * Client-side navigation link.
276
276
  *
277
277
  * Intercepts left-clicks and uses the router's navigation helpers for SPA
278
- * navigation. Keeps normal anchor behaviour when modifier keys are used
279
- * or when the link is external.
278
+ * navigation. Keeps normal anchor behaviour when modifier keys are used,
279
+ * when the link is external, or when `target` / `download` attributes
280
+ * are present.
280
281
  *
281
282
  * Automatically prefetches page chunks on hover for faster navigation.
282
283
  */
283
284
  export function Link(props) {
284
- const { prefetch = true, scrollToTop = true } = props;
285
+ const { children, href, className, prefetch: prefetchProp = true, scrollToTop = true, replace: replaceProp, target, download, onClick: userOnClick, onMouseEnter: userOnMouseEnter, onFocus: userOnFocus, ...restProps } = props;
285
286
  const onClick = (e) => {
287
+ // Let user's onClick run first so they can call e.preventDefault()
288
+ userOnClick?.(e);
286
289
  if (e.defaultPrevented ||
287
290
  e.button !== 0 || // only left click
288
291
  e.metaKey ||
289
292
  e.ctrlKey ||
290
293
  e.shiftKey ||
291
294
  e.altKey ||
292
- isExternalUrl(props.href) // let browser handle external links
295
+ target || // let browser handle target="_blank" etc.
296
+ download != null || // let browser handle downloads
297
+ isExternalUrl(href) // let browser handle external links
293
298
  ) {
294
299
  return;
295
300
  }
296
301
  e.preventDefault();
297
- navigate(props.href, { replace: props.replace, scrollToTop });
298
- props.onClick?.(e);
302
+ navigate(href, { replace: replaceProp, scrollToTop });
299
303
  };
300
304
  const onMouseEnter = async (e) => {
301
305
  // Prefetch the route on hover if enabled and not external (lazy-load prefetch logic)
302
- if (prefetch && !isExternalUrl(props.href) && globalRoutes.length > 0) {
306
+ if (prefetchProp && !isExternalUrl(href) && globalRoutes.length > 0) {
303
307
  const { prefetchRoute } = await import("./prefetch.js");
304
- prefetchRoute(props.href, globalRoutes);
308
+ prefetchRoute(href, globalRoutes);
305
309
  }
306
- props.onMouseEnter?.(e);
310
+ userOnMouseEnter?.(e);
307
311
  };
308
312
  const onFocus = async (e) => {
309
313
  // Also prefetch on focus (keyboard navigation)
310
- if (prefetch && !isExternalUrl(props.href) && globalRoutes.length > 0) {
314
+ if (prefetchProp && !isExternalUrl(href) && globalRoutes.length > 0) {
311
315
  const { prefetchRoute } = await import("./prefetch.js");
312
- prefetchRoute(props.href, globalRoutes);
316
+ prefetchRoute(href, globalRoutes);
313
317
  }
314
- props.onFocus?.(e);
318
+ userOnFocus?.(e);
315
319
  };
316
- const { children, href, className, prefetch: _prefetch, scrollToTop: _scrollToTop, ...safeProps } = props;
317
- return (_jsx("a", { href: href, onClick: onClick, onMouseEnter: onMouseEnter, onFocus: onFocus, className: className, ...safeProps, children: children }));
320
+ return (_jsx("a", { ...restProps, href: href, target: target, download: download, onClick: onClick, onMouseEnter: onMouseEnter, onFocus: onFocus, className: className, children: children }));
318
321
  }
319
322
  // Main router component
320
323
  export function AppRouter({ AppShell }) {
@@ -1 +1 @@
1
- {"version":3,"file":"Router.js","sourceRoot":"","sources":["../../src/client/Router.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentType } from \"react\";\nimport React, { useMemo, useSyncExternalStore, useTransition } from \"react\";\n\nimport type { RouteEntry } from \"./routerManifest.js\";\nimport { buildRoutes } from \"./routerManifest.js\";\n\n// Event emitter for router events\ntype RouterEvent = \"navigation\" | \"before-navigation\";\ntype EventListener = (event: { from: string; to: string; preventDefault?: () => void }) => void;\n\nclass RouterEventEmitter {\n private listeners: Map<RouterEvent, Set<EventListener>> = new Map();\n\n on(event: RouterEvent, listener: EventListener): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n\n // Return unsubscribe function\n return () => {\n this.listeners.get(event)?.delete(listener);\n };\n }\n\n emit(event: RouterEvent, data: { from: string; to: string }): boolean {\n const eventListeners = this.listeners.get(event);\n if (!eventListeners || eventListeners.size === 0) {\n return true;\n }\n\n let prevented = false;\n const preventDefault = () => {\n prevented = true;\n };\n\n const eventData = event === \"before-navigation\" ? { ...data, preventDefault } : data;\n\n eventListeners.forEach((listener) => {\n listener(eventData);\n });\n\n return !prevented;\n }\n\n // Clear all listeners - useful for HMR\n clear() {\n this.listeners.clear();\n }\n}\n\n// Use a singleton that survives HMR by attaching to window in dev mode\nlet routerEventEmitter: RouterEventEmitter;\n\nif (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n // In dev mode, reuse the same emitter instance across HMR\n const globalWindow = window as typeof window & { __heliumRouterEmitter?: RouterEventEmitter };\n if (!globalWindow.__heliumRouterEmitter) {\n globalWindow.__heliumRouterEmitter = new RouterEventEmitter();\n }\n routerEventEmitter = globalWindow.__heliumRouterEmitter;\n} else {\n routerEventEmitter = new RouterEventEmitter();\n}\n\ntype RouterState = {\n path: string;\n searchParams: URLSearchParams;\n isNavigating: boolean;\n};\n\nfunction getLocation(): RouterState {\n const { pathname, search } = window.location;\n return {\n path: pathname,\n searchParams: new URLSearchParams(search),\n isNavigating: false,\n };\n}\n\nfunction matchRoute(path: string, routes: RouteEntry[]) {\n for (const r of routes) {\n const m = r.matcher(path);\n if (m) {\n return { params: m.params, route: r };\n }\n }\n return null;\n}\n\n// Location store for useSyncExternalStore\n// Preserve across HMR by attaching to window in dev mode\nlet currentLocation: RouterState;\nlet locationListeners: Set<() => void>;\n\nif (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n const globalWindow = window as typeof window & {\n __heliumCurrentLocation?: RouterState;\n __heliumLocationListeners?: Set<() => void>;\n };\n if (!globalWindow.__heliumCurrentLocation) {\n globalWindow.__heliumCurrentLocation = getLocation();\n }\n if (!globalWindow.__heliumLocationListeners) {\n globalWindow.__heliumLocationListeners = new Set();\n }\n currentLocation = globalWindow.__heliumCurrentLocation;\n locationListeners = globalWindow.__heliumLocationListeners;\n} else if (typeof window !== \"undefined\") {\n currentLocation = getLocation();\n locationListeners = new Set();\n} else {\n currentLocation = { path: \"/\", searchParams: new URLSearchParams(), isNavigating: false };\n locationListeners = new Set();\n}\n\n// Helper to re-extract params from path using stored routes during HMR\nfunction extractParamsFromPath(path: string): Record<string, string | string[]> {\n if (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n const globalWindow = window as typeof window & { __heliumGlobalRoutes?: RouteEntry[] };\n const routes = globalWindow.__heliumGlobalRoutes;\n if (routes && routes.length > 0) {\n const match = matchRoute(path, routes);\n if (match) {\n return match.params;\n }\n }\n }\n return {};\n}\n\nfunction subscribeToLocation(callback: () => void) {\n locationListeners.add(callback);\n return () => locationListeners.delete(callback);\n}\n\nfunction getLocationSnapshot() {\n return currentLocation;\n}\n\nfunction getServerSnapshot() {\n return { path: \"/\", searchParams: new URLSearchParams(), isNavigating: false };\n}\n\nfunction updateLocation(isNavigating = false) {\n const newLocation = { ...getLocation(), isNavigating };\n currentLocation = newLocation;\n // Update the global reference in dev mode\n if (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n (window as typeof window & { __heliumCurrentLocation?: RouterState }).__heliumCurrentLocation = newLocation;\n }\n locationListeners.forEach((listener) => listener());\n}\n\n// Set up global listeners once\nif (typeof window !== \"undefined\") {\n // Only set up once, survives HMR\n const globalWindow = window as typeof window & { __heliumLocationListenerSetup?: boolean };\n if (!globalWindow.__heliumLocationListenerSetup) {\n globalWindow.__heliumLocationListenerSetup = true;\n\n window.addEventListener(\"popstate\", () => updateLocation(false));\n\n // Also listen to navigation events from the emitter\n routerEventEmitter.on(\"navigation\", () => updateLocation(false));\n }\n}\n\n/** Options for push/replace navigation methods */\nexport interface RouterNavigationOptions {\n /** Scroll to top after navigation (default: true) */\n scrollToTop?: boolean;\n}\n\n// Context for useRouter hook\ntype RouterContext = {\n path: string;\n params: Record<string, string | string[]>;\n searchParams: URLSearchParams;\n push: (href: string, options?: RouterNavigationOptions) => void;\n replace: (href: string, options?: RouterNavigationOptions) => void;\n on: (event: RouterEvent, listener: EventListener) => () => void;\n status: 200 | 404;\n isNavigating: boolean;\n /** Indicates content is stale (old content shown while new content renders) - React 18+ concurrent feature */\n isPending: boolean;\n};\n\nexport const RouterContext = React.createContext<RouterContext | null>(null);\n\n/**\n * Access router context inside a component tree managed by <AppRouter />.\n *\n * Provides current path, route params, URL search params and navigation helpers\n * (\\`push\\`, \\`replace\\`) as well as an \\`on\\` method to subscribe to navigation events.\n * The \\`isNavigating\\` property indicates when a navigation is in progress.\n * The \\`isPending\\` property indicates when content is stale (React concurrent features).\n * Throws when used outside of an <AppRouter /> provider.\n */\nexport function useRouter() {\n const ctx = React.useContext(RouterContext);\n if (!ctx) {\n // During HMR in development, context might be temporarily unavailable\n // Provide a temporary fallback to prevent white screen of death\n // Re-extract params from current path using stored routes\n if (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n const currentPath = window.location.pathname;\n return {\n path: currentPath,\n params: extractParamsFromPath(currentPath),\n searchParams: new URLSearchParams(window.location.search),\n push: (href: string, options?: RouterNavigationOptions) => {\n window.history.pushState({}, \"\", href);\n if (options?.scrollToTop !== false) {\n window.scrollTo({ top: 0, left: 0, behavior: \"smooth\" });\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n },\n replace: (href: string, options?: RouterNavigationOptions) => {\n window.history.replaceState({}, \"\", href);\n if (options?.scrollToTop !== false) {\n window.scrollTo({ top: 0, left: 0, behavior: \"smooth\" });\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n },\n on: () => () => {},\n status: 200 as const,\n isNavigating: false,\n isPending: false,\n };\n }\n throw new Error(\"useRouter must be used inside <AppRouter>\");\n }\n return ctx;\n}\n\n/**\n * Redirect component for declarative navigation.\n * Use this instead of calling router.push() during render.\n *\n * @example\n * \\`\\`\\`tsx\n * export default function Docs() {\n * return <Redirect to=\"/docs/getting-started\" />;\n * }\n * \\`\\`\\`\n */\nexport function Redirect({ to, replace = false }: { to: string; replace?: boolean }) {\n const hasRedirected = React.useRef(false);\n\n // Use useLayoutEffect to redirect before paint\n React.useLayoutEffect(() => {\n const targetPath = to.split(\"?\")[0];\n if (!hasRedirected.current && window.location.pathname !== targetPath) {\n hasRedirected.current = true;\n\n // Perform navigation\n if (replace) {\n window.history.replaceState(null, \"\", to);\n } else {\n window.history.pushState(null, \"\", to);\n }\n\n // Emit navigation event to update router state\n routerEventEmitter.emit(\"navigation\", {\n from: window.location.pathname,\n to: targetPath,\n });\n }\n }, [to, replace]);\n\n return null;\n}\n\n/** Options for navigation */\ninterface NavigateOptions {\n replace?: boolean;\n scrollToTop?: boolean;\n}\n\n// Navigation helper\nfunction navigate(href: string, options: NavigateOptions = {}) {\n const { replace = false, scrollToTop = true } = options;\n const from = window.location.pathname;\n const to = href.split(\"?\")[0]; // Extract pathname from href\n\n // Emit before-navigation event (can be prevented)\n const canNavigate = routerEventEmitter.emit(\"before-navigation\", { from, to });\n if (!canNavigate) {\n return; // Navigation was prevented\n }\n\n // Set navigating state to true before navigation\n currentLocation = { ...currentLocation, isNavigating: true };\n locationListeners.forEach((listener) => listener());\n\n if (replace) {\n window.history.replaceState(null, \"\", href);\n } else {\n window.history.pushState(null, \"\", href);\n }\n\n // Update location and clear navigating state after navigation\n // Use requestAnimationFrame to allow the new page to start rendering\n requestAnimationFrame(() => {\n updateLocation(false);\n // Scroll to top if enabled\n if (scrollToTop) {\n window.scrollTo({ top: 0, left: 0, behavior: \"smooth\" });\n }\n // Emit navigation event after navigation completes\n routerEventEmitter.emit(\"navigation\", { from, to });\n });\n}\n\nexport type LinkProps = React.PropsWithChildren<\n Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, \"href\"> & {\n href: string;\n replace?: boolean;\n /** Disable prefetching on hover (default: false - prefetch is enabled) */\n prefetch?: boolean;\n /** Scroll to top after navigation (default: true) */\n scrollToTop?: boolean;\n }\n>;\n\n/**\n * Check if a URL is external (different origin).\n */\nfunction isExternalUrl(href: string): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n try {\n const url = new URL(href, window.location.origin);\n return url.origin !== window.location.origin;\n } catch {\n return false;\n }\n}\n\n// Store routes globally for prefetching (set by AppRouter)\n// Preserve across HMR in dev mode\nlet globalRoutes: RouteEntry[];\n\nif (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n const globalWindow = window as typeof window & { __heliumGlobalRoutes?: RouteEntry[] };\n if (!globalWindow.__heliumGlobalRoutes) {\n globalWindow.__heliumGlobalRoutes = [];\n }\n globalRoutes = globalWindow.__heliumGlobalRoutes;\n} else {\n globalRoutes = [];\n}\n\n/**\n * Client-side navigation link.\n *\n * Intercepts left-clicks and uses the router's navigation helpers for SPA\n * navigation. Keeps normal anchor behaviour when modifier keys are used\n * or when the link is external.\n *\n * Automatically prefetches page chunks on hover for faster navigation.\n */\nexport function Link(props: LinkProps) {\n const { prefetch = true, scrollToTop = true } = props;\n\n const onClick = (e: React.MouseEvent<HTMLAnchorElement>) => {\n if (\n e.defaultPrevented ||\n e.button !== 0 || // only left click\n e.metaKey ||\n e.ctrlKey ||\n e.shiftKey ||\n e.altKey ||\n isExternalUrl(props.href) // let browser handle external links\n ) {\n return;\n }\n e.preventDefault();\n navigate(props.href, { replace: props.replace, scrollToTop });\n props.onClick?.(e);\n };\n\n const onMouseEnter = async (e: React.MouseEvent<HTMLAnchorElement>) => {\n // Prefetch the route on hover if enabled and not external (lazy-load prefetch logic)\n if (prefetch && !isExternalUrl(props.href) && globalRoutes.length > 0) {\n const { prefetchRoute } = await import(\"./prefetch.js\");\n prefetchRoute(props.href, globalRoutes);\n }\n props.onMouseEnter?.(e);\n };\n\n const onFocus = async (e: React.FocusEvent<HTMLAnchorElement>) => {\n // Also prefetch on focus (keyboard navigation)\n if (prefetch && !isExternalUrl(props.href) && globalRoutes.length > 0) {\n const { prefetchRoute } = await import(\"./prefetch.js\");\n prefetchRoute(props.href, globalRoutes);\n }\n props.onFocus?.(e);\n };\n\n const { children, href, className, prefetch: _prefetch, scrollToTop: _scrollToTop, ...safeProps } = props;\n\n return (\n <a href={href} onClick={onClick} onMouseEnter={onMouseEnter} onFocus={onFocus} className={className} {...safeProps}>\n {children}\n </a>\n );\n}\n\n// AppShell props type\n/**\n * Props passed to an optional \\`AppShell\\` wrapper component used by <AppRouter />.\n *\n * \\`Component\\` — the page component to render. \\`pageProps\\` — props provided to the page.\n */\nexport type AppShellProps<TPageProps extends Record<string, unknown> = Record<string, unknown>> = {\n Component: ComponentType<TPageProps>;\n pageProps: TPageProps;\n};\n\n// Main router component\nexport function AppRouter({ AppShell }: { AppShell?: ComponentType<AppShellProps> }) {\n // useTransition for concurrent rendering - allows React to keep UI responsive during navigation\n const [isPending, startTransition] = useTransition();\n\n // Build routes once on mount (client-side only)\n const { routes, NotFound } = useMemo(() => {\n if (typeof window === \"undefined\") {\n return { routes: [], NotFound: undefined };\n }\n const result = buildRoutes();\n // Store routes globally for Link prefetching\n // In dev mode, also update the global reference to survive HMR\n if (import.meta.env?.DEV) {\n const globalWindow = window as typeof window & { __heliumGlobalRoutes?: RouteEntry[] };\n globalWindow.__heliumGlobalRoutes = result.routes;\n // Update the module-level reference as well\n globalRoutes.length = 0;\n globalRoutes.push(...result.routes);\n } else {\n globalRoutes = result.routes;\n }\n return result;\n }, []);\n\n // Use useSyncExternalStore to subscribe to location changes\n // This ensures synchronous updates when location changes\n const state = useSyncExternalStore(subscribeToLocation, getLocationSnapshot, getServerSnapshot);\n\n const match = useMemo(() => matchRoute(state.path, routes), [state.path, routes]);\n\n // Use matched params, or fall back to re-extracting from path using global routes during HMR\n const currentParams = match?.params ?? (import.meta.env?.DEV ? extractParamsFromPath(state.path) : {});\n\n // In dev mode, always read fresh searchParams from URL to handle HMR edge cases\n const currentSearchParams = import.meta.env?.DEV ? new URLSearchParams(window.location.search) : state.searchParams;\n\n const routerValue: RouterContext = {\n path: state.path,\n params: currentParams,\n searchParams: currentSearchParams,\n push: (href, options) => {\n // Wrap navigation in startTransition for smoother updates\n startTransition(() => {\n navigate(href, { scrollToTop: options?.scrollToTop });\n });\n },\n replace: (href, options) => {\n startTransition(() => {\n navigate(href, { replace: true, scrollToTop: options?.scrollToTop });\n });\n },\n on: (event, listener) => routerEventEmitter.on(event, listener),\n status: match ? 200 : 404,\n isNavigating: state.isNavigating,\n isPending,\n };\n\n if (!match) {\n const NotFoundComp = NotFound ?? (() => <div>Not found</div>);\n const content = <NotFoundComp />;\n\n return <RouterContext.Provider value={routerValue}>{AppShell ? <AppShell Component={NotFoundComp} pageProps={{}} /> : content}</RouterContext.Provider>;\n }\n\n const Page = match.route.Component as ComponentType<{ params: Record<string, string | string[]>; searchParams: URLSearchParams }>;\n const pageProps = {\n params: match.params,\n searchParams: currentSearchParams,\n };\n\n // Create a wrapped component that includes all layouts\n const WrappedPage = () => {\n let content = <Page {...pageProps} />;\n // Wrap page with layouts (from outer to inner)\n for (let i = match.route.layouts.length - 1; i >= 0; i--) {\n const Layout = match.route.layouts[i];\n content = <Layout>{content}</Layout>;\n }\n return content;\n };\n\n const finalContent = AppShell ? <AppShell Component={WrappedPage} pageProps={{}} /> : <WrappedPage />;\n\n return <RouterContext.Provider value={routerValue}>{finalContent}</RouterContext.Provider>;\n}\n"]}
1
+ {"version":3,"file":"Router.js","sourceRoot":"","sources":["../../src/client/Router.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentType } from \"react\";\nimport React, { useMemo, useSyncExternalStore, useTransition } from \"react\";\n\nimport type { RouteEntry } from \"./routerManifest.js\";\nimport { buildRoutes } from \"./routerManifest.js\";\n\n// Event emitter for router events\ntype RouterEvent = \"navigation\" | \"before-navigation\";\ntype EventListener = (event: { from: string; to: string; preventDefault?: () => void }) => void;\n\nclass RouterEventEmitter {\n private listeners: Map<RouterEvent, Set<EventListener>> = new Map();\n\n on(event: RouterEvent, listener: EventListener): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n\n // Return unsubscribe function\n return () => {\n this.listeners.get(event)?.delete(listener);\n };\n }\n\n emit(event: RouterEvent, data: { from: string; to: string }): boolean {\n const eventListeners = this.listeners.get(event);\n if (!eventListeners || eventListeners.size === 0) {\n return true;\n }\n\n let prevented = false;\n const preventDefault = () => {\n prevented = true;\n };\n\n const eventData = event === \"before-navigation\" ? { ...data, preventDefault } : data;\n\n eventListeners.forEach((listener) => {\n listener(eventData);\n });\n\n return !prevented;\n }\n\n // Clear all listeners - useful for HMR\n clear() {\n this.listeners.clear();\n }\n}\n\n// Use a singleton that survives HMR by attaching to window in dev mode\nlet routerEventEmitter: RouterEventEmitter;\n\nif (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n // In dev mode, reuse the same emitter instance across HMR\n const globalWindow = window as typeof window & { __heliumRouterEmitter?: RouterEventEmitter };\n if (!globalWindow.__heliumRouterEmitter) {\n globalWindow.__heliumRouterEmitter = new RouterEventEmitter();\n }\n routerEventEmitter = globalWindow.__heliumRouterEmitter;\n} else {\n routerEventEmitter = new RouterEventEmitter();\n}\n\ntype RouterState = {\n path: string;\n searchParams: URLSearchParams;\n isNavigating: boolean;\n};\n\nfunction getLocation(): RouterState {\n const { pathname, search } = window.location;\n return {\n path: pathname,\n searchParams: new URLSearchParams(search),\n isNavigating: false,\n };\n}\n\nfunction matchRoute(path: string, routes: RouteEntry[]) {\n for (const r of routes) {\n const m = r.matcher(path);\n if (m) {\n return { params: m.params, route: r };\n }\n }\n return null;\n}\n\n// Location store for useSyncExternalStore\n// Preserve across HMR by attaching to window in dev mode\nlet currentLocation: RouterState;\nlet locationListeners: Set<() => void>;\n\nif (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n const globalWindow = window as typeof window & {\n __heliumCurrentLocation?: RouterState;\n __heliumLocationListeners?: Set<() => void>;\n };\n if (!globalWindow.__heliumCurrentLocation) {\n globalWindow.__heliumCurrentLocation = getLocation();\n }\n if (!globalWindow.__heliumLocationListeners) {\n globalWindow.__heliumLocationListeners = new Set();\n }\n currentLocation = globalWindow.__heliumCurrentLocation;\n locationListeners = globalWindow.__heliumLocationListeners;\n} else if (typeof window !== \"undefined\") {\n currentLocation = getLocation();\n locationListeners = new Set();\n} else {\n currentLocation = { path: \"/\", searchParams: new URLSearchParams(), isNavigating: false };\n locationListeners = new Set();\n}\n\n// Helper to re-extract params from path using stored routes during HMR\nfunction extractParamsFromPath(path: string): Record<string, string | string[]> {\n if (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n const globalWindow = window as typeof window & { __heliumGlobalRoutes?: RouteEntry[] };\n const routes = globalWindow.__heliumGlobalRoutes;\n if (routes && routes.length > 0) {\n const match = matchRoute(path, routes);\n if (match) {\n return match.params;\n }\n }\n }\n return {};\n}\n\nfunction subscribeToLocation(callback: () => void) {\n locationListeners.add(callback);\n return () => locationListeners.delete(callback);\n}\n\nfunction getLocationSnapshot() {\n return currentLocation;\n}\n\nfunction getServerSnapshot() {\n return { path: \"/\", searchParams: new URLSearchParams(), isNavigating: false };\n}\n\nfunction updateLocation(isNavigating = false) {\n const newLocation = { ...getLocation(), isNavigating };\n currentLocation = newLocation;\n // Update the global reference in dev mode\n if (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n (window as typeof window & { __heliumCurrentLocation?: RouterState }).__heliumCurrentLocation = newLocation;\n }\n locationListeners.forEach((listener) => listener());\n}\n\n// Set up global listeners once\nif (typeof window !== \"undefined\") {\n // Only set up once, survives HMR\n const globalWindow = window as typeof window & { __heliumLocationListenerSetup?: boolean };\n if (!globalWindow.__heliumLocationListenerSetup) {\n globalWindow.__heliumLocationListenerSetup = true;\n\n window.addEventListener(\"popstate\", () => updateLocation(false));\n\n // Also listen to navigation events from the emitter\n routerEventEmitter.on(\"navigation\", () => updateLocation(false));\n }\n}\n\n/** Options for push/replace navigation methods */\nexport interface RouterNavigationOptions {\n /** Scroll to top after navigation (default: true) */\n scrollToTop?: boolean;\n}\n\n// Context for useRouter hook\ntype RouterContext = {\n path: string;\n params: Record<string, string | string[]>;\n searchParams: URLSearchParams;\n push: (href: string, options?: RouterNavigationOptions) => void;\n replace: (href: string, options?: RouterNavigationOptions) => void;\n on: (event: RouterEvent, listener: EventListener) => () => void;\n status: 200 | 404;\n isNavigating: boolean;\n /** Indicates content is stale (old content shown while new content renders) - React 18+ concurrent feature */\n isPending: boolean;\n};\n\nexport const RouterContext = React.createContext<RouterContext | null>(null);\n\n/**\n * Access router context inside a component tree managed by <AppRouter />.\n *\n * Provides current path, route params, URL search params and navigation helpers\n * (\\`push\\`, \\`replace\\`) as well as an \\`on\\` method to subscribe to navigation events.\n * The \\`isNavigating\\` property indicates when a navigation is in progress.\n * The \\`isPending\\` property indicates when content is stale (React concurrent features).\n * Throws when used outside of an <AppRouter /> provider.\n */\nexport function useRouter() {\n const ctx = React.useContext(RouterContext);\n if (!ctx) {\n // During HMR in development, context might be temporarily unavailable\n // Provide a temporary fallback to prevent white screen of death\n // Re-extract params from current path using stored routes\n if (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n const currentPath = window.location.pathname;\n return {\n path: currentPath,\n params: extractParamsFromPath(currentPath),\n searchParams: new URLSearchParams(window.location.search),\n push: (href: string, options?: RouterNavigationOptions) => {\n window.history.pushState({}, \"\", href);\n if (options?.scrollToTop !== false) {\n window.scrollTo({ top: 0, left: 0, behavior: \"smooth\" });\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n },\n replace: (href: string, options?: RouterNavigationOptions) => {\n window.history.replaceState({}, \"\", href);\n if (options?.scrollToTop !== false) {\n window.scrollTo({ top: 0, left: 0, behavior: \"smooth\" });\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n },\n on: () => () => {},\n status: 200 as const,\n isNavigating: false,\n isPending: false,\n };\n }\n throw new Error(\"useRouter must be used inside <AppRouter>\");\n }\n return ctx;\n}\n\n/**\n * Redirect component for declarative navigation.\n * Use this instead of calling router.push() during render.\n *\n * @example\n * \\`\\`\\`tsx\n * export default function Docs() {\n * return <Redirect to=\"/docs/getting-started\" />;\n * }\n * \\`\\`\\`\n */\nexport function Redirect({ to, replace = false }: { to: string; replace?: boolean }) {\n const hasRedirected = React.useRef(false);\n\n // Use useLayoutEffect to redirect before paint\n React.useLayoutEffect(() => {\n const targetPath = to.split(\"?\")[0];\n if (!hasRedirected.current && window.location.pathname !== targetPath) {\n hasRedirected.current = true;\n\n // Perform navigation\n if (replace) {\n window.history.replaceState(null, \"\", to);\n } else {\n window.history.pushState(null, \"\", to);\n }\n\n // Emit navigation event to update router state\n routerEventEmitter.emit(\"navigation\", {\n from: window.location.pathname,\n to: targetPath,\n });\n }\n }, [to, replace]);\n\n return null;\n}\n\n/** Options for navigation */\ninterface NavigateOptions {\n replace?: boolean;\n scrollToTop?: boolean;\n}\n\n// Navigation helper\nfunction navigate(href: string, options: NavigateOptions = {}) {\n const { replace = false, scrollToTop = true } = options;\n const from = window.location.pathname;\n const to = href.split(\"?\")[0]; // Extract pathname from href\n\n // Emit before-navigation event (can be prevented)\n const canNavigate = routerEventEmitter.emit(\"before-navigation\", { from, to });\n if (!canNavigate) {\n return; // Navigation was prevented\n }\n\n // Set navigating state to true before navigation\n currentLocation = { ...currentLocation, isNavigating: true };\n locationListeners.forEach((listener) => listener());\n\n if (replace) {\n window.history.replaceState(null, \"\", href);\n } else {\n window.history.pushState(null, \"\", href);\n }\n\n // Scroll to top immediately after pushState, before React re-renders.\n // Using instant scroll avoids race conditions where smooth scrolling\n // gets interrupted by React DOM updates, especially on Safari mobile.\n if (scrollToTop) {\n window.scrollTo({ top: 0, left: 0, behavior: \"instant\" });\n }\n\n // Update location state synchronously so there is no stale-state window\n // between pushState and the next render.\n updateLocation(false);\n\n // Emit navigation event after state is consistent\n routerEventEmitter.emit(\"navigation\", { from, to });\n}\n\nexport type LinkProps = React.PropsWithChildren<\n Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, \"href\"> & {\n href: string;\n replace?: boolean;\n /** Disable prefetching on hover (default: false - prefetch is enabled) */\n prefetch?: boolean;\n /** Scroll to top after navigation (default: true) */\n scrollToTop?: boolean;\n }\n>;\n\n/**\n * Check if a URL is external (different origin).\n */\nfunction isExternalUrl(href: string): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n try {\n const url = new URL(href, window.location.origin);\n return url.origin !== window.location.origin;\n } catch {\n return false;\n }\n}\n\n// Store routes globally for prefetching (set by AppRouter)\n// Preserve across HMR in dev mode\nlet globalRoutes: RouteEntry[];\n\nif (typeof window !== \"undefined\" && import.meta.env?.DEV) {\n const globalWindow = window as typeof window & { __heliumGlobalRoutes?: RouteEntry[] };\n if (!globalWindow.__heliumGlobalRoutes) {\n globalWindow.__heliumGlobalRoutes = [];\n }\n globalRoutes = globalWindow.__heliumGlobalRoutes;\n} else {\n globalRoutes = [];\n}\n\n/**\n * Client-side navigation link.\n *\n * Intercepts left-clicks and uses the router's navigation helpers for SPA\n * navigation. Keeps normal anchor behaviour when modifier keys are used,\n * when the link is external, or when `target` / `download` attributes\n * are present.\n *\n * Automatically prefetches page chunks on hover for faster navigation.\n */\nexport function Link(props: LinkProps) {\n const {\n children,\n href,\n className,\n prefetch: prefetchProp = true,\n scrollToTop = true,\n replace: replaceProp,\n target,\n download,\n onClick: userOnClick,\n onMouseEnter: userOnMouseEnter,\n onFocus: userOnFocus,\n ...restProps\n } = props;\n\n const onClick = (e: React.MouseEvent<HTMLAnchorElement>) => {\n // Let user's onClick run first so they can call e.preventDefault()\n userOnClick?.(e);\n\n if (\n e.defaultPrevented ||\n e.button !== 0 || // only left click\n e.metaKey ||\n e.ctrlKey ||\n e.shiftKey ||\n e.altKey ||\n target || // let browser handle target=\"_blank\" etc.\n download != null || // let browser handle downloads\n isExternalUrl(href) // let browser handle external links\n ) {\n return;\n }\n e.preventDefault();\n navigate(href, { replace: replaceProp, scrollToTop });\n };\n\n const onMouseEnter = async (e: React.MouseEvent<HTMLAnchorElement>) => {\n // Prefetch the route on hover if enabled and not external (lazy-load prefetch logic)\n if (prefetchProp && !isExternalUrl(href) && globalRoutes.length > 0) {\n const { prefetchRoute } = await import(\"./prefetch.js\");\n prefetchRoute(href, globalRoutes);\n }\n userOnMouseEnter?.(e);\n };\n\n const onFocus = async (e: React.FocusEvent<HTMLAnchorElement>) => {\n // Also prefetch on focus (keyboard navigation)\n if (prefetchProp && !isExternalUrl(href) && globalRoutes.length > 0) {\n const { prefetchRoute } = await import(\"./prefetch.js\");\n prefetchRoute(href, globalRoutes);\n }\n userOnFocus?.(e);\n };\n\n return (\n <a {...restProps} href={href} target={target} download={download} onClick={onClick} onMouseEnter={onMouseEnter} onFocus={onFocus} className={className}>\n {children}\n </a>\n );\n}\n\n// AppShell props type\n/**\n * Props passed to an optional \\`AppShell\\` wrapper component used by <AppRouter />.\n *\n * \\`Component\\` — the page component to render. \\`pageProps\\` — props provided to the page.\n */\nexport type AppShellProps<TPageProps extends Record<string, unknown> = Record<string, unknown>> = {\n Component: ComponentType<TPageProps>;\n pageProps: TPageProps;\n};\n\n// Main router component\nexport function AppRouter({ AppShell }: { AppShell?: ComponentType<AppShellProps> }) {\n // useTransition for concurrent rendering - allows React to keep UI responsive during navigation\n const [isPending, startTransition] = useTransition();\n\n // Build routes once on mount (client-side only)\n const { routes, NotFound } = useMemo(() => {\n if (typeof window === \"undefined\") {\n return { routes: [], NotFound: undefined };\n }\n const result = buildRoutes();\n // Store routes globally for Link prefetching\n // In dev mode, also update the global reference to survive HMR\n if (import.meta.env?.DEV) {\n const globalWindow = window as typeof window & { __heliumGlobalRoutes?: RouteEntry[] };\n globalWindow.__heliumGlobalRoutes = result.routes;\n // Update the module-level reference as well\n globalRoutes.length = 0;\n globalRoutes.push(...result.routes);\n } else {\n globalRoutes = result.routes;\n }\n return result;\n }, []);\n\n // Use useSyncExternalStore to subscribe to location changes\n // This ensures synchronous updates when location changes\n const state = useSyncExternalStore(subscribeToLocation, getLocationSnapshot, getServerSnapshot);\n\n const match = useMemo(() => matchRoute(state.path, routes), [state.path, routes]);\n\n // Use matched params, or fall back to re-extracting from path using global routes during HMR\n const currentParams = match?.params ?? (import.meta.env?.DEV ? extractParamsFromPath(state.path) : {});\n\n // In dev mode, always read fresh searchParams from URL to handle HMR edge cases\n const currentSearchParams = import.meta.env?.DEV ? new URLSearchParams(window.location.search) : state.searchParams;\n\n const routerValue: RouterContext = {\n path: state.path,\n params: currentParams,\n searchParams: currentSearchParams,\n push: (href, options) => {\n // Wrap navigation in startTransition for smoother updates\n startTransition(() => {\n navigate(href, { scrollToTop: options?.scrollToTop });\n });\n },\n replace: (href, options) => {\n startTransition(() => {\n navigate(href, { replace: true, scrollToTop: options?.scrollToTop });\n });\n },\n on: (event, listener) => routerEventEmitter.on(event, listener),\n status: match ? 200 : 404,\n isNavigating: state.isNavigating,\n isPending,\n };\n\n if (!match) {\n const NotFoundComp = NotFound ?? (() => <div>Not found</div>);\n const content = <NotFoundComp />;\n\n return <RouterContext.Provider value={routerValue}>{AppShell ? <AppShell Component={NotFoundComp} pageProps={{}} /> : content}</RouterContext.Provider>;\n }\n\n const Page = match.route.Component as ComponentType<{ params: Record<string, string | string[]>; searchParams: URLSearchParams }>;\n const pageProps = {\n params: match.params,\n searchParams: currentSearchParams,\n };\n\n // Create a wrapped component that includes all layouts\n const WrappedPage = () => {\n let content = <Page {...pageProps} />;\n // Wrap page with layouts (from outer to inner)\n for (let i = match.route.layouts.length - 1; i >= 0; i--) {\n const Layout = match.route.layouts[i];\n content = <Layout>{content}</Layout>;\n }\n return content;\n };\n\n const finalContent = AppShell ? <AppShell Component={WrappedPage} pageProps={{}} /> : <WrappedPage />;\n\n return <RouterContext.Provider value={routerValue}>{finalContent}</RouterContext.Provider>;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"devServer.d.ts","sourceRoot":"","sources":["../../src/server/devServer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAQ/C,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;AAC9E,KAAK,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,iBAAiB,CAAC;AAE3F,UAAU,WAAW;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;CAC3B;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,GAAE,YAAiB,EAAE,OAAO,GAAE,WAAW,EAAO,QAgU7I"}
1
+ {"version":3,"file":"devServer.d.ts","sourceRoot":"","sources":["../../src/server/devServer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAQ/C,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;AAC9E,KAAK,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,iBAAiB,CAAC;AAE3F,UAAU,WAAW;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;CAC3B;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,GAAE,YAAiB,EAAE,OAAO,GAAE,WAAW,EAAO,QAgV7I"}
@@ -132,6 +132,13 @@ export function attachToDevServer(httpServer, loadHandlers, config = {}, workers
132
132
  socket.close(1008, "Too many connections from your IP");
133
133
  return;
134
134
  }
135
+ // Prevent unhandled errors from crashing the process (e.g. maxPayload exceeded)
136
+ socket.on("error", (err) => {
137
+ log("warn", "WebSocket error:", err);
138
+ if (socket.readyState === socket.OPEN || socket.readyState === socket.CLOSING) {
139
+ socket.close(1009, "Message too large");
140
+ }
141
+ });
135
142
  socket.on("message", (msg, _isBinary) => {
136
143
  // Check rate limit
137
144
  if (rateLimiter && !rateLimiter.checkRateLimit(socket)) {
@@ -180,7 +187,12 @@ export function attachToDevServer(httpServer, loadHandlers, config = {}, workers
180
187
  if (req.url?.startsWith("/rpc")) {
181
188
  // Security: read token from Sec-WebSocket-Protocol header instead of query string
182
189
  const protocols = req.headers["sec-websocket-protocol"];
183
- const token = typeof protocols === "string" ? protocols.split(",").map((p) => p.trim()).find((p) => p.includes(".")) : undefined;
190
+ const token = typeof protocols === "string"
191
+ ? protocols
192
+ .split(",")
193
+ .map((p) => p.trim())
194
+ .find((p) => p.includes("."))
195
+ : undefined;
184
196
  if (!token || !verifyConnectionToken(token)) {
185
197
  log("warn", "WebSocket connection rejected - invalid token");
186
198
  socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
@@ -263,8 +275,9 @@ export function attachToDevServer(httpServer, loadHandlers, config = {}, workers
263
275
  chunks.push(chunk);
264
276
  });
265
277
  req.on("end", async () => {
266
- if (aborted)
278
+ if (aborted) {
267
279
  return;
280
+ }
268
281
  try {
269
282
  if (!currentRegistry) {
270
283
  res.writeHead(503, { "Content-Type": "application/json" });
@@ -1 +1 @@
1
- {"version":3,"file":"devServer.js","sourceRoot":"","sources":["../../src/server/devServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { encode as msgpackEncode } from \"@msgpack/msgpack\";\nimport type http from \"http\";\nimport type http2 from \"http2\";\nimport type https from \"https\";\nimport { promisify } from \"util\";\nimport type WebSocket from \"ws\";\nimport { WebSocketServer } from \"ws\";\nimport { brotliCompress, deflate, gzip } from \"zlib\";\n\nimport { injectEnvToProcess, loadEnvFiles } from \"../utils/envLoader.js\";\nimport { extractClientIP } from \"../utils/ipExtractor.js\";\nimport { log } from \"../utils/logger.js\";\nimport type { HeliumConfig } from \"./config.js\";\nimport { getRpcConfig, getRpcSecurityConfig, getTrustProxyDepth } from \"./config.js\";\nimport type { HeliumContext } from \"./context.js\";\nimport type { HeliumWorkerDef } from \"./defineWorker.js\";\nimport { startWorker, stopAllWorkers } from \"./defineWorker.js\";\nimport { HTTPRouter } from \"./httpRouter.js\";\nimport { RateLimiter } from \"./rateLimiter.js\";\nimport { RpcRegistry } from \"./rpcRegistry.js\";\nimport { initializeSecurity, verifyConnectionToken } from \"./security.js\";\nimport { prepareForMsgpack } from \"./serializer.js\";\n\nconst gzipAsync = promisify(gzip);\nconst deflateAsync = promisify(deflate);\nconst brotliCompressAsync = promisify(brotliCompress);\n\ntype LoadHandlersFn = (registry: RpcRegistry, httpRouter: HTTPRouter) => void;\ntype HttpServer = http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer;\n\ninterface WorkerEntry {\n name: string;\n worker: HeliumWorkerDef;\n}\n\nlet currentRegistry: RpcRegistry | null = null;\nlet currentHttpRouter: HTTPRouter | null = null;\nlet wss: WebSocketServer | null = null;\nlet rateLimiter: RateLimiter | null = null;\nlet currentWorkers: WorkerEntry[] = [];\n\n/**\n * Attaches HeliumTS HTTP handlers and WebSocket RPC server to an existing HTTP server.\n * This is used in dev mode to attach to Vite's dev server.\n */\nexport function attachToDevServer(httpServer: HttpServer, loadHandlers: LoadHandlersFn, config: HeliumConfig = {}, workers: WorkerEntry[] = []) {\n // Load environment variables for server-side access\n const envVars = loadEnvFiles();\n injectEnvToProcess(envVars);\n\n // Load configuration\n const trustProxyDepth = getTrustProxyDepth(config);\n const rpcSecurity = getRpcSecurityConfig(config);\n const rpcConfig = getRpcConfig(config);\n const compressionConfig = rpcConfig.compression;\n initializeSecurity(rpcSecurity);\n\n // Re-initialize rate limiter with new config (always recreate in dev mode to pick up config changes)\n rateLimiter = new RateLimiter(rpcSecurity.maxMessagesPerWindow, rpcSecurity.rateLimitWindowMs, rpcSecurity.maxConnectionsPerIP);\n\n const registry = new RpcRegistry();\n const httpRouter = new HTTPRouter();\n httpRouter.setTrustProxyDepth(trustProxyDepth);\n loadHandlers(registry, httpRouter);\n registry.setRateLimiter(rateLimiter);\n registry.setMaxBatchSize(rpcConfig.maxBatchSize);\n currentRegistry = registry;\n currentHttpRouter = httpRouter;\n\n // Start workers if they changed\n const workersChanged = workers.length !== currentWorkers.length || workers.some((w, i) => w.name !== currentWorkers[i]?.name || w.worker !== currentWorkers[i]?.worker);\n\n if (workersChanged && workers.length > 0) {\n // Stop all existing workers before starting new ones\n stopAllWorkers().then(() => {\n // Start new workers\n for (const { name, worker } of workers) {\n // Use export name if worker name is anonymous\n if (worker.name === \"anonymous\") {\n worker.name = name;\n worker.__id = name;\n worker.options.name = name;\n }\n if (worker.options.autoStart) {\n const createContext = (): HeliumContext => ({\n req: {\n ip: \"127.0.0.1\",\n headers: {},\n url: undefined,\n method: undefined,\n raw: {} as http.IncomingMessage,\n },\n });\n startWorker(worker, createContext).catch((err) => {\n log(\"error\", `Failed to start worker '${worker.name}':`, err);\n });\n }\n }\n currentWorkers = workers;\n });\n } else if (currentWorkers.length === 0 && workers.length > 0) {\n // First time starting workers\n for (const { name, worker } of workers) {\n // Use export name if worker name is anonymous\n if (worker.name === \"anonymous\") {\n worker.name = name;\n worker.__id = name;\n worker.options.name = name;\n }\n if (worker.options.autoStart) {\n const createContext = (): HeliumContext => ({\n req: {\n ip: \"127.0.0.1\",\n headers: {},\n url: undefined,\n method: undefined,\n raw: {} as http.IncomingMessage,\n },\n });\n startWorker(worker, createContext).catch((err) => {\n log(\"error\", `Failed to start worker '${worker.name}':`, err);\n });\n }\n }\n currentWorkers = workers;\n }\n\n // Attach WebSocket server if not already attached\n if (!wss) {\n wss = new WebSocketServer({\n noServer: true,\n maxPayload: rpcConfig.maxWsPayload,\n perMessageDeflate: compressionConfig.enabled\n ? {\n zlibDeflateOptions: {\n chunkSize: 1024,\n memLevel: 7,\n level: 9, // 6 is default compression level (balanced)\n },\n zlibInflateOptions: {\n chunkSize: 10 * 1024,\n },\n threshold: compressionConfig.threshold,\n }\n : false,\n });\n\n wss.on(\"connection\", (socket: WebSocket, req: http.IncomingMessage) => {\n // Extract client IP with proxy configuration\n const ip = extractClientIP(req, trustProxyDepth);\n\n // Store connection metadata for RPC context\n if (currentRegistry) {\n currentRegistry.setSocketMetadata(socket, ip, req);\n }\n\n // Track connection and check IP limit\n if (rateLimiter && !rateLimiter.trackConnection(socket, ip)) {\n socket.close(1008, \"Too many connections from your IP\");\n return;\n }\n\n socket.on(\"message\", (msg: WebSocket.RawData, _isBinary: boolean) => {\n // Check rate limit\n if (rateLimiter && !rateLimiter.checkRateLimit(socket)) {\n // Parse request to get the ID for proper error response\n try {\n let req: any;\n // Always expect MessagePack\n const buffer = Buffer.isBuffer(msg) ? msg : Buffer.from(msg as any);\n const { decode: msgpackDecode } = require(\"@msgpack/msgpack\");\n req = msgpackDecode(buffer);\n\n const stats = rateLimiter.getConnectionStats(socket);\n const now = Date.now();\n const resetInSeconds = stats ? Math.ceil((stats.resetTimeMs - now) / 1000) : 0;\n\n const createError = (id: string) => ({\n id,\n ok: false,\n stats: {\n remainingRequests: stats ? stats.remainingMessages : 0,\n resetInSeconds,\n },\n error: \"Rate limit exceeded\",\n });\n\n let errorResponse: any;\n if (Array.isArray(req)) {\n errorResponse = req.map((r: any) => createError(r.id));\n } else {\n errorResponse = createError(req.id);\n }\n\n socket.send(msgpackEncode(errorResponse) as Buffer);\n } catch {\n // If we can't parse the request, just close the connection\n socket.close();\n }\n return;\n }\n\n // Always use the current registry (may have been updated)\n if (currentRegistry) {\n currentRegistry.handleMessage(socket, Buffer.isBuffer(msg) ? msg : Buffer.from(msg as any));\n }\n });\n });\n\n // Handle WebSocket upgrade requests\n httpServer.on(\"upgrade\", (req, socket, head) => {\n if (req.url?.startsWith(\"/rpc\")) {\n // Security: read token from Sec-WebSocket-Protocol header instead of query string\n const protocols = req.headers[\"sec-websocket-protocol\"];\n const token = typeof protocols === \"string\" ? protocols.split(\",\").map((p) => p.trim()).find((p) => p.includes(\".\")) : undefined;\n\n if (!token || !verifyConnectionToken(token)) {\n log(\"warn\", \"WebSocket connection rejected - invalid token\");\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n // Check IP connection limit before upgrading\n const ip = extractClientIP(req, trustProxyDepth);\n if (rateLimiter && rpcSecurity.maxConnectionsPerIP > 0) {\n const currentConnections = rateLimiter.getIPConnectionCount(ip);\n if (currentConnections >= rpcSecurity.maxConnectionsPerIP) {\n log(\"warn\", `WebSocket connection rejected - IP ${ip} has ${currentConnections} connections`);\n socket.write(\"HTTP/1.1 429 Too Many Requests\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n }\n\n wss!.handleUpgrade(req, socket, head, (ws) => {\n wss!.emit(\"connection\", ws, req);\n });\n }\n });\n\n log(\"info\", \"WebSocket RPC attached to dev server at /rpc\");\n }\n\n // Security: max body size for HTTP requests\n const maxBodySize = rpcConfig.maxBodySize ?? 1_048_576;\n\n // Attach HTTP request handler\n // We need to intercept requests before Vite handles them\n const originalListeners = httpServer.listeners(\"request\").slice();\n httpServer.removeAllListeners(\"request\");\n\n httpServer.on(\"request\", async (req: any, res: any) => {\n // Handle token refresh endpoint\n if (req.url === \"/__helium__/refresh-token\") {\n // Security: only allow POST to prevent CSRF via <img>/<script> tags\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Method not allowed\" }));\n return;\n }\n // Security: require custom header to prevent cross-origin requests\n if (!req.headers[\"x-requested-with\"]) {\n res.writeHead(403, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Forbidden\" }));\n return;\n }\n const { generateConnectionToken } = await import(\"./security.js\");\n const token = generateConnectionToken();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ token }));\n return;\n }\n\n // Handle HTTP-based RPC endpoint (alternative to WebSocket for mobile networks)\n if (req.url === \"/__helium__/rpc\" && req.method === \"POST\") {\n // Security: verify connection token for HTTP RPC\n const authToken = req.headers[\"x-helium-token\"] as string | undefined;\n if (!authToken || !verifyConnectionToken(authToken)) {\n res.writeHead(401, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Unauthorized\" }));\n return;\n }\n\n // Security: check Content-Length before reading body\n const contentLength = parseInt(req.headers[\"content-length\"] || \"0\", 10);\n if (contentLength > maxBodySize) {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Request entity too large\" }));\n return;\n }\n\n const chunks: Buffer[] = [];\n let totalSize = 0;\n let aborted = false;\n req.on(\"data\", (chunk: Buffer) => {\n totalSize += chunk.length;\n if (totalSize > maxBodySize) {\n aborted = true;\n req.destroy();\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Request entity too large\" }));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", async () => {\n if (aborted) return;\n try {\n if (!currentRegistry) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Server not ready\" }));\n return;\n }\n\n const body = Buffer.concat(chunks);\n const ip = extractClientIP(req, trustProxyDepth);\n const result = await currentRegistry.handleHttpRequest(body, ip, req);\n\n const encoded = msgpackEncode(prepareForMsgpack(result.response));\n let responseBody = Buffer.from(encoded as Uint8Array);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/msgpack\",\n \"Cache-Control\": \"no-store\",\n };\n\n // Handle compression\n const acceptEncoding = req.headers[\"accept-encoding\"] as string;\n if (acceptEncoding && responseBody.length > 1024) {\n if (acceptEncoding.includes(\"br\")) {\n responseBody = await brotliCompressAsync(responseBody);\n headers[\"Content-Encoding\"] = \"br\";\n } else if (acceptEncoding.includes(\"gzip\")) {\n responseBody = await gzipAsync(responseBody);\n headers[\"Content-Encoding\"] = \"gzip\";\n } else if (acceptEncoding.includes(\"deflate\")) {\n responseBody = await deflateAsync(responseBody);\n headers[\"Content-Encoding\"] = \"deflate\";\n }\n }\n\n res.writeHead(200, headers);\n res.end(responseBody);\n } catch (error) {\n log(\"error\", \"HTTP RPC error:\", error);\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Internal server error\" }));\n }\n });\n return;\n }\n\n // Try HTTP handlers first\n if (currentHttpRouter) {\n const handled = await currentHttpRouter.handleRequest(req, res);\n if (handled) {\n return;\n }\n }\n\n // If no handler matched, pass to original Vite handlers\n for (const listener of originalListeners) {\n (listener as any)(req, res);\n }\n });\n}\n"]}
1
+ {"version":3,"file":"devServer.js","sourceRoot":"","sources":["../../src/server/devServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { encode as msgpackEncode } from \"@msgpack/msgpack\";\nimport type http from \"http\";\nimport type http2 from \"http2\";\nimport type https from \"https\";\nimport { promisify } from \"util\";\nimport type WebSocket from \"ws\";\nimport { WebSocketServer } from \"ws\";\nimport { brotliCompress, deflate, gzip } from \"zlib\";\n\nimport { injectEnvToProcess, loadEnvFiles } from \"../utils/envLoader.js\";\nimport { extractClientIP } from \"../utils/ipExtractor.js\";\nimport { log } from \"../utils/logger.js\";\nimport type { HeliumConfig } from \"./config.js\";\nimport { getRpcConfig, getRpcSecurityConfig, getTrustProxyDepth } from \"./config.js\";\nimport type { HeliumContext } from \"./context.js\";\nimport type { HeliumWorkerDef } from \"./defineWorker.js\";\nimport { startWorker, stopAllWorkers } from \"./defineWorker.js\";\nimport { HTTPRouter } from \"./httpRouter.js\";\nimport { RateLimiter } from \"./rateLimiter.js\";\nimport { RpcRegistry } from \"./rpcRegistry.js\";\nimport { initializeSecurity, verifyConnectionToken } from \"./security.js\";\nimport { prepareForMsgpack } from \"./serializer.js\";\n\nconst gzipAsync = promisify(gzip);\nconst deflateAsync = promisify(deflate);\nconst brotliCompressAsync = promisify(brotliCompress);\n\ntype LoadHandlersFn = (registry: RpcRegistry, httpRouter: HTTPRouter) => void;\ntype HttpServer = http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer;\n\ninterface WorkerEntry {\n name: string;\n worker: HeliumWorkerDef;\n}\n\nlet currentRegistry: RpcRegistry | null = null;\nlet currentHttpRouter: HTTPRouter | null = null;\nlet wss: WebSocketServer | null = null;\nlet rateLimiter: RateLimiter | null = null;\nlet currentWorkers: WorkerEntry[] = [];\n\n/**\n * Attaches HeliumTS HTTP handlers and WebSocket RPC server to an existing HTTP server.\n * This is used in dev mode to attach to Vite's dev server.\n */\nexport function attachToDevServer(httpServer: HttpServer, loadHandlers: LoadHandlersFn, config: HeliumConfig = {}, workers: WorkerEntry[] = []) {\n // Load environment variables for server-side access\n const envVars = loadEnvFiles();\n injectEnvToProcess(envVars);\n\n // Load configuration\n const trustProxyDepth = getTrustProxyDepth(config);\n const rpcSecurity = getRpcSecurityConfig(config);\n const rpcConfig = getRpcConfig(config);\n const compressionConfig = rpcConfig.compression;\n initializeSecurity(rpcSecurity);\n\n // Re-initialize rate limiter with new config (always recreate in dev mode to pick up config changes)\n rateLimiter = new RateLimiter(rpcSecurity.maxMessagesPerWindow, rpcSecurity.rateLimitWindowMs, rpcSecurity.maxConnectionsPerIP);\n\n const registry = new RpcRegistry();\n const httpRouter = new HTTPRouter();\n httpRouter.setTrustProxyDepth(trustProxyDepth);\n loadHandlers(registry, httpRouter);\n registry.setRateLimiter(rateLimiter);\n registry.setMaxBatchSize(rpcConfig.maxBatchSize);\n currentRegistry = registry;\n currentHttpRouter = httpRouter;\n\n // Start workers if they changed\n const workersChanged = workers.length !== currentWorkers.length || workers.some((w, i) => w.name !== currentWorkers[i]?.name || w.worker !== currentWorkers[i]?.worker);\n\n if (workersChanged && workers.length > 0) {\n // Stop all existing workers before starting new ones\n stopAllWorkers().then(() => {\n // Start new workers\n for (const { name, worker } of workers) {\n // Use export name if worker name is anonymous\n if (worker.name === \"anonymous\") {\n worker.name = name;\n worker.__id = name;\n worker.options.name = name;\n }\n if (worker.options.autoStart) {\n const createContext = (): HeliumContext => ({\n req: {\n ip: \"127.0.0.1\",\n headers: {},\n url: undefined,\n method: undefined,\n raw: {} as http.IncomingMessage,\n },\n });\n startWorker(worker, createContext).catch((err) => {\n log(\"error\", `Failed to start worker '${worker.name}':`, err);\n });\n }\n }\n currentWorkers = workers;\n });\n } else if (currentWorkers.length === 0 && workers.length > 0) {\n // First time starting workers\n for (const { name, worker } of workers) {\n // Use export name if worker name is anonymous\n if (worker.name === \"anonymous\") {\n worker.name = name;\n worker.__id = name;\n worker.options.name = name;\n }\n if (worker.options.autoStart) {\n const createContext = (): HeliumContext => ({\n req: {\n ip: \"127.0.0.1\",\n headers: {},\n url: undefined,\n method: undefined,\n raw: {} as http.IncomingMessage,\n },\n });\n startWorker(worker, createContext).catch((err) => {\n log(\"error\", `Failed to start worker '${worker.name}':`, err);\n });\n }\n }\n currentWorkers = workers;\n }\n\n // Attach WebSocket server if not already attached\n if (!wss) {\n wss = new WebSocketServer({\n noServer: true,\n maxPayload: rpcConfig.maxWsPayload,\n perMessageDeflate: compressionConfig.enabled\n ? {\n zlibDeflateOptions: {\n chunkSize: 1024,\n memLevel: 7,\n level: 9, // 6 is default compression level (balanced)\n },\n zlibInflateOptions: {\n chunkSize: 10 * 1024,\n },\n threshold: compressionConfig.threshold,\n }\n : false,\n });\n\n wss.on(\"connection\", (socket: WebSocket, req: http.IncomingMessage) => {\n // Extract client IP with proxy configuration\n const ip = extractClientIP(req, trustProxyDepth);\n\n // Store connection metadata for RPC context\n if (currentRegistry) {\n currentRegistry.setSocketMetadata(socket, ip, req);\n }\n\n // Track connection and check IP limit\n if (rateLimiter && !rateLimiter.trackConnection(socket, ip)) {\n socket.close(1008, \"Too many connections from your IP\");\n return;\n }\n\n // Prevent unhandled errors from crashing the process (e.g. maxPayload exceeded)\n socket.on(\"error\", (err) => {\n log(\"warn\", \"WebSocket error:\", err);\n if (socket.readyState === socket.OPEN || socket.readyState === socket.CLOSING) {\n socket.close(1009, \"Message too large\");\n }\n });\n\n socket.on(\"message\", (msg: WebSocket.RawData, _isBinary: boolean) => {\n // Check rate limit\n if (rateLimiter && !rateLimiter.checkRateLimit(socket)) {\n // Parse request to get the ID for proper error response\n try {\n let req: any;\n // Always expect MessagePack\n const buffer = Buffer.isBuffer(msg) ? msg : Buffer.from(msg as any);\n const { decode: msgpackDecode } = require(\"@msgpack/msgpack\");\n req = msgpackDecode(buffer);\n\n const stats = rateLimiter.getConnectionStats(socket);\n const now = Date.now();\n const resetInSeconds = stats ? Math.ceil((stats.resetTimeMs - now) / 1000) : 0;\n\n const createError = (id: string) => ({\n id,\n ok: false,\n stats: {\n remainingRequests: stats ? stats.remainingMessages : 0,\n resetInSeconds,\n },\n error: \"Rate limit exceeded\",\n });\n\n let errorResponse: any;\n if (Array.isArray(req)) {\n errorResponse = req.map((r: any) => createError(r.id));\n } else {\n errorResponse = createError(req.id);\n }\n\n socket.send(msgpackEncode(errorResponse) as Buffer);\n } catch {\n // If we can't parse the request, just close the connection\n socket.close();\n }\n return;\n }\n\n // Always use the current registry (may have been updated)\n if (currentRegistry) {\n currentRegistry.handleMessage(socket, Buffer.isBuffer(msg) ? msg : Buffer.from(msg as any));\n }\n });\n });\n\n // Handle WebSocket upgrade requests\n httpServer.on(\"upgrade\", (req, socket, head) => {\n if (req.url?.startsWith(\"/rpc\")) {\n // Security: read token from Sec-WebSocket-Protocol header instead of query string\n const protocols = req.headers[\"sec-websocket-protocol\"];\n const token =\n typeof protocols === \"string\"\n ? protocols\n .split(\",\")\n .map((p) => p.trim())\n .find((p) => p.includes(\".\"))\n : undefined;\n\n if (!token || !verifyConnectionToken(token)) {\n log(\"warn\", \"WebSocket connection rejected - invalid token\");\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n // Check IP connection limit before upgrading\n const ip = extractClientIP(req, trustProxyDepth);\n if (rateLimiter && rpcSecurity.maxConnectionsPerIP > 0) {\n const currentConnections = rateLimiter.getIPConnectionCount(ip);\n if (currentConnections >= rpcSecurity.maxConnectionsPerIP) {\n log(\"warn\", `WebSocket connection rejected - IP ${ip} has ${currentConnections} connections`);\n socket.write(\"HTTP/1.1 429 Too Many Requests\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n }\n\n wss!.handleUpgrade(req, socket, head, (ws) => {\n wss!.emit(\"connection\", ws, req);\n });\n }\n });\n\n log(\"info\", \"WebSocket RPC attached to dev server at /rpc\");\n }\n\n // Security: max body size for HTTP requests\n const maxBodySize = rpcConfig.maxBodySize ?? 1_048_576;\n\n // Attach HTTP request handler\n // We need to intercept requests before Vite handles them\n const originalListeners = httpServer.listeners(\"request\").slice();\n httpServer.removeAllListeners(\"request\");\n\n httpServer.on(\"request\", async (req: any, res: any) => {\n // Handle token refresh endpoint\n if (req.url === \"/__helium__/refresh-token\") {\n // Security: only allow POST to prevent CSRF via <img>/<script> tags\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Method not allowed\" }));\n return;\n }\n // Security: require custom header to prevent cross-origin requests\n if (!req.headers[\"x-requested-with\"]) {\n res.writeHead(403, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Forbidden\" }));\n return;\n }\n const { generateConnectionToken } = await import(\"./security.js\");\n const token = generateConnectionToken();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ token }));\n return;\n }\n\n // Handle HTTP-based RPC endpoint (alternative to WebSocket for mobile networks)\n if (req.url === \"/__helium__/rpc\" && req.method === \"POST\") {\n // Security: verify connection token for HTTP RPC\n const authToken = req.headers[\"x-helium-token\"] as string | undefined;\n if (!authToken || !verifyConnectionToken(authToken)) {\n res.writeHead(401, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Unauthorized\" }));\n return;\n }\n\n // Security: check Content-Length before reading body\n const contentLength = parseInt(req.headers[\"content-length\"] || \"0\", 10);\n if (contentLength > maxBodySize) {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Request entity too large\" }));\n return;\n }\n\n const chunks: Buffer[] = [];\n let totalSize = 0;\n let aborted = false;\n req.on(\"data\", (chunk: Buffer) => {\n totalSize += chunk.length;\n if (totalSize > maxBodySize) {\n aborted = true;\n req.destroy();\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Request entity too large\" }));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", async () => {\n if (aborted) {\n return;\n }\n try {\n if (!currentRegistry) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Server not ready\" }));\n return;\n }\n\n const body = Buffer.concat(chunks);\n const ip = extractClientIP(req, trustProxyDepth);\n const result = await currentRegistry.handleHttpRequest(body, ip, req);\n\n const encoded = msgpackEncode(prepareForMsgpack(result.response));\n let responseBody = Buffer.from(encoded as Uint8Array);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/msgpack\",\n \"Cache-Control\": \"no-store\",\n };\n\n // Handle compression\n const acceptEncoding = req.headers[\"accept-encoding\"] as string;\n if (acceptEncoding && responseBody.length > 1024) {\n if (acceptEncoding.includes(\"br\")) {\n responseBody = await brotliCompressAsync(responseBody);\n headers[\"Content-Encoding\"] = \"br\";\n } else if (acceptEncoding.includes(\"gzip\")) {\n responseBody = await gzipAsync(responseBody);\n headers[\"Content-Encoding\"] = \"gzip\";\n } else if (acceptEncoding.includes(\"deflate\")) {\n responseBody = await deflateAsync(responseBody);\n headers[\"Content-Encoding\"] = \"deflate\";\n }\n }\n\n res.writeHead(200, headers);\n res.end(responseBody);\n } catch (error) {\n log(\"error\", \"HTTP RPC error:\", error);\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Internal server error\" }));\n }\n });\n return;\n }\n\n // Try HTTP handlers first\n if (currentHttpRouter) {\n const handled = await currentHttpRouter.handleRequest(req, res);\n if (handled) {\n return;\n }\n }\n\n // If no handler matched, pass to original Vite handlers\n for (const listener of originalListeners) {\n (listener as any)(req, res);\n }\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"prodServer.d.ts","sourceRoot":"","sources":["../../src/server/prodServer.ts"],"names":[],"mappings":"AAEA,OAAO,IAAI,MAAM,MAAM,CAAC;AASxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAQ/C,UAAU,WAAW;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;CAC3B;AAED,UAAU,iBAAiB;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1E,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,wEAgZzD"}
1
+ {"version":3,"file":"prodServer.d.ts","sourceRoot":"","sources":["../../src/server/prodServer.ts"],"names":[],"mappings":"AAEA,OAAO,IAAI,MAAM,MAAM,CAAC;AASxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAQ/C,UAAU,WAAW;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;CAC3B;AAED,UAAU,iBAAiB;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1E,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,wEAgazD"}
@@ -113,8 +113,9 @@ export function startProdServer(options) {
113
113
  chunks.push(chunk);
114
114
  });
115
115
  req.on("end", async () => {
116
- if (aborted)
116
+ if (aborted) {
117
117
  return;
118
+ }
118
119
  try {
119
120
  const body = Buffer.concat(chunks);
120
121
  const ip = extractClientIP(req, trustProxyDepth);
@@ -284,6 +285,13 @@ export function startProdServer(options) {
284
285
  socket.close(1008, "Too many connections from your IP");
285
286
  return;
286
287
  }
288
+ // Prevent unhandled errors from crashing the process (e.g. maxPayload exceeded)
289
+ socket.on("error", (err) => {
290
+ log("warn", "WebSocket error:", err);
291
+ if (socket.readyState === socket.OPEN || socket.readyState === socket.CLOSING) {
292
+ socket.close(1009, "Message too large");
293
+ }
294
+ });
287
295
  socket.on("message", (msg, _isBinary) => {
288
296
  // Check rate limit
289
297
  if (!rateLimiter.checkRateLimit(socket)) {
@@ -330,7 +338,12 @@ export function startProdServer(options) {
330
338
  if (req.url?.startsWith("/rpc")) {
331
339
  // Security: read token from Sec-WebSocket-Protocol header instead of query string
332
340
  const protocols = req.headers["sec-websocket-protocol"];
333
- const token = typeof protocols === "string" ? protocols.split(",").map((p) => p.trim()).find((p) => p.includes(".")) : undefined;
341
+ const token = typeof protocols === "string"
342
+ ? protocols
343
+ .split(",")
344
+ .map((p) => p.trim())
345
+ .find((p) => p.includes("."))
346
+ : undefined;
334
347
  if (!token || !verifyConnectionToken(token)) {
335
348
  log("warn", "WebSocket connection rejected - invalid token");
336
349
  socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
@@ -1 +1 @@
1
- {"version":3,"file":"prodServer.js","sourceRoot":"","sources":["../../src/server/prodServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { encode as msgpackEncode } from \"@msgpack/msgpack\";\nimport fs from \"fs\";\nimport http from \"http\";\nimport path from \"path\";\nimport { promisify } from \"util\";\nimport type WebSocket from \"ws\";\nimport { WebSocketServer } from \"ws\";\nimport { brotliCompress, deflate, gzip } from \"zlib\";\n\nimport { extractClientIP } from \"../utils/ipExtractor.js\";\nimport { log } from \"../utils/logger.js\";\nimport type { HeliumConfig } from \"./config.js\";\nimport { getRpcConfig, getRpcSecurityConfig, getTrustProxyDepth } from \"./config.js\";\nimport type { HeliumContext } from \"./context.js\";\nimport type { HeliumWorkerDef } from \"./defineWorker.js\";\nimport { startWorker, stopAllWorkers } from \"./defineWorker.js\";\nimport { HTTPRouter } from \"./httpRouter.js\";\nimport { RateLimiter } from \"./rateLimiter.js\";\nimport { RpcRegistry } from \"./rpcRegistry.js\";\nimport { generateConnectionToken, initializeSecurity, verifyConnectionToken } from \"./security.js\";\nimport { prepareForMsgpack } from \"./serializer.js\";\n\nconst gzipAsync = promisify(gzip);\nconst deflateAsync = promisify(deflate);\nconst brotliCompressAsync = promisify(brotliCompress);\n\ninterface WorkerEntry {\n name: string;\n worker: HeliumWorkerDef;\n}\n\ninterface ProdServerOptions {\n port?: number;\n distDir?: string;\n staticDir?: string;\n registerHandlers: (registry: RpcRegistry, httpRouter: HTTPRouter) => void;\n config?: HeliumConfig;\n workers?: WorkerEntry[];\n}\n\n/**\n * Starts a production HTTP server that:\n * - Serves static files from the dist directory\n * - Supports SSG (Static Site Generation) by serving .html files for routes (e.g., /about -> about.html)\n * - Falls back to index.html for client-side routing (SPA)\n * - Handles custom HTTP endpoints (webhooks, auth, etc.)\n * - Hosts WebSocket RPC server\n * - Starts background workers\n *\n * SSG Behavior:\n * - Production correctly serves SSG pages (e.g., /about serves about.html with pre-rendered content)\n * - This ensures search engines and social media crawlers see the correct content\n * - Client-side navigation between pages still works via React Router\n */\nexport function startProdServer(options: ProdServerOptions) {\n const { port = Number(process.env.PORT || 3000), distDir = \"dist\", staticDir = path.resolve(process.cwd(), distDir), registerHandlers, config = {}, workers = [] } = options;\n\n // Load configuration\n const trustProxyDepth = getTrustProxyDepth(config);\n const rpcSecurity = getRpcSecurityConfig(config);\n const rpcConfig = getRpcConfig(config);\n const compressionConfig = rpcConfig.compression;\n initializeSecurity(rpcSecurity);\n\n // Initialize rate limiter\n const rateLimiter = new RateLimiter(rpcSecurity.maxMessagesPerWindow, rpcSecurity.rateLimitWindowMs, rpcSecurity.maxConnectionsPerIP);\n\n const registry = new RpcRegistry();\n const httpRouter = new HTTPRouter();\n httpRouter.setTrustProxyDepth(trustProxyDepth);\n registerHandlers(registry, httpRouter);\n registry.setRateLimiter(rateLimiter);\n registry.setMaxBatchSize(rpcConfig.maxBatchSize);\n\n // Security: max body size for HTTP requests (1 MB default)\n const maxBodySize = rpcConfig.maxBodySize ?? 1_048_576;\n // Security: max batch size for RPC requests\n const maxBatchSize = rpcConfig.maxBatchSize ?? 20;\n\n // Create HTTP server\n const server = http.createServer(async (req, res) => {\n // Apply security headers to all responses\n setSecurityHeaders(res, config);\n\n // Handle CORS preflight\n if (req.method === \"OPTIONS\") {\n handleCorsHeaders(req, res, config);\n res.writeHead(204);\n res.end();\n return;\n }\n handleCorsHeaders(req, res, config);\n\n // Handle token refresh endpoint\n if (req.url === \"/__helium__/refresh-token\") {\n // Security: only allow POST to prevent CSRF via <img>/<script> tags\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Method not allowed\" }));\n return;\n }\n // Security: require custom header to prevent cross-origin requests\n if (!req.headers[\"x-requested-with\"]) {\n res.writeHead(403, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Forbidden\" }));\n return;\n }\n const token = generateConnectionToken();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ token }));\n return;\n }\n\n // Handle HTTP-based RPC endpoint (alternative to WebSocket for mobile networks)\n if (req.url === \"/__helium__/rpc\" && req.method === \"POST\") {\n // Security: verify connection token for HTTP RPC\n const authToken = req.headers[\"x-helium-token\"] as string | undefined;\n if (!authToken || !verifyConnectionToken(authToken)) {\n res.writeHead(401, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Unauthorized\" }));\n return;\n }\n\n // Security: check Content-Length before reading body\n const contentLength = parseInt(req.headers[\"content-length\"] || \"0\", 10);\n if (contentLength > maxBodySize) {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Request entity too large\" }));\n return;\n }\n\n const chunks: Buffer[] = [];\n let totalSize = 0;\n let aborted = false;\n req.on(\"data\", (chunk: Buffer) => {\n totalSize += chunk.length;\n if (totalSize > maxBodySize) {\n aborted = true;\n req.destroy();\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Request entity too large\" }));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", async () => {\n if (aborted) return;\n try {\n const body = Buffer.concat(chunks);\n const ip = extractClientIP(req, trustProxyDepth);\n const result = await registry.handleHttpRequest(body, ip, req);\n\n const encoded = msgpackEncode(prepareForMsgpack(result.response));\n let responseBody = Buffer.from(encoded as Uint8Array);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/msgpack\",\n \"Cache-Control\": \"no-store\",\n };\n\n // Handle compression\n const acceptEncoding = req.headers[\"accept-encoding\"] as string;\n if (acceptEncoding && responseBody.length > 1024) {\n if (acceptEncoding.includes(\"br\")) {\n responseBody = await brotliCompressAsync(responseBody);\n headers[\"Content-Encoding\"] = \"br\";\n } else if (acceptEncoding.includes(\"gzip\")) {\n responseBody = await gzipAsync(responseBody);\n headers[\"Content-Encoding\"] = \"gzip\";\n } else if (acceptEncoding.includes(\"deflate\")) {\n responseBody = await deflateAsync(responseBody);\n headers[\"Content-Encoding\"] = \"deflate\";\n }\n }\n\n res.writeHead(200, headers);\n res.end(responseBody);\n } catch (error) {\n log(\"error\", \"HTTP RPC error:\", error);\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Internal server error\" }));\n }\n });\n return;\n }\n\n // Try HTTP handlers first (webhooks, auth, etc.)\n const handled = await httpRouter.handleRequest(req, res);\n if (handled) {\n return;\n }\n\n // Serve static files\n const url = req.url || \"/\";\n\n // Block access to sensitive configuration and server files\n const blockedFiles = [\"helium.config.js\", \"helium.config.mjs\", \"helium.config.ts\", \"server.js\", \".env\", \".env.local\", \".env.production\"];\n\n const requestedFile = path.basename(url.split(\"?\")[0]);\n let filePath: string = path.join(staticDir, \"index.html\");\n let is404 = false;\n\n if (blockedFiles.some((blocked) => requestedFile === blocked || requestedFile.startsWith(\".env\"))) {\n // Serve index.html so the SPA router can render the 404 page\n filePath = path.join(staticDir, \"index.html\");\n is404 = true;\n } else {\n // Clean URL (remove query params and trailing slash)\n const cleanUrl = url.split(\"?\")[0].replace(/\\/$/, \"\") || \"/\";\n\n // Security: path traversal prevention — resolve and verify\n const resolvedStaticDir = path.resolve(staticDir);\n const candidatePath = path.resolve(staticDir, \".\" + cleanUrl);\n if (!candidatePath.startsWith(resolvedStaticDir + path.sep) && candidatePath !== resolvedStaticDir) {\n filePath = path.join(staticDir, \"index.html\");\n is404 = true;\n }\n\n // Try different file paths for SSG support\n if (!is404 && cleanUrl === \"/\") {\n // Try index.ssg.html first (if root page has SSG)\n const ssgIndexPath = path.join(staticDir, \"index.ssg.html\");\n if (fs.existsSync(ssgIndexPath)) {\n filePath = ssgIndexPath;\n } else {\n filePath = path.join(staticDir, \"index.html\");\n }\n } else if (!is404) {\n // If cleanUrl has no extension, prioritize .html files for SSG pages\n if (!path.extname(cleanUrl)) {\n const htmlPath = path.join(staticDir, cleanUrl + \".html\");\n if (fs.existsSync(htmlPath)) {\n filePath = htmlPath;\n } else {\n // Fall back to exact path (for assets or directories)\n filePath = path.join(staticDir, cleanUrl);\n }\n } else {\n // Has an extension, try exact path (for assets like /assets/main.js)\n filePath = path.join(staticDir, cleanUrl);\n }\n }\n\n // If file doesn't exist or is a directory, fall back to index.html for SPA routing\n const isFileOrExists = !is404 && filePath && fs.existsSync(filePath) && fs.statSync(filePath).isFile();\n if (!isFileOrExists && !url.startsWith(\"/api\") && !url.startsWith(\"/webhooks\") && !url.startsWith(\"/auth\")) {\n // Fall back to index.html for SPA routing\n // Note: We don't set is404 here because the client-side router will determine\n // if the route exists. If it doesn't, the router will render the 404 page.\n filePath = path.join(staticDir, \"index.html\");\n // Don't set is404 = true here - let the client-side router handle it\n }\n }\n\n // Check if file exists (should always exist now since we fallback to index.html)\n if (!fs.existsSync(filePath)) {\n // This should rarely happen - only if index.html itself is missing\n res.writeHead(404, { \"Content-Type\": \"text/html\" });\n res.end(\"Not found\");\n return;\n }\n\n // Determine content type\n const ext = path.extname(filePath);\n const contentTypes: Record<string, string> = {\n \".html\": \"text/html\",\n \".js\": \"application/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".eot\": \"application/vnd.ms-fontobject\",\n };\n const contentType = contentTypes[ext] || \"application/octet-stream\";\n\n try {\n const content = fs.readFileSync(filePath);\n\n // Set status code to 404 if serving the 404 page\n const statusCode = is404 ? 404 : 200;\n res.writeHead(statusCode, { \"Content-Type\": contentType });\n res.end(content);\n } catch (error) {\n log(\"error\", \"Error serving file:\", error);\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal server error\");\n }\n });\n\n // Setup WebSocket server for RPC\n const wss = new WebSocketServer({\n noServer: true,\n maxPayload: rpcConfig.maxWsPayload,\n perMessageDeflate: compressionConfig.enabled\n ? {\n zlibDeflateOptions: {\n chunkSize: 1024,\n memLevel: 7,\n level: 9, // 6 is default compression level (balanced)\n },\n zlibInflateOptions: {\n chunkSize: 10 * 1024,\n },\n threshold: compressionConfig.threshold,\n }\n : false,\n });\n\n wss.on(\"connection\", (socket: WebSocket, req: http.IncomingMessage) => {\n // Extract client IP with proxy configuration\n const ip = extractClientIP(req, trustProxyDepth);\n\n // Store connection metadata for RPC context\n registry.setSocketMetadata(socket, ip, req);\n\n // Track connection and check IP limit\n if (!rateLimiter.trackConnection(socket, ip)) {\n socket.close(1008, \"Too many connections from your IP\");\n return;\n }\n\n socket.on(\"message\", (msg: WebSocket.RawData, _isBinary: boolean) => {\n // Check rate limit\n if (!rateLimiter.checkRateLimit(socket)) {\n // Parse request to get the ID for proper error response\n try {\n let req: any;\n // Always expect MessagePack\n const buffer = Buffer.isBuffer(msg) ? msg : Buffer.from(msg as any);\n const { decode: msgpackDecode } = require(\"@msgpack/msgpack\");\n req = msgpackDecode(buffer);\n\n const stats = rateLimiter.getConnectionStats(socket);\n const now = Date.now();\n const resetInSeconds = stats ? Math.ceil((stats.resetTimeMs - now) / 1000) : 0;\n\n const createError = (id: string) => ({\n id,\n ok: false,\n stats: {\n remainingRequests: stats ? stats.remainingMessages : 0,\n resetInSeconds,\n },\n error: \"Rate limit exceeded\",\n });\n\n let errorResponse: any;\n if (Array.isArray(req)) {\n errorResponse = req.map((r: any) => createError(r.id));\n } else {\n errorResponse = createError(req.id);\n }\n\n log(\"warn\", `Rate limit exceeded for IP ${ip}, resets in ${resetInSeconds} seconds`);\n socket.send(msgpackEncode(errorResponse) as Buffer);\n } catch {\n // If we can't parse the request, just close the connection\n socket.close();\n }\n return;\n }\n\n registry.handleMessage(socket, Buffer.isBuffer(msg) ? msg : Buffer.from(msg as any));\n });\n });\n\n // Handle WebSocket upgrade requests\n server.on(\"upgrade\", (req, socket, head) => {\n if (req.url?.startsWith(\"/rpc\")) {\n // Security: read token from Sec-WebSocket-Protocol header instead of query string\n const protocols = req.headers[\"sec-websocket-protocol\"];\n const token = typeof protocols === \"string\" ? protocols.split(\",\").map((p) => p.trim()).find((p) => p.includes(\".\")) : undefined;\n\n if (!token || !verifyConnectionToken(token)) {\n log(\"warn\", \"WebSocket connection rejected - invalid token\");\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n // Check IP connection limit before upgrading\n const ip = extractClientIP(req, trustProxyDepth);\n if (rpcSecurity.maxConnectionsPerIP > 0) {\n const currentConnections = rateLimiter.getIPConnectionCount(ip);\n if (currentConnections >= rpcSecurity.maxConnectionsPerIP) {\n log(\"warn\", `WebSocket connection rejected - IP ${ip} has ${currentConnections} connections`);\n socket.write(\"HTTP/1.1 429 Too Many Requests\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit(\"connection\", ws, req);\n });\n } else {\n socket.destroy();\n }\n });\n\n // Start server\n server.listen(port, () => {\n log(\"info\", `Production server listening on http://localhost:${port}`);\n log(\"info\", `Serving static files from ${staticDir}`);\n log(\"info\", `WebSocket RPC available at ws://localhost:${port}/rpc`);\n\n // Start workers\n if (workers.length > 0) {\n log(\"info\", `Starting ${workers.length} worker(s)...`);\n for (const { name, worker } of workers) {\n // Use export name if worker name is anonymous\n if (worker.name === \"anonymous\") {\n worker.name = name;\n worker.__id = name;\n worker.options.name = name;\n }\n if (worker.options.autoStart) {\n const createContext = (): HeliumContext => ({\n req: {\n ip: \"127.0.0.1\",\n headers: {},\n url: undefined,\n method: undefined,\n raw: {} as http.IncomingMessage,\n },\n });\n startWorker(worker, createContext).catch((err) => {\n log(\"error\", `Failed to start worker '${worker.name}':`, err);\n });\n }\n }\n }\n });\n\n // Handle graceful shutdown\n const shutdown = async () => {\n log(\"info\", \"Shutting down...\");\n await stopAllWorkers();\n server.close(() => {\n log(\"info\", \"Server closed\");\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n return server;\n}\n\n// ============================================================================\n// Security helper functions\n// ============================================================================\n\n/**\n * Set default security headers on every HTTP response.\n */\nfunction setSecurityHeaders(res: http.ServerResponse, config: HeliumConfig): void {\n res.setHeader(\"X-Content-Type-Options\", \"nosniff\");\n res.setHeader(\"X-Frame-Options\", \"DENY\");\n res.setHeader(\"X-XSS-Protection\", \"0\");\n res.setHeader(\"Referrer-Policy\", \"strict-origin-when-cross-origin\");\n res.setHeader(\"Permissions-Policy\", \"camera=(), microphone=(), geolocation=()\");\n\n const csp = config.security?.contentSecurityPolicy;\n if (csp) {\n res.setHeader(\"Content-Security-Policy\", csp);\n }\n\n if (config.security?.hsts !== false) {\n res.setHeader(\"Strict-Transport-Security\", \"max-age=31536000; includeSubDomains\");\n }\n}\n\n/**\n * Handle CORS headers based on configuration.\n * Default: restrict to same-origin (no CORS header = browser blocks cross-origin).\n */\nfunction handleCorsHeaders(req: http.IncomingMessage, res: http.ServerResponse, config: HeliumConfig): void {\n const allowedOrigins = config.security?.corsOrigins;\n if (!allowedOrigins || allowedOrigins.length === 0) {\n // No CORS configured — same-origin only by default\n return;\n }\n\n const origin = req.headers.origin;\n if (!origin) {\n return;\n }\n\n const isAllowed = allowedOrigins.includes(\"*\") || allowedOrigins.includes(origin);\n if (isAllowed) {\n res.setHeader(\"Access-Control-Allow-Origin\", allowedOrigins.includes(\"*\") ? \"*\" : origin);\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, X-Requested-With, X-Helium-Token\");\n res.setHeader(\"Access-Control-Max-Age\", \"86400\");\n\n if (!allowedOrigins.includes(\"*\")) {\n res.setHeader(\"Vary\", \"Origin\");\n }\n }\n}"]}
1
+ {"version":3,"file":"prodServer.js","sourceRoot":"","sources":["../../src/server/prodServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGrF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAClC,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;AACxC,MAAM,mBAAmB,GAAG,SAAS,CAAC,cAAc,CAAC,CAAC;AAgBtD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,OAA0B;IACtD,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,EAAE,MAAM,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC;IAE7K,qBAAqB;IACrB,MAAM,eAAe,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,iBAAiB,GAAG,SAAS,CAAC,WAAW,CAAC;IAChD,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAEhC,0BAA0B;IAC1B,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,WAAW,CAAC,oBAAoB,EAAE,WAAW,CAAC,iBAAiB,EAAE,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAEtI,MAAM,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IACpC,UAAU,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAC/C,gBAAgB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACvC,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACrC,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAEjD,2DAA2D;IAC3D,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,IAAI,OAAS,CAAC;IACvD,4CAA4C;IAC5C,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,IAAI,EAAE,CAAC;IAElD,qBAAqB;IACrB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAChD,0CAA0C;QAC1C,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAEhC,wBAAwB;QACxB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC3B,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YACpC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACX,CAAC;QACD,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QAEpC,gCAAgC;QAChC,IAAI,GAAG,CAAC,GAAG,KAAK,2BAA2B,EAAE,CAAC;YAC1C,oEAAoE;YACpE,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBACxB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC,CAAC;gBACzD,OAAO;YACX,CAAC;YACD,mEAAmE;YACnE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACnC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;gBAChD,OAAO;YACX,CAAC;YACD,MAAM,KAAK,GAAG,uBAAuB,EAAE,CAAC;YACxC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YACnC,OAAO;QACX,CAAC;QAED,gFAAgF;QAChF,IAAI,GAAG,CAAC,GAAG,KAAK,iBAAiB,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACzD,iDAAiD;YACjD,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;YACtE,IAAI,CAAC,SAAS,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC;gBAClD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;gBAC9D,OAAO;YACX,CAAC;YAED,qDAAqD;YACrD,MAAM,aAAa,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;YACzE,IAAI,aAAa,GAAG,WAAW,EAAE,CAAC;gBAC9B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;gBAC1E,OAAO;YACX,CAAC;YAED,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,IAAI,SAAS,GAAG,CAAC,CAAC;YAClB,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;gBAC7B,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC;gBAC1B,IAAI,SAAS,GAAG,WAAW,EAAE,CAAC;oBAC1B,OAAO,GAAG,IAAI,CAAC;oBACf,GAAG,CAAC,OAAO,EAAE,CAAC;oBACd,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;oBAC1E,OAAO;gBACX,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;gBACrB,IAAI,OAAO,EAAE,CAAC;oBACV,OAAO;gBACX,CAAC;gBACD,IAAI,CAAC;oBACD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACnC,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;oBACjD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,iBAAiB,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;oBAE/D,MAAM,OAAO,GAAG,aAAa,CAAC,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAClE,IAAI,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,OAAqB,CAAC,CAAC;oBACtD,MAAM,OAAO,GAA2B;wBACpC,cAAc,EAAE,qBAAqB;wBACrC,eAAe,EAAE,UAAU;qBAC9B,CAAC;oBAEF,qBAAqB;oBACrB,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAW,CAAC;oBAChE,IAAI,cAAc,IAAI,YAAY,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;wBAC/C,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;4BAChC,YAAY,GAAG,MAAM,mBAAmB,CAAC,YAAY,CAAC,CAAC;4BACvD,OAAO,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAAC;wBACvC,CAAC;6BAAM,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;4BACzC,YAAY,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,CAAC;4BAC7C,OAAO,CAAC,kBAAkB,CAAC,GAAG,MAAM,CAAC;wBACzC,CAAC;6BAAM,IAAI,cAAc,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;4BAC5C,YAAY,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,CAAC;4BAChD,OAAO,CAAC,kBAAkB,CAAC,GAAG,SAAS,CAAC;wBAC5C,CAAC;oBACL,CAAC;oBAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;oBAC5B,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBAC1B,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACb,GAAG,CAAC,OAAO,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAAC;oBACvC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC;gBAC3E,CAAC;YACL,CAAC,CAAC,CAAC;YACH,OAAO;QACX,CAAC;QAED,iDAAiD;QACjD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACzD,IAAI,OAAO,EAAE,CAAC;YACV,OAAO;QACX,CAAC;QAED,qBAAqB;QACrB,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;QAE3B,2DAA2D;QAC3D,MAAM,YAAY,GAAG,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,iBAAiB,CAAC,CAAC;QAEzI,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,IAAI,QAAQ,GAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAC1D,IAAI,KAAK,GAAG,KAAK,CAAC;QAElB,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,aAAa,KAAK,OAAO,IAAI,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YAChG,6DAA6D;YAC7D,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;YAC9C,KAAK,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,CAAC;YACJ,qDAAqD;YACrD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;YAE7D,2DAA2D;YAC3D,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAClD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,GAAG,QAAQ,CAAC,CAAC;YAC9D,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,aAAa,KAAK,iBAAiB,EAAE,CAAC;gBACjG,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;gBAC9C,KAAK,GAAG,IAAI,CAAC;YACjB,CAAC;YAED,2CAA2C;YAC3C,IAAI,CAAC,KAAK,IAAI,QAAQ,KAAK,GAAG,EAAE,CAAC;gBAC7B,kDAAkD;gBAClD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;gBAC5D,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC9B,QAAQ,GAAG,YAAY,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACJ,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;gBAClD,CAAC;YACL,CAAC;iBAAM,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,qEAAqE;gBACrE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC;oBAC1D,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;wBAC1B,QAAQ,GAAG,QAAQ,CAAC;oBACxB,CAAC;yBAAM,CAAC;wBACJ,sDAAsD;wBACtD,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;oBAC9C,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACJ,qEAAqE;oBACrE,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBAC9C,CAAC;YACL,CAAC;YAED,mFAAmF;YACnF,MAAM,cAAc,GAAG,CAAC,KAAK,IAAI,QAAQ,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;YACvG,IAAI,CAAC,cAAc,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzG,0CAA0C;gBAC1C,8EAA8E;gBAC9E,2EAA2E;gBAC3E,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;gBAC9C,qEAAqE;YACzE,CAAC;QACL,CAAC;QAED,iFAAiF;QACjF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,mEAAmE;YACnE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACrB,OAAO;QACX,CAAC;QAED,yBAAyB;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,YAAY,GAA2B;YACzC,OAAO,EAAE,WAAW;YACpB,KAAK,EAAE,wBAAwB;YAC/B,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,kBAAkB;YAC3B,MAAM,EAAE,WAAW;YACnB,MAAM,EAAE,YAAY;YACpB,OAAO,EAAE,YAAY;YACrB,MAAM,EAAE,WAAW;YACnB,MAAM,EAAE,eAAe;YACvB,MAAM,EAAE,cAAc;YACtB,OAAO,EAAE,WAAW;YACpB,QAAQ,EAAE,YAAY;YACtB,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,+BAA+B;SAC1C,CAAC;QACF,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;QAEpE,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAE1C,iDAAiD;YACjD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YACrC,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,GAAG,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,CAAC,CAAC;YAC3C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,iCAAiC;IACjC,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC;QAC5B,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,SAAS,CAAC,YAAY;QAClC,iBAAiB,EAAE,iBAAiB,CAAC,OAAO;YACxC,CAAC,CAAC;gBACI,kBAAkB,EAAE;oBAChB,SAAS,EAAE,IAAI;oBACf,QAAQ,EAAE,CAAC;oBACX,KAAK,EAAE,CAAC,EAAE,4CAA4C;iBACzD;gBACD,kBAAkB,EAAE;oBAChB,SAAS,EAAE,EAAE,GAAG,IAAI;iBACvB;gBACD,SAAS,EAAE,iBAAiB,CAAC,SAAS;aACzC;YACH,CAAC,CAAC,KAAK;KACd,CAAC,CAAC;IAEH,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAiB,EAAE,GAAyB,EAAE,EAAE;QAClE,6CAA6C;QAC7C,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;QAEjD,4CAA4C;QAC5C,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QAE5C,sCAAsC;QACtC,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,mCAAmC,CAAC,CAAC;YACxD,OAAO;QACX,CAAC;QAED,gFAAgF;QAChF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;YACrC,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC5E,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;YAC5C,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAsB,EAAE,SAAkB,EAAE,EAAE;YAChE,mBAAmB;YACnB,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtC,wDAAwD;gBACxD,IAAI,CAAC;oBACD,IAAI,GAAQ,CAAC;oBACb,4BAA4B;oBAC5B,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAU,CAAC,CAAC;oBACpE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;oBAC9D,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;oBAE5B,MAAM,KAAK,GAAG,WAAW,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;oBACrD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBACvB,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAE/E,MAAM,WAAW,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,CAAC;wBACjC,EAAE;wBACF,EAAE,EAAE,KAAK;wBACT,KAAK,EAAE;4BACH,iBAAiB,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;4BACtD,cAAc;yBACjB;wBACD,KAAK,EAAE,qBAAqB;qBAC/B,CAAC,CAAC;oBAEH,IAAI,aAAkB,CAAC;oBACvB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;wBACrB,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBAC3D,CAAC;yBAAM,CAAC;wBACJ,aAAa,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACxC,CAAC;oBAED,GAAG,CAAC,MAAM,EAAE,8BAA8B,EAAE,eAAe,cAAc,UAAU,CAAC,CAAC;oBACrF,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,CAAW,CAAC,CAAC;gBACxD,CAAC;gBAAC,MAAM,CAAC;oBACL,2DAA2D;oBAC3D,MAAM,CAAC,KAAK,EAAE,CAAC;gBACnB,CAAC;gBACD,OAAO;YACX,CAAC;YAED,QAAQ,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAU,CAAC,CAAC,CAAC;QACzF,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,oCAAoC;IACpC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QACvC,IAAI,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,kFAAkF;YAClF,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;YACxD,MAAM,KAAK,GACP,OAAO,SAAS,KAAK,QAAQ;gBACzB,CAAC,CAAC,SAAS;qBACJ,KAAK,CAAC,GAAG,CAAC;qBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;qBACpB,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACnC,CAAC,CAAC,SAAS,CAAC;YAEpB,IAAI,CAAC,KAAK,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1C,GAAG,CAAC,MAAM,EAAE,+CAA+C,CAAC,CAAC;gBAC7D,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBAClD,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO;YACX,CAAC;YAED,6CAA6C;YAC7C,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;YACjD,IAAI,WAAW,CAAC,mBAAmB,GAAG,CAAC,EAAE,CAAC;gBACtC,MAAM,kBAAkB,GAAG,WAAW,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;gBAChE,IAAI,kBAAkB,IAAI,WAAW,CAAC,mBAAmB,EAAE,CAAC;oBACxD,GAAG,CAAC,MAAM,EAAE,sCAAsC,EAAE,QAAQ,kBAAkB,cAAc,CAAC,CAAC;oBAC9F,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;oBACvD,MAAM,CAAC,OAAO,EAAE,CAAC;oBACjB,OAAO;gBACX,CAAC;YACL,CAAC;YAED,GAAG,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;gBACxC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;YACpC,CAAC,CAAC,CAAC;QACP,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,eAAe;IACf,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACrB,GAAG,CAAC,MAAM,EAAE,mDAAmD,IAAI,EAAE,CAAC,CAAC;QACvE,GAAG,CAAC,MAAM,EAAE,6BAA6B,SAAS,EAAE,CAAC,CAAC;QACtD,GAAG,CAAC,MAAM,EAAE,6CAA6C,IAAI,MAAM,CAAC,CAAC;QAErE,gBAAgB;QAChB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,GAAG,CAAC,MAAM,EAAE,YAAY,OAAO,CAAC,MAAM,eAAe,CAAC,CAAC;YACvD,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;gBACrC,8CAA8C;gBAC9C,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBAC9B,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;oBACnB,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;oBACnB,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;gBAC/B,CAAC;gBACD,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;oBAC3B,MAAM,aAAa,GAAG,GAAkB,EAAE,CAAC,CAAC;wBACxC,GAAG,EAAE;4BACD,EAAE,EAAE,WAAW;4BACf,OAAO,EAAE,EAAE;4BACX,GAAG,EAAE,SAAS;4BACd,MAAM,EAAE,SAAS;4BACjB,GAAG,EAAE,EAA0B;yBAClC;qBACJ,CAAC,CAAC;oBACH,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;wBAC7C,GAAG,CAAC,OAAO,EAAE,2BAA2B,MAAM,CAAC,IAAI,IAAI,EAAE,GAAG,CAAC,CAAC;oBAClE,CAAC,CAAC,CAAC;gBACP,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,2BAA2B;IAC3B,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QACxB,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QAChC,MAAM,cAAc,EAAE,CAAC;QACvB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;YACd,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,+EAA+E;AAC/E,4BAA4B;AAC5B,+EAA+E;AAE/E;;GAEG;AACH,SAAS,kBAAkB,CAAC,GAAwB,EAAE,MAAoB;IACtE,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;IACnD,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;IACzC,GAAG,CAAC,SAAS,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACvC,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,iCAAiC,CAAC,CAAC;IACpE,GAAG,CAAC,SAAS,CAAC,oBAAoB,EAAE,0CAA0C,CAAC,CAAC;IAEhF,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACnD,IAAI,GAAG,EAAE,CAAC;QACN,GAAG,CAAC,SAAS,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;QAClC,GAAG,CAAC,SAAS,CAAC,2BAA2B,EAAE,qCAAqC,CAAC,CAAC;IACtF,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,GAAyB,EAAE,GAAwB,EAAE,MAAoB;IAChG,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC;IACpD,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,mDAAmD;QACnD,OAAO;IACX,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;IAClC,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO;IACX,CAAC;IAED,MAAM,SAAS,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClF,IAAI,SAAS,EAAE,CAAC;QACZ,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC1F,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,oBAAoB,CAAC,CAAC;QACpE,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,gDAAgD,CAAC,CAAC;QAChG,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;QAEjD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;AACL,CAAC","sourcesContent":["import { encode as msgpackEncode } from \"@msgpack/msgpack\";\nimport fs from \"fs\";\nimport http from \"http\";\nimport path from \"path\";\nimport { promisify } from \"util\";\nimport type WebSocket from \"ws\";\nimport { WebSocketServer } from \"ws\";\nimport { brotliCompress, deflate, gzip } from \"zlib\";\n\nimport { extractClientIP } from \"../utils/ipExtractor.js\";\nimport { log } from \"../utils/logger.js\";\nimport type { HeliumConfig } from \"./config.js\";\nimport { getRpcConfig, getRpcSecurityConfig, getTrustProxyDepth } from \"./config.js\";\nimport type { HeliumContext } from \"./context.js\";\nimport type { HeliumWorkerDef } from \"./defineWorker.js\";\nimport { startWorker, stopAllWorkers } from \"./defineWorker.js\";\nimport { HTTPRouter } from \"./httpRouter.js\";\nimport { RateLimiter } from \"./rateLimiter.js\";\nimport { RpcRegistry } from \"./rpcRegistry.js\";\nimport { generateConnectionToken, initializeSecurity, verifyConnectionToken } from \"./security.js\";\nimport { prepareForMsgpack } from \"./serializer.js\";\n\nconst gzipAsync = promisify(gzip);\nconst deflateAsync = promisify(deflate);\nconst brotliCompressAsync = promisify(brotliCompress);\n\ninterface WorkerEntry {\n name: string;\n worker: HeliumWorkerDef;\n}\n\ninterface ProdServerOptions {\n port?: number;\n distDir?: string;\n staticDir?: string;\n registerHandlers: (registry: RpcRegistry, httpRouter: HTTPRouter) => void;\n config?: HeliumConfig;\n workers?: WorkerEntry[];\n}\n\n/**\n * Starts a production HTTP server that:\n * - Serves static files from the dist directory\n * - Supports SSG (Static Site Generation) by serving .html files for routes (e.g., /about -> about.html)\n * - Falls back to index.html for client-side routing (SPA)\n * - Handles custom HTTP endpoints (webhooks, auth, etc.)\n * - Hosts WebSocket RPC server\n * - Starts background workers\n *\n * SSG Behavior:\n * - Production correctly serves SSG pages (e.g., /about serves about.html with pre-rendered content)\n * - This ensures search engines and social media crawlers see the correct content\n * - Client-side navigation between pages still works via React Router\n */\nexport function startProdServer(options: ProdServerOptions) {\n const { port = Number(process.env.PORT || 3000), distDir = \"dist\", staticDir = path.resolve(process.cwd(), distDir), registerHandlers, config = {}, workers = [] } = options;\n\n // Load configuration\n const trustProxyDepth = getTrustProxyDepth(config);\n const rpcSecurity = getRpcSecurityConfig(config);\n const rpcConfig = getRpcConfig(config);\n const compressionConfig = rpcConfig.compression;\n initializeSecurity(rpcSecurity);\n\n // Initialize rate limiter\n const rateLimiter = new RateLimiter(rpcSecurity.maxMessagesPerWindow, rpcSecurity.rateLimitWindowMs, rpcSecurity.maxConnectionsPerIP);\n\n const registry = new RpcRegistry();\n const httpRouter = new HTTPRouter();\n httpRouter.setTrustProxyDepth(trustProxyDepth);\n registerHandlers(registry, httpRouter);\n registry.setRateLimiter(rateLimiter);\n registry.setMaxBatchSize(rpcConfig.maxBatchSize);\n\n // Security: max body size for HTTP requests (1 MB default)\n const maxBodySize = rpcConfig.maxBodySize ?? 1_048_576;\n // Security: max batch size for RPC requests\n const maxBatchSize = rpcConfig.maxBatchSize ?? 20;\n\n // Create HTTP server\n const server = http.createServer(async (req, res) => {\n // Apply security headers to all responses\n setSecurityHeaders(res, config);\n\n // Handle CORS preflight\n if (req.method === \"OPTIONS\") {\n handleCorsHeaders(req, res, config);\n res.writeHead(204);\n res.end();\n return;\n }\n handleCorsHeaders(req, res, config);\n\n // Handle token refresh endpoint\n if (req.url === \"/__helium__/refresh-token\") {\n // Security: only allow POST to prevent CSRF via <img>/<script> tags\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Method not allowed\" }));\n return;\n }\n // Security: require custom header to prevent cross-origin requests\n if (!req.headers[\"x-requested-with\"]) {\n res.writeHead(403, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Forbidden\" }));\n return;\n }\n const token = generateConnectionToken();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ token }));\n return;\n }\n\n // Handle HTTP-based RPC endpoint (alternative to WebSocket for mobile networks)\n if (req.url === \"/__helium__/rpc\" && req.method === \"POST\") {\n // Security: verify connection token for HTTP RPC\n const authToken = req.headers[\"x-helium-token\"] as string | undefined;\n if (!authToken || !verifyConnectionToken(authToken)) {\n res.writeHead(401, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Unauthorized\" }));\n return;\n }\n\n // Security: check Content-Length before reading body\n const contentLength = parseInt(req.headers[\"content-length\"] || \"0\", 10);\n if (contentLength > maxBodySize) {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Request entity too large\" }));\n return;\n }\n\n const chunks: Buffer[] = [];\n let totalSize = 0;\n let aborted = false;\n req.on(\"data\", (chunk: Buffer) => {\n totalSize += chunk.length;\n if (totalSize > maxBodySize) {\n aborted = true;\n req.destroy();\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Request entity too large\" }));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", async () => {\n if (aborted) {\n return;\n }\n try {\n const body = Buffer.concat(chunks);\n const ip = extractClientIP(req, trustProxyDepth);\n const result = await registry.handleHttpRequest(body, ip, req);\n\n const encoded = msgpackEncode(prepareForMsgpack(result.response));\n let responseBody = Buffer.from(encoded as Uint8Array);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/msgpack\",\n \"Cache-Control\": \"no-store\",\n };\n\n // Handle compression\n const acceptEncoding = req.headers[\"accept-encoding\"] as string;\n if (acceptEncoding && responseBody.length > 1024) {\n if (acceptEncoding.includes(\"br\")) {\n responseBody = await brotliCompressAsync(responseBody);\n headers[\"Content-Encoding\"] = \"br\";\n } else if (acceptEncoding.includes(\"gzip\")) {\n responseBody = await gzipAsync(responseBody);\n headers[\"Content-Encoding\"] = \"gzip\";\n } else if (acceptEncoding.includes(\"deflate\")) {\n responseBody = await deflateAsync(responseBody);\n headers[\"Content-Encoding\"] = \"deflate\";\n }\n }\n\n res.writeHead(200, headers);\n res.end(responseBody);\n } catch (error) {\n log(\"error\", \"HTTP RPC error:\", error);\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Internal server error\" }));\n }\n });\n return;\n }\n\n // Try HTTP handlers first (webhooks, auth, etc.)\n const handled = await httpRouter.handleRequest(req, res);\n if (handled) {\n return;\n }\n\n // Serve static files\n const url = req.url || \"/\";\n\n // Block access to sensitive configuration and server files\n const blockedFiles = [\"helium.config.js\", \"helium.config.mjs\", \"helium.config.ts\", \"server.js\", \".env\", \".env.local\", \".env.production\"];\n\n const requestedFile = path.basename(url.split(\"?\")[0]);\n let filePath: string = path.join(staticDir, \"index.html\");\n let is404 = false;\n\n if (blockedFiles.some((blocked) => requestedFile === blocked || requestedFile.startsWith(\".env\"))) {\n // Serve index.html so the SPA router can render the 404 page\n filePath = path.join(staticDir, \"index.html\");\n is404 = true;\n } else {\n // Clean URL (remove query params and trailing slash)\n const cleanUrl = url.split(\"?\")[0].replace(/\\/$/, \"\") || \"/\";\n\n // Security: path traversal prevention — resolve and verify\n const resolvedStaticDir = path.resolve(staticDir);\n const candidatePath = path.resolve(staticDir, \".\" + cleanUrl);\n if (!candidatePath.startsWith(resolvedStaticDir + path.sep) && candidatePath !== resolvedStaticDir) {\n filePath = path.join(staticDir, \"index.html\");\n is404 = true;\n }\n\n // Try different file paths for SSG support\n if (!is404 && cleanUrl === \"/\") {\n // Try index.ssg.html first (if root page has SSG)\n const ssgIndexPath = path.join(staticDir, \"index.ssg.html\");\n if (fs.existsSync(ssgIndexPath)) {\n filePath = ssgIndexPath;\n } else {\n filePath = path.join(staticDir, \"index.html\");\n }\n } else if (!is404) {\n // If cleanUrl has no extension, prioritize .html files for SSG pages\n if (!path.extname(cleanUrl)) {\n const htmlPath = path.join(staticDir, cleanUrl + \".html\");\n if (fs.existsSync(htmlPath)) {\n filePath = htmlPath;\n } else {\n // Fall back to exact path (for assets or directories)\n filePath = path.join(staticDir, cleanUrl);\n }\n } else {\n // Has an extension, try exact path (for assets like /assets/main.js)\n filePath = path.join(staticDir, cleanUrl);\n }\n }\n\n // If file doesn't exist or is a directory, fall back to index.html for SPA routing\n const isFileOrExists = !is404 && filePath && fs.existsSync(filePath) && fs.statSync(filePath).isFile();\n if (!isFileOrExists && !url.startsWith(\"/api\") && !url.startsWith(\"/webhooks\") && !url.startsWith(\"/auth\")) {\n // Fall back to index.html for SPA routing\n // Note: We don't set is404 here because the client-side router will determine\n // if the route exists. If it doesn't, the router will render the 404 page.\n filePath = path.join(staticDir, \"index.html\");\n // Don't set is404 = true here - let the client-side router handle it\n }\n }\n\n // Check if file exists (should always exist now since we fallback to index.html)\n if (!fs.existsSync(filePath)) {\n // This should rarely happen - only if index.html itself is missing\n res.writeHead(404, { \"Content-Type\": \"text/html\" });\n res.end(\"Not found\");\n return;\n }\n\n // Determine content type\n const ext = path.extname(filePath);\n const contentTypes: Record<string, string> = {\n \".html\": \"text/html\",\n \".js\": \"application/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".eot\": \"application/vnd.ms-fontobject\",\n };\n const contentType = contentTypes[ext] || \"application/octet-stream\";\n\n try {\n const content = fs.readFileSync(filePath);\n\n // Set status code to 404 if serving the 404 page\n const statusCode = is404 ? 404 : 200;\n res.writeHead(statusCode, { \"Content-Type\": contentType });\n res.end(content);\n } catch (error) {\n log(\"error\", \"Error serving file:\", error);\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal server error\");\n }\n });\n\n // Setup WebSocket server for RPC\n const wss = new WebSocketServer({\n noServer: true,\n maxPayload: rpcConfig.maxWsPayload,\n perMessageDeflate: compressionConfig.enabled\n ? {\n zlibDeflateOptions: {\n chunkSize: 1024,\n memLevel: 7,\n level: 9, // 6 is default compression level (balanced)\n },\n zlibInflateOptions: {\n chunkSize: 10 * 1024,\n },\n threshold: compressionConfig.threshold,\n }\n : false,\n });\n\n wss.on(\"connection\", (socket: WebSocket, req: http.IncomingMessage) => {\n // Extract client IP with proxy configuration\n const ip = extractClientIP(req, trustProxyDepth);\n\n // Store connection metadata for RPC context\n registry.setSocketMetadata(socket, ip, req);\n\n // Track connection and check IP limit\n if (!rateLimiter.trackConnection(socket, ip)) {\n socket.close(1008, \"Too many connections from your IP\");\n return;\n }\n\n // Prevent unhandled errors from crashing the process (e.g. maxPayload exceeded)\n socket.on(\"error\", (err) => {\n log(\"warn\", \"WebSocket error:\", err);\n if (socket.readyState === socket.OPEN || socket.readyState === socket.CLOSING) {\n socket.close(1009, \"Message too large\");\n }\n });\n\n socket.on(\"message\", (msg: WebSocket.RawData, _isBinary: boolean) => {\n // Check rate limit\n if (!rateLimiter.checkRateLimit(socket)) {\n // Parse request to get the ID for proper error response\n try {\n let req: any;\n // Always expect MessagePack\n const buffer = Buffer.isBuffer(msg) ? msg : Buffer.from(msg as any);\n const { decode: msgpackDecode } = require(\"@msgpack/msgpack\");\n req = msgpackDecode(buffer);\n\n const stats = rateLimiter.getConnectionStats(socket);\n const now = Date.now();\n const resetInSeconds = stats ? Math.ceil((stats.resetTimeMs - now) / 1000) : 0;\n\n const createError = (id: string) => ({\n id,\n ok: false,\n stats: {\n remainingRequests: stats ? stats.remainingMessages : 0,\n resetInSeconds,\n },\n error: \"Rate limit exceeded\",\n });\n\n let errorResponse: any;\n if (Array.isArray(req)) {\n errorResponse = req.map((r: any) => createError(r.id));\n } else {\n errorResponse = createError(req.id);\n }\n\n log(\"warn\", `Rate limit exceeded for IP ${ip}, resets in ${resetInSeconds} seconds`);\n socket.send(msgpackEncode(errorResponse) as Buffer);\n } catch {\n // If we can't parse the request, just close the connection\n socket.close();\n }\n return;\n }\n\n registry.handleMessage(socket, Buffer.isBuffer(msg) ? msg : Buffer.from(msg as any));\n });\n });\n\n // Handle WebSocket upgrade requests\n server.on(\"upgrade\", (req, socket, head) => {\n if (req.url?.startsWith(\"/rpc\")) {\n // Security: read token from Sec-WebSocket-Protocol header instead of query string\n const protocols = req.headers[\"sec-websocket-protocol\"];\n const token =\n typeof protocols === \"string\"\n ? protocols\n .split(\",\")\n .map((p) => p.trim())\n .find((p) => p.includes(\".\"))\n : undefined;\n\n if (!token || !verifyConnectionToken(token)) {\n log(\"warn\", \"WebSocket connection rejected - invalid token\");\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n // Check IP connection limit before upgrading\n const ip = extractClientIP(req, trustProxyDepth);\n if (rpcSecurity.maxConnectionsPerIP > 0) {\n const currentConnections = rateLimiter.getIPConnectionCount(ip);\n if (currentConnections >= rpcSecurity.maxConnectionsPerIP) {\n log(\"warn\", `WebSocket connection rejected - IP ${ip} has ${currentConnections} connections`);\n socket.write(\"HTTP/1.1 429 Too Many Requests\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit(\"connection\", ws, req);\n });\n } else {\n socket.destroy();\n }\n });\n\n // Start server\n server.listen(port, () => {\n log(\"info\", `Production server listening on http://localhost:${port}`);\n log(\"info\", `Serving static files from ${staticDir}`);\n log(\"info\", `WebSocket RPC available at ws://localhost:${port}/rpc`);\n\n // Start workers\n if (workers.length > 0) {\n log(\"info\", `Starting ${workers.length} worker(s)...`);\n for (const { name, worker } of workers) {\n // Use export name if worker name is anonymous\n if (worker.name === \"anonymous\") {\n worker.name = name;\n worker.__id = name;\n worker.options.name = name;\n }\n if (worker.options.autoStart) {\n const createContext = (): HeliumContext => ({\n req: {\n ip: \"127.0.0.1\",\n headers: {},\n url: undefined,\n method: undefined,\n raw: {} as http.IncomingMessage,\n },\n });\n startWorker(worker, createContext).catch((err) => {\n log(\"error\", `Failed to start worker '${worker.name}':`, err);\n });\n }\n }\n }\n });\n\n // Handle graceful shutdown\n const shutdown = async () => {\n log(\"info\", \"Shutting down...\");\n await stopAllWorkers();\n server.close(() => {\n log(\"info\", \"Server closed\");\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n return server;\n}\n\n// ============================================================================\n// Security helper functions\n// ============================================================================\n\n/**\n * Set default security headers on every HTTP response.\n */\nfunction setSecurityHeaders(res: http.ServerResponse, config: HeliumConfig): void {\n res.setHeader(\"X-Content-Type-Options\", \"nosniff\");\n res.setHeader(\"X-Frame-Options\", \"DENY\");\n res.setHeader(\"X-XSS-Protection\", \"0\");\n res.setHeader(\"Referrer-Policy\", \"strict-origin-when-cross-origin\");\n res.setHeader(\"Permissions-Policy\", \"camera=(), microphone=(), geolocation=()\");\n\n const csp = config.security?.contentSecurityPolicy;\n if (csp) {\n res.setHeader(\"Content-Security-Policy\", csp);\n }\n\n if (config.security?.hsts !== false) {\n res.setHeader(\"Strict-Transport-Security\", \"max-age=31536000; includeSubDomains\");\n }\n}\n\n/**\n * Handle CORS headers based on configuration.\n * Default: restrict to same-origin (no CORS header = browser blocks cross-origin).\n */\nfunction handleCorsHeaders(req: http.IncomingMessage, res: http.ServerResponse, config: HeliumConfig): void {\n const allowedOrigins = config.security?.corsOrigins;\n if (!allowedOrigins || allowedOrigins.length === 0) {\n // No CORS configured — same-origin only by default\n return;\n }\n\n const origin = req.headers.origin;\n if (!origin) {\n return;\n }\n\n const isAllowed = allowedOrigins.includes(\"*\") || allowedOrigins.includes(origin);\n if (isAllowed) {\n res.setHeader(\"Access-Control-Allow-Origin\", allowedOrigins.includes(\"*\") ? \"*\" : origin);\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, X-Requested-With, X-Helium-Token\");\n res.setHeader(\"Access-Control-Max-Age\", \"86400\");\n\n if (!allowedOrigins.includes(\"*\")) {\n res.setHeader(\"Vary\", \"Origin\");\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heliumts",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "A lightweight full-stack React framework with file-based routing, RPC, and SSG support",
5
5
  "keywords": [
6
6
  "react",