@hyperspan/framework 0.1.3 → 0.1.5

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/dist/server.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // Generated by dts-bundle-generator v9.5.1
2
2
 
3
- import { Context, Handler, Hono } from 'hono';
3
+ import { Context, Hono } from 'hono';
4
4
 
5
5
  declare class TmplHtml {
6
6
  _kind: string;
@@ -15,84 +15,36 @@ declare class TmplHtml {
15
15
  constructor(props: Pick<TmplHtml, "content" | "asyncContent">);
16
16
  }
17
17
  export declare const IS_PROD: boolean;
18
- /**
19
- * Route
20
- * Define a route that can handle a direct HTTP request
21
- * Route handlers should return a Response or TmplHtml object
22
- */
23
- export declare function createRoute(handler: Handler): HSRoute;
24
- /**
25
- * Component
26
- * Define a component or partial with an optional loading placeholder
27
- * These can be rendered anywhere inside other templates - even if async.
28
- */
29
- export declare function createComponent(render: () => THSComponentReturn | Promise<THSComponentReturn>): HSComponent;
30
- /**
31
- * Form + route handler
32
- * Automatically handles and parses form data
33
- *
34
- * INITIAL IDEA OF HOW THIS WILL WORK:
35
- * ---
36
- * 1. Renders component as initial form markup for GET request
37
- * 2. Bind form onSubmit function to custom client JS handling
38
- * 3. Submits form with JavaScript fetch()
39
- * 4. Replaces form content with content from server
40
- * 5. All validation and save logic is on the server
41
- * 6. Handles any Exception thrown on server as error displayed in client
42
- */
43
- export declare function createForm(renderForm: (data?: any) => THSResponseTypes, schema?: z.ZodSchema | null): HSFormRoute;
44
18
  /**
45
19
  * Types
46
20
  */
47
- export type THSComponentReturn = TmplHtml | string | number | null;
48
21
  export type THSResponseTypes = TmplHtml | Response | string | null;
49
- export declare const HS_DEFAULT_LOADING: () => TmplHtml;
50
- /**
51
- * Route handler helper
52
- */
53
- export declare class HSComponent {
54
- _kind: string;
55
- _handlers: Record<string, Handler>;
56
- _loading?: () => TmplHtml;
57
- render: () => THSComponentReturn | Promise<THSComponentReturn>;
58
- constructor(render: () => THSComponentReturn | Promise<THSComponentReturn>);
59
- loading(fn: () => TmplHtml): this;
60
- }
22
+ export type THSRouteHandler = (context: Context) => THSResponseTypes | Promise<THSResponseTypes>;
23
+ export type THSRoute = {
24
+ _kind: "hsRoute";
25
+ get: (handler: THSRouteHandler) => THSRoute;
26
+ post: (handler: THSRouteHandler) => THSRoute;
27
+ put: (handler: THSRouteHandler) => THSRoute;
28
+ delete: (handler: THSRouteHandler) => THSRoute;
29
+ patch: (handler: THSRouteHandler) => THSRoute;
30
+ run: (method: string, context: Context) => Promise<Response>;
31
+ };
61
32
  /**
62
- * Route handler helper
33
+ * Define a route that can handle a direct HTTP request.
34
+ * Route handlers should return a TmplHtml or Response object
63
35
  */
64
- export declare class HSRoute {
65
- _kind: string;
66
- _handlers: Record<string, Handler>;
67
- _methods: null | string[];
68
- constructor(handler: Handler);
69
- }
36
+ export declare function createRoute(handler?: THSRouteHandler): THSRoute;
70
37
  /**
71
- * Form route handler helper
38
+ * Create new API Route
39
+ * API Route handlers should return a JSON object or a Response
72
40
  */
73
- export type THSFormRenderer = (data?: any) => THSResponseTypes;
74
- export declare class HSFormRoute {
75
- _kind: string;
76
- _handlers: Record<string, Handler>;
77
- _form: THSFormRenderer;
78
- _methods: null | string[];
79
- _schema: null | z.ZodSchema;
80
- constructor(renderForm: THSFormRenderer, schema?: z.ZodSchema | null);
81
- getDefaultData(): unknown;
82
- /**
83
- * Get form renderer method
84
- */
85
- renderForm(data?: any): THSResponseTypes;
86
- get(handler: Handler): this;
87
- patch(handler: Handler): this;
88
- post(handler: Handler): this;
89
- put(handler: Handler): this;
90
- delete(handler: Handler): this;
91
- }
41
+ export declare function createAPIRoute(handler?: THSRouteHandler): THSRoute;
92
42
  /**
93
- * Run route from file
43
+ * Get a Hyperspan runnable route from a module import
44
+ * @throws Error if no runnable route found
94
45
  */
95
- export declare function runFileRoute(RouteModule: any, context: Context): Promise<Response | false>;
46
+ export declare function getRunnableRoute(route: unknown): THSRoute;
47
+ export declare function isRunnableRoute(route: unknown): boolean;
96
48
  export type THSServerConfig = {
97
49
  appDir: string;
98
50
  staticFileRoot: string;
@@ -109,6 +61,10 @@ export type THSRouteMap = {
109
61
  params: string[];
110
62
  };
111
63
  export declare function buildRoutes(config: THSServerConfig): Promise<THSRouteMap[]>;
64
+ /**
65
+ * Run route from file
66
+ */
67
+ export declare function createRouteFromModule(RouteModule: any): (context: Context) => Promise<Response>;
112
68
  /**
113
69
  * Create and start Bun HTTP server
114
70
  */
package/dist/server.js CHANGED
@@ -1796,321 +1796,155 @@ var WSContext = class {
1796
1796
  }
1797
1797
  };
1798
1798
 
1799
- // node_modules/@zod/core/dist/esm/core.js
1800
- var $brand = Symbol("zod_brand");
1801
-
1802
- class $ZodAsyncError extends Error {
1803
- constructor() {
1804
- super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`);
1799
+ // node_modules/hono/dist/http-exception.js
1800
+ var HTTPException = class extends Error {
1801
+ res;
1802
+ status;
1803
+ constructor(status = 500, options) {
1804
+ super(options?.message, { cause: options?.cause });
1805
+ this.res = options?.res;
1806
+ this.status = status;
1807
+ }
1808
+ getResponse() {
1809
+ if (this.res) {
1810
+ const newResponse = new Response(this.res.body, {
1811
+ status: this.status,
1812
+ headers: this.res.headers
1813
+ });
1814
+ return newResponse;
1815
+ }
1816
+ return new Response(this.message, {
1817
+ status: this.status
1818
+ });
1805
1819
  }
1806
- }
1807
- var globalConfig = {};
1808
- function config(config2) {
1809
- if (config2)
1810
- Object.assign(globalConfig, config2);
1811
- return globalConfig;
1812
- }
1820
+ };
1813
1821
 
1814
- // node_modules/@zod/core/dist/esm/util.js
1815
- function jsonStringifyReplacer(_, value) {
1816
- if (typeof value === "bigint")
1817
- return value.toString();
1818
- return value;
1819
- }
1820
- function cached(getter) {
1821
- const set = false;
1822
- return {
1823
- get value() {
1824
- if (!set) {
1825
- const value = getter();
1826
- Object.defineProperty(this, "value", { value });
1827
- return value;
1822
+ // src/server.ts
1823
+ var IS_PROD = false;
1824
+ var CWD = process.cwd();
1825
+ function createRoute(handler) {
1826
+ let _handlers = {};
1827
+ if (handler) {
1828
+ _handlers["GET"] = handler;
1829
+ }
1830
+ const api = {
1831
+ _kind: "hsRoute",
1832
+ get(handler2) {
1833
+ _handlers["GET"] = handler2;
1834
+ return api;
1835
+ },
1836
+ post(handler2) {
1837
+ _handlers["POST"] = handler2;
1838
+ return api;
1839
+ },
1840
+ put(handler2) {
1841
+ _handlers["PUT"] = handler2;
1842
+ return api;
1843
+ },
1844
+ delete(handler2) {
1845
+ _handlers["DELETE"] = handler2;
1846
+ return api;
1847
+ },
1848
+ patch(handler2) {
1849
+ _handlers["PATCH"] = handler2;
1850
+ return api;
1851
+ },
1852
+ async run(method, context) {
1853
+ const handler2 = _handlers[method];
1854
+ if (!handler2) {
1855
+ throw new HTTPException(405, { message: "Method not allowed" });
1856
+ }
1857
+ const routeContent = await handler2(context);
1858
+ if (routeContent instanceof Response) {
1859
+ return routeContent;
1860
+ }
1861
+ const userIsBot = isbot(context.req.header("User-Agent"));
1862
+ const streamOpt = context.req.query("__nostream");
1863
+ const streamingEnabled = !userIsBot && (streamOpt !== undefined ? streamOpt : true);
1864
+ const routeKind = typeof routeContent;
1865
+ if (routeContent && routeKind === "object" && (routeContent instanceof TmplHtml || routeContent.constructor.name === "TmplHtml" || routeContent?._kind === "TmplHtml")) {
1866
+ if (streamingEnabled) {
1867
+ return new StreamResponse(renderStream(routeContent));
1868
+ } else {
1869
+ const output = await renderAsync(routeContent);
1870
+ return context.html(output);
1871
+ }
1828
1872
  }
1829
- throw new Error("cached value already set");
1873
+ return context.text(String(routeContent));
1830
1874
  }
1831
1875
  };
1876
+ return api;
1832
1877
  }
1833
- var allowsEval = cached(() => {
1834
- try {
1835
- new Function("");
1836
- return true;
1837
- } catch (_) {
1838
- return false;
1839
- }
1840
- });
1841
- var propertyKeyTypes = new Set(["string", "number", "symbol"]);
1842
- var primitiveTypes = new Set(["string", "number", "bigint", "boolean", "symbol", "undefined"]);
1843
- var NUMBER_FORMAT_RANGES = {
1844
- safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER],
1845
- int32: [-2147483648, 2147483647],
1846
- uint32: [0, 4294967295],
1847
- float32: [-340282346638528860000000000000000000000, 340282346638528860000000000000000000000],
1848
- float64: [-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]
1849
- };
1850
- function unwrapMessage(message) {
1851
- return typeof message === "string" ? message : message?.message;
1852
- }
1853
- function finalizeIssue(iss, ctx, config2) {
1854
- const full = { ...iss, path: iss.path ?? [] };
1855
- if (!iss.message) {
1856
- const message = unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config2.customError?.(iss)) ?? unwrapMessage(config2.localeError?.(iss)) ?? "Invalid input";
1857
- full.message = message;
1858
- }
1859
- delete full.inst;
1860
- delete full.continue;
1861
- if (!ctx?.reportInput) {
1862
- delete full.input;
1863
- }
1864
- return full;
1865
- }
1866
-
1867
- // node_modules/@zod/core/dist/esm/errors.js
1868
- var ZOD_ERROR = Symbol.for("{{zod.error}}");
1869
-
1870
- class $ZodError {
1871
- get message() {
1872
- return JSON.stringify(this.issues, jsonStringifyReplacer, 2);
1873
- }
1874
- constructor(issues) {
1875
- Object.defineProperty(this, "_tag", { value: ZOD_ERROR, enumerable: false });
1876
- Object.defineProperty(this, "name", { value: "$ZodError", enumerable: false });
1877
- this.issues = issues;
1878
- }
1879
- static [Symbol.hasInstance](inst) {
1880
- return inst?._tag === ZOD_ERROR;
1881
- }
1882
- }
1883
- function flattenError(error, mapper = (issue) => issue.message) {
1884
- const fieldErrors = {};
1885
- const formErrors = [];
1886
- for (const sub of error.issues) {
1887
- if (sub.path.length > 0) {
1888
- fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || [];
1889
- fieldErrors[sub.path[0]].push(mapper(sub));
1890
- } else {
1891
- formErrors.push(mapper(sub));
1892
- }
1893
- }
1894
- return { formErrors, fieldErrors };
1895
- }
1896
- function formatError(error, _mapper) {
1897
- const mapper = _mapper || function(issue) {
1898
- return issue.message;
1899
- };
1900
- const fieldErrors = { _errors: [] };
1901
- const processError = (error2) => {
1902
- for (const issue of error2.issues) {
1903
- if (issue.code === "invalid_union") {
1904
- issue.errors.map((issues) => processError({ issues }));
1905
- } else if (issue.code === "invalid_key") {
1906
- processError({ issues: issue.issues });
1907
- } else if (issue.code === "invalid_element") {
1908
- processError({ issues: issue.issues });
1909
- } else if (issue.path.length === 0) {
1910
- fieldErrors._errors.push(mapper(issue));
1911
- } else {
1912
- let curr = fieldErrors;
1913
- let i = 0;
1914
- while (i < issue.path.length) {
1915
- const el = issue.path[i];
1916
- const terminal = i === issue.path.length - 1;
1917
- if (!terminal) {
1918
- curr[el] = curr[el] || { _errors: [] };
1919
- } else {
1920
- curr[el] = curr[el] || { _errors: [] };
1921
- curr[el]._errors.push(mapper(issue));
1922
- }
1923
- curr = curr[el];
1924
- i++;
1878
+ function createAPIRoute(handler) {
1879
+ let _handlers = {};
1880
+ if (handler) {
1881
+ _handlers["GET"] = handler;
1882
+ }
1883
+ const api = {
1884
+ _kind: "hsRoute",
1885
+ get(handler2) {
1886
+ _handlers["GET"] = handler2;
1887
+ return api;
1888
+ },
1889
+ post(handler2) {
1890
+ _handlers["POST"] = handler2;
1891
+ return api;
1892
+ },
1893
+ put(handler2) {
1894
+ _handlers["PUT"] = handler2;
1895
+ return api;
1896
+ },
1897
+ delete(handler2) {
1898
+ _handlers["DELETE"] = handler2;
1899
+ return api;
1900
+ },
1901
+ patch(handler2) {
1902
+ _handlers["PATCH"] = handler2;
1903
+ return api;
1904
+ },
1905
+ async run(method, context) {
1906
+ const handler2 = _handlers[method];
1907
+ if (!handler2) {
1908
+ throw new Error("Method not allowed");
1909
+ }
1910
+ try {
1911
+ const response = await handler2(context);
1912
+ if (response instanceof Response) {
1913
+ return response;
1925
1914
  }
1915
+ return context.json({ meta: { success: true, dtResponse: new Date }, data: response }, { status: 200 });
1916
+ } catch (err) {
1917
+ const e = err;
1918
+ console.error(e);
1919
+ return context.json({
1920
+ meta: { success: false, dtResponse: new Date },
1921
+ data: {},
1922
+ error: {
1923
+ message: e.message,
1924
+ stack: IS_PROD ? undefined : e.stack?.split(`
1925
+ `)
1926
+ }
1927
+ }, { status: 500 });
1926
1928
  }
1927
1929
  }
1928
1930
  };
1929
- processError(error);
1930
- return fieldErrors;
1931
- }
1932
-
1933
- // node_modules/@zod/core/dist/esm/parse.js
1934
- function _parse(schema, value, _ctx) {
1935
- const ctx = _ctx ? { ..._ctx, async: false } : { async: false };
1936
- const result = schema._zod.run({ value, issues: [] }, ctx);
1937
- if (result instanceof Promise) {
1938
- throw new $ZodAsyncError;
1939
- }
1940
- if (result.issues.length) {
1941
- throw new (this?.Error ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
1942
- }
1943
- return result.value;
1931
+ return api;
1944
1932
  }
1945
-
1946
- // node_modules/zod/dist/esm/errors.js
1947
- class ZodError extends $ZodError {
1948
- format(mapper) {
1949
- return formatError(this, mapper);
1933
+ function getRunnableRoute(route) {
1934
+ if (isRunnableRoute(route)) {
1935
+ return route;
1950
1936
  }
1951
- flatten(mapper) {
1952
- return flattenError(this, mapper);
1937
+ const kind = typeof route;
1938
+ if (kind === "function") {
1939
+ return createRoute(route);
1953
1940
  }
1954
- addIssue(issue) {
1955
- this.issues.push(issue);
1941
+ if (kind === "object" && "default" in route) {
1942
+ return getRunnableRoute(route.default);
1956
1943
  }
1957
- addIssues(issues) {
1958
- this.issues.push(...issues);
1959
- }
1960
- get isEmpty() {
1961
- return this.issues.length === 0;
1962
- }
1963
- }
1964
-
1965
- // node_modules/zod/dist/esm/parse.js
1966
- var parse = /* @__PURE__ */ _parse.bind({ Error: ZodError });
1967
-
1968
- // src/server.ts
1969
- var IS_PROD = false;
1970
- var CWD = process.cwd();
1971
- function createRoute(handler) {
1972
- return new HSRoute(handler);
1944
+ throw new Error('Route not runnable. Use "export default createRoute()" to create a Hyperspan route.');
1973
1945
  }
1974
- function createComponent(render2) {
1975
- return new HSComponent(render2);
1976
- }
1977
- function createForm(renderForm, schema) {
1978
- return new HSFormRoute(renderForm, schema);
1979
- }
1980
- var HS_DEFAULT_LOADING = () => html`<div>Loading...</div>`;
1981
-
1982
- class HSComponent {
1983
- _kind = "hsComponent";
1984
- _handlers = {};
1985
- _loading;
1986
- render;
1987
- constructor(render2) {
1988
- this.render = render2;
1989
- }
1990
- loading(fn) {
1991
- this._loading = fn;
1992
- return this;
1993
- }
1994
- }
1995
-
1996
- class HSRoute {
1997
- _kind = "hsRoute";
1998
- _handlers = {};
1999
- _methods = null;
2000
- constructor(handler) {
2001
- this._handlers.GET = handler;
2002
- }
2003
- }
2004
-
2005
- class HSFormRoute {
2006
- _kind = "hsFormRoute";
2007
- _handlers = {};
2008
- _form;
2009
- _methods = null;
2010
- _schema = null;
2011
- constructor(renderForm, schema = null) {
2012
- if (schema) {
2013
- this._form = renderForm;
2014
- this._schema = schema;
2015
- } else {
2016
- this._form = renderForm;
2017
- }
2018
- this._handlers.GET = () => renderForm(this.getDefaultData());
2019
- }
2020
- getDefaultData() {
2021
- if (!this._schema) {
2022
- return {};
2023
- }
2024
- const data = parse(this._schema, {});
2025
- return data;
2026
- }
2027
- renderForm(data) {
2028
- return this._form(data || this.getDefaultData());
2029
- }
2030
- get(handler) {
2031
- this._handlers.GET = handler;
2032
- return this;
2033
- }
2034
- patch(handler) {
2035
- this._handlers.PATCH = handler;
2036
- return this;
2037
- }
2038
- post(handler) {
2039
- this._handlers.POST = handler;
2040
- return this;
2041
- }
2042
- put(handler) {
2043
- this._handlers.PUT = handler;
2044
- return this;
2045
- }
2046
- delete(handler) {
2047
- this._handlers.DELETE = handler;
2048
- return this;
2049
- }
2050
- }
2051
- async function runFileRoute(RouteModule, context) {
2052
- const req = context.req;
2053
- const url = new URL(req.url);
2054
- const qs = url.searchParams;
2055
- const userIsBot = isbot(context.req.header("User-Agent"));
2056
- const streamOpt = qs.get("__nostream") ? !Boolean(qs.get("__nostream")) : undefined;
2057
- const streamingEnabled = !userIsBot && (streamOpt !== undefined ? streamOpt : true);
2058
- const RouteComponent = RouteModule.default;
2059
- const reqMethod = req.method.toUpperCase();
2060
- try {
2061
- if (RouteModule[reqMethod] !== undefined) {
2062
- return await runAPIRoute(RouteModule[reqMethod], context);
2063
- }
2064
- let routeContent;
2065
- if (!RouteComponent) {
2066
- throw new Error("No route was exported by default in matched route file.");
2067
- }
2068
- if (typeof RouteComponent._handlers !== "undefined") {
2069
- const routeMethodHandler = RouteComponent._handlers[reqMethod];
2070
- if (!routeMethodHandler) {
2071
- return new Response("Method Not Allowed", {
2072
- status: 405,
2073
- headers: { "content-type": "text/plain" }
2074
- });
2075
- }
2076
- routeContent = await routeMethodHandler(context);
2077
- } else {
2078
- routeContent = await RouteComponent(context);
2079
- }
2080
- if (routeContent instanceof Response) {
2081
- return routeContent;
2082
- }
2083
- let routeKind = typeof routeContent;
2084
- if (routeKind === "object" && (routeContent instanceof TmplHtml || routeContent.constructor.name === "TmplHtml" || routeContent?._kind === "TmplHtml")) {
2085
- if (streamingEnabled) {
2086
- return new StreamResponse(renderStream(routeContent));
2087
- } else {
2088
- const output = await renderAsync(routeContent);
2089
- return context.html(output);
2090
- }
2091
- }
2092
- console.log("Returning unknown type... ", routeContent);
2093
- return routeContent;
2094
- } catch (e) {
2095
- console.error(e);
2096
- return await showErrorReponse(context, e);
2097
- }
2098
- }
2099
- async function runAPIRoute(routeFn, context, middlewareResult) {
2100
- try {
2101
- return await routeFn(context, middlewareResult);
2102
- } catch (err) {
2103
- const e = err;
2104
- console.error(e);
2105
- return context.json({
2106
- meta: { success: false },
2107
- data: {
2108
- message: e.message,
2109
- stack: IS_PROD ? undefined : e.stack?.split(`
2110
- `)
2111
- }
2112
- }, { status: 500 });
2113
- }
1946
+ function isRunnableRoute(route) {
1947
+ return typeof route === "object" && "run" in route;
2114
1948
  }
2115
1949
  async function showErrorReponse(context, err) {
2116
1950
  const output = render(html`
@@ -2127,8 +1961,8 @@ async function showErrorReponse(context, err) {
2127
1961
  });
2128
1962
  }
2129
1963
  var ROUTE_SEGMENT = /(\[[a-zA-Z_\.]+\])/g;
2130
- async function buildRoutes(config2) {
2131
- const routesDir = join(config2.appDir, "routes");
1964
+ async function buildRoutes(config) {
1965
+ const routesDir = join(config.appDir, "routes");
2132
1966
  console.log(routesDir);
2133
1967
  const files = await readdir(routesDir, { recursive: true });
2134
1968
  const routes = [];
@@ -2163,25 +1997,34 @@ async function buildRoutes(config2) {
2163
1997
  }
2164
1998
  return routes;
2165
1999
  }
2166
- async function createServer(config2) {
2000
+ function createRouteFromModule(RouteModule) {
2001
+ return async (context) => {
2002
+ const reqMethod = context.req.method.toUpperCase();
2003
+ try {
2004
+ const runnableRoute = getRunnableRoute(RouteModule);
2005
+ const content = await runnableRoute.run(reqMethod, context);
2006
+ if (content instanceof Response) {
2007
+ return content;
2008
+ }
2009
+ return context.text(String(content));
2010
+ } catch (e) {
2011
+ console.error(e);
2012
+ return await showErrorReponse(context, e);
2013
+ }
2014
+ };
2015
+ }
2016
+ async function createServer(config) {
2167
2017
  await Promise.all([buildClientJS(), buildClientCSS()]);
2168
2018
  const app = new Hono2;
2169
- config2.beforeRoutesAdded && config2.beforeRoutesAdded(app);
2170
- const fileRoutes = await buildRoutes(config2);
2019
+ config.beforeRoutesAdded && config.beforeRoutesAdded(app);
2020
+ const fileRoutes = await buildRoutes(config);
2171
2021
  const routeMap = [];
2172
2022
  for (let i = 0;i < fileRoutes.length; i++) {
2173
2023
  let route = fileRoutes[i];
2174
2024
  const fullRouteFile = join(CWD, route.file);
2175
2025
  const routePattern = normalizePath(route.route);
2176
2026
  routeMap.push({ route: routePattern, file: route.file });
2177
- const routeModule = await import(fullRouteFile);
2178
- app.all(routePattern, async (context) => {
2179
- const matchedRoute = await runFileRoute(routeModule, context);
2180
- if (matchedRoute) {
2181
- return matchedRoute;
2182
- }
2183
- return context.notFound();
2184
- });
2027
+ app.all(routePattern, createRouteFromModule(await import(fullRouteFile)));
2185
2028
  }
2186
2029
  if (routeMap.length === 0) {
2187
2030
  app.get("/", (context) => {
@@ -2192,9 +2035,12 @@ async function createServer(config2) {
2192
2035
  console.log("[Hyperspan] File system routes (in app/routes):");
2193
2036
  console.table(routeMap);
2194
2037
  }
2195
- config2.afterRoutesAdded && config2.afterRoutesAdded(app);
2038
+ config.afterRoutesAdded && config.afterRoutesAdded(app);
2196
2039
  app.use("*", serveStatic2({
2197
- root: config2.staticFileRoot
2040
+ root: config.staticFileRoot,
2041
+ onFound: IS_PROD ? (_, c) => {
2042
+ c.header("Cache-Control", "public, max-age=2592000");
2043
+ } : undefined
2198
2044
  }));
2199
2045
  app.notFound((context) => {
2200
2046
  return context.text("Not... found?", { status: 404 });
@@ -2209,8 +2055,9 @@ class StreamResponse extends Response {
2209
2055
  return new Response(stream, {
2210
2056
  status: 200,
2211
2057
  headers: {
2212
- "Content-Type": "text/html",
2213
2058
  "Transfer-Encoding": "chunked",
2059
+ "Content-Type": "text/html; charset=UTF-8",
2060
+ "Content-Encoding": "Identity",
2214
2061
  ...options?.headers ?? {}
2215
2062
  },
2216
2063
  ...options
@@ -2236,18 +2083,15 @@ function normalizePath(urlPath) {
2236
2083
  return (urlPath.endsWith("/") ? urlPath.substring(0, urlPath.length - 1) : urlPath).toLowerCase() || "/";
2237
2084
  }
2238
2085
  export {
2239
- runFileRoute,
2240
2086
  normalizePath,
2087
+ isRunnableRoute,
2088
+ getRunnableRoute,
2241
2089
  createServer,
2090
+ createRouteFromModule,
2242
2091
  createRoute,
2243
2092
  createReadableStreamFromAsyncGenerator,
2244
- createForm,
2245
- createComponent,
2093
+ createAPIRoute,
2246
2094
  buildRoutes,
2247
2095
  StreamResponse,
2248
- IS_PROD,
2249
- HS_DEFAULT_LOADING,
2250
- HSRoute,
2251
- HSFormRoute,
2252
- HSComponent
2096
+ IS_PROD
2253
2097
  };