@netrojs/fnetro 0.2.21 → 0.3.0

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/core.js CHANGED
@@ -1,16 +1,55 @@
1
+ // types.ts
2
+ var SPA_HEADER = "x-fnetro-spa";
3
+ var STATE_KEY = "__FNETRO_STATE__";
4
+ var PARAMS_KEY = "__FNETRO_PARAMS__";
5
+ var SEO_KEY = "__FNETRO_SEO__";
6
+ var DATA_KEY = /* @__PURE__ */ Symbol.for("fnetro:data");
7
+
1
8
  // core.ts
9
+ var VUE_BRANDS = ["__name", "__file", "__vccOpts", "setup", "render", "data", "components"];
10
+ function isAsyncLoader(c) {
11
+ if (typeof c !== "function") return false;
12
+ const f = c;
13
+ for (const brand of VUE_BRANDS) {
14
+ if (brand in f) return false;
15
+ }
16
+ return true;
17
+ }
2
18
  function definePage(def) {
3
19
  return { __type: "page", ...def };
4
20
  }
5
21
  function defineGroup(def) {
6
22
  return { __type: "group", ...def };
7
23
  }
8
- function defineLayout(Component) {
9
- return { __type: "layout", Component };
24
+ function defineLayout(component) {
25
+ return { __type: "layout", component };
10
26
  }
11
27
  function defineApiRoute(path, register) {
12
28
  return { __type: "api", path, register };
13
29
  }
30
+ function compilePath(path) {
31
+ const keys = [];
32
+ const src = path.replace(/\[\.\.\.([^\]]+)\]/g, (_, k) => {
33
+ keys.push(k);
34
+ return "(.*)";
35
+ }).replace(/\[([^\]]+)\]/g, (_, k) => {
36
+ keys.push(k);
37
+ return "([^/]+)";
38
+ }).replace(/\*/g, "(.*)");
39
+ return { re: new RegExp(`^${src}$`), keys };
40
+ }
41
+ function matchPath(cp, pathname) {
42
+ const m = pathname.match(cp.re);
43
+ if (!m) return null;
44
+ const params = {};
45
+ cp.keys.forEach((k, i) => {
46
+ params[k] = decodeURIComponent(m[i + 1] ?? "");
47
+ });
48
+ return params;
49
+ }
50
+ function toVueRouterPath(fnetroPath) {
51
+ return fnetroPath.replace(/\[\.\.\.([^\]]+)\]/g, ":$1(.*)*").replace(/\[([^\]]+)\]/g, ":$1");
52
+ }
14
53
  function resolveRoutes(routes, options = {}) {
15
54
  const pages = [];
16
55
  const apis = [];
@@ -21,7 +60,11 @@ function resolveRoutes(routes, options = {}) {
21
60
  const prefix = (options.prefix ?? "") + route.prefix;
22
61
  const mw = [...options.middleware ?? [], ...route.middleware ?? []];
23
62
  const layout = route.layout !== void 0 ? route.layout : options.layout;
24
- const sub = resolveRoutes(route.routes, { prefix, middleware: mw, layout });
63
+ const sub = resolveRoutes(route.routes, {
64
+ prefix,
65
+ middleware: mw,
66
+ ...layout !== void 0 && { layout }
67
+ });
25
68
  pages.push(...sub.pages);
26
69
  apis.push(...sub.apis);
27
70
  } else {
@@ -35,31 +78,8 @@ function resolveRoutes(routes, options = {}) {
35
78
  }
36
79
  return { pages, apis };
37
80
  }
38
- function compilePath(path) {
39
- const keys = [];
40
- const src = path.replace(/\[\.\.\.([^\]]+)\]/g, (_, k) => {
41
- keys.push(k);
42
- return "(.*)";
43
- }).replace(/\[([^\]]+)\]/g, (_, k) => {
44
- keys.push(k);
45
- return "([^/]+)";
46
- }).replace(/\*/g, "(.*)");
47
- return { re: new RegExp(`^${src}$`), keys };
48
- }
49
- function matchPath(compiled, pathname) {
50
- const m = pathname.match(compiled.re);
51
- if (!m) return null;
52
- const params = {};
53
- compiled.keys.forEach((k, i) => {
54
- params[k] = decodeURIComponent(m[i + 1] ?? "");
55
- });
56
- return params;
57
- }
58
- var SPA_HEADER = "x-fnetro-spa";
59
- var STATE_KEY = "__FNETRO_STATE__";
60
- var PARAMS_KEY = "__FNETRO_PARAMS__";
61
- var SEO_KEY = "__FNETRO_SEO__";
62
81
  export {
82
+ DATA_KEY,
63
83
  PARAMS_KEY,
64
84
  SEO_KEY,
65
85
  SPA_HEADER,
@@ -69,6 +89,8 @@ export {
69
89
  defineGroup,
70
90
  defineLayout,
71
91
  definePage,
92
+ isAsyncLoader,
72
93
  matchPath,
73
- resolveRoutes
94
+ resolveRoutes,
95
+ toVueRouterPath
74
96
  };
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Hono, MiddlewareHandler, Context } from 'hono';
2
- import { Component, JSX } from 'solid-js';
2
+ import { Component } from 'vue';
3
3
  import { Plugin } from 'vite';
4
4
 
5
5
  type HonoMiddleware = MiddlewareHandler;
@@ -16,44 +16,33 @@ interface SEOMeta {
16
16
  ogDescription?: string;
17
17
  ogImage?: string;
18
18
  ogImageAlt?: string;
19
- ogImageWidth?: string;
20
- ogImageHeight?: string;
21
19
  ogUrl?: string;
22
20
  ogType?: string;
23
21
  ogSiteName?: string;
24
- ogLocale?: string;
25
22
  twitterCard?: 'summary' | 'summary_large_image' | 'app' | 'player';
26
23
  twitterSite?: string;
27
- twitterCreator?: string;
28
24
  twitterTitle?: string;
29
25
  twitterDescription?: string;
30
26
  twitterImage?: string;
31
- twitterImageAlt?: string;
27
+ /** Structured data injected as <script type="application/ld+json">. */
32
28
  jsonLd?: Record<string, unknown> | Record<string, unknown>[];
33
- extra?: Array<{
34
- name?: string;
35
- property?: string;
36
- httpEquiv?: string;
37
- content: string;
38
- }>;
39
29
  }
40
- type PageProps<TData extends object = {}> = TData & {
41
- url: string;
42
- params: Record<string, string>;
43
- };
44
- interface LayoutProps {
45
- children: JSX.Element;
46
- url: string;
47
- params: Record<string, string>;
48
- }
49
- interface PageDef<TData extends object = {}> {
30
+ type AsyncLoader = () => Promise<{
31
+ default: Component;
32
+ } | Component>;
33
+ interface PageDef<TData extends object = Record<string, never>> {
50
34
  readonly __type: 'page';
51
35
  path: string;
52
36
  middleware?: HonoMiddleware[];
53
37
  loader?: (c: LoaderCtx) => TData | Promise<TData>;
54
38
  seo?: SEOMeta | ((data: TData, params: Record<string, string>) => SEOMeta);
39
+ /** Override or disable the app-level layout for this route. */
55
40
  layout?: LayoutDef | false;
56
- Page: Component<PageProps<TData>>;
41
+ /**
42
+ * The Vue component to render for this route.
43
+ * Use () => import('./Page.vue') for automatic code splitting.
44
+ */
45
+ component: Component | AsyncLoader;
57
46
  }
58
47
  interface GroupDef {
59
48
  readonly __type: 'group';
@@ -64,7 +53,8 @@ interface GroupDef {
64
53
  }
65
54
  interface LayoutDef {
66
55
  readonly __type: 'layout';
67
- Component: Component<LayoutProps>;
56
+ /** Vue layout component — must contain <slot /> for page content. */
57
+ component: Component;
68
58
  }
69
59
  interface ApiRouteDef {
70
60
  readonly __type: 'api';
@@ -79,66 +69,79 @@ interface AppConfig {
79
69
  routes: Route[];
80
70
  notFound?: Component;
81
71
  htmlAttrs?: Record<string, string>;
72
+ /** Extra HTML injected into <head> (e.g. font preloads). */
82
73
  head?: string;
83
74
  }
84
- type ClientMiddleware = (url: string, next: () => Promise<void>) => Promise<void>;
85
- declare function definePage<TData extends object = {}>(def: Omit<PageDef<TData>, '__type'>): PageDef<TData>;
86
- declare function defineGroup(def: Omit<GroupDef, '__type'>): GroupDef;
87
- declare function defineLayout(Component: Component<LayoutProps>): LayoutDef;
88
- declare function defineApiRoute(path: string, register: ApiRouteDef['register']): ApiRouteDef;
89
75
  interface ResolvedRoute {
90
76
  fullPath: string;
91
77
  page: PageDef<any>;
92
78
  layout: LayoutDef | false | undefined;
93
79
  middleware: HonoMiddleware[];
94
80
  }
95
- declare function resolveRoutes(routes: Route[], options?: {
96
- prefix?: string;
97
- middleware?: HonoMiddleware[];
98
- layout?: LayoutDef | false;
99
- }): {
100
- pages: ResolvedRoute[];
101
- apis: ApiRouteDef[];
102
- };
103
81
  interface CompiledPath {
104
82
  re: RegExp;
105
83
  keys: string[];
106
84
  }
107
- declare function compilePath(path: string): CompiledPath;
108
- declare function matchPath(compiled: CompiledPath, pathname: string): Record<string, string> | null;
85
+ type ClientMiddleware = (url: string, next: () => Promise<void>) => Promise<void>;
86
+ /** Custom request header that identifies an SPA navigation (JSON payload). */
109
87
  declare const SPA_HEADER = "x-fnetro-spa";
88
+ /** window key for SSR-injected per-page loader data. */
110
89
  declare const STATE_KEY = "__FNETRO_STATE__";
90
+ /** window key for SSR-injected URL params. */
111
91
  declare const PARAMS_KEY = "__FNETRO_PARAMS__";
92
+ /** window key for SSR-injected SEO meta. */
112
93
  declare const SEO_KEY = "__FNETRO_SEO__";
94
+ /**
95
+ * Vue provide/inject key for the reactive page-data object.
96
+ * Symbol.for() ensures the same reference across module instances (SSR safe).
97
+ */
98
+ declare const DATA_KEY: unique symbol;
99
+
100
+ /**
101
+ * Returns true when `c` is an async factory function (i.e. `() => import(...)`)
102
+ * rather than a resolved Vue component object.
103
+ *
104
+ * Used by both server.ts (to resolve the import before SSR) and client.ts
105
+ * (to wrap with defineAsyncComponent for lazy hydration).
106
+ */
107
+ declare function isAsyncLoader(c: unknown): c is AsyncLoader;
108
+ declare function definePage<TData extends object = Record<string, never>>(def: Omit<PageDef<TData>, '__type'>): PageDef<TData>;
109
+ declare function defineGroup(def: Omit<GroupDef, '__type'>): GroupDef;
110
+ /** Wrap a Vue layout component (must render <slot />) as a FNetro layout. */
111
+ declare function defineLayout(component: Component): LayoutDef;
112
+ declare function defineApiRoute(path: string, register: ApiRouteDef['register']): ApiRouteDef;
113
+ declare function compilePath(path: string): CompiledPath;
114
+ declare function matchPath(cp: CompiledPath, pathname: string): Record<string, string> | null;
115
+ /**
116
+ * Convert FNetro `[param]` syntax to Vue Router `:param` syntax.
117
+ *
118
+ * `/posts/[slug]` → `/posts/:slug`
119
+ * `/files/[...path]` → `/files/:path(.*)*`
120
+ */
121
+ declare function toVueRouterPath(fnetroPath: string): string;
122
+ declare function resolveRoutes(routes: Route[], options?: {
123
+ prefix?: string;
124
+ middleware?: HonoMiddleware[];
125
+ layout?: LayoutDef | false;
126
+ }): {
127
+ pages: ResolvedRoute[];
128
+ apis: ApiRouteDef[];
129
+ };
113
130
 
114
131
  interface AssetConfig {
115
- /** Explicit script URLs injected into every HTML page. */
116
132
  scripts?: string[];
117
- /** Explicit stylesheet URLs injected into every HTML page. */
118
133
  styles?: string[];
119
- /**
120
- * Directory that contains the Vite-generated `manifest.json`.
121
- * When provided, asset URLs are resolved from the manifest so hashed
122
- * filenames work correctly. Typically equals `clientOutDir`.
123
- */
134
+ /** Directory containing the Vite-built assets and .vite/manifest.json. */
124
135
  manifestDir?: string;
125
- /**
126
- * Key in the manifest corresponding to the client entry file.
127
- * @default `'client.ts'`
128
- */
129
136
  manifestEntry?: string;
130
137
  }
131
138
  interface FNetroOptions extends AppConfig {
132
- /**
133
- * Production asset configuration.
134
- * In dev mode `@hono/vite-dev-server` injects assets automatically — ignored.
135
- */
136
139
  assets?: AssetConfig;
137
140
  }
138
141
  interface FNetroApp {
139
- /** The underlying Hono instance — attach custom routes, error handlers, etc. */
142
+ /** The Hono instance — attach extra routes, error handlers, middleware. */
140
143
  app: Hono;
141
- /** Fetch handler for edge runtimes */
144
+ /** WinterCG-compatible fetch handler for edge runtimes. */
142
145
  handler: typeof Hono.prototype.fetch;
143
146
  }
144
147
  declare function createFNetro(config: FNetroOptions): FNetroApp;
@@ -149,24 +152,24 @@ interface ServeOptions {
149
152
  port?: number;
150
153
  hostname?: string;
151
154
  runtime?: Runtime;
152
- /** Root directory for static file serving. @default `'./dist'` */
155
+ /** Root directory that contains the built assets and public files. */
153
156
  staticDir?: string;
154
157
  }
155
158
  declare function serve(opts: ServeOptions): Promise<void>;
156
159
  interface FNetroPluginOptions {
157
- /** Server entry file. @default `'server.ts'` */
160
+ /** Server entry file. @default 'server.ts' */
158
161
  serverEntry?: string;
159
- /** Client entry file. @default `'client.ts'` */
162
+ /** Client entry file. @default 'client.ts' */
160
163
  clientEntry?: string;
161
- /** Server bundle output directory. @default `'dist/server'` */
164
+ /** Server bundle output dir. @default 'dist/server' */
162
165
  serverOutDir?: string;
163
- /** Client assets output directory. @default `'dist/assets'` */
166
+ /** Client assets output dir. @default 'dist/assets' */
164
167
  clientOutDir?: string;
165
- /** Extra packages to mark external in the server bundle. */
168
+ /** Extra packages external to the server bundle. */
166
169
  serverExternal?: string[];
167
- /** Extra options forwarded to `vite-plugin-solid`. */
168
- solidOptions?: Record<string, unknown>;
170
+ /** Options forwarded to @vitejs/plugin-vue in the client build. */
171
+ vueOptions?: Record<string, unknown>;
169
172
  }
170
- declare function fnetroVitePlugin(opts?: FNetroPluginOptions): Plugin[];
173
+ declare function fnetroVitePlugin(opts?: FNetroPluginOptions): Plugin;
171
174
 
172
- export { type ApiRouteDef, type AppConfig, type AssetConfig, type ClientMiddleware, type CompiledPath, type FNetroApp, type FNetroOptions, type FNetroPluginOptions, type GroupDef, type HonoMiddleware, type LayoutDef, type LayoutProps, type LoaderCtx, PARAMS_KEY, type PageDef, type PageProps, type ResolvedRoute, type Route, type Runtime, type SEOMeta, SEO_KEY, SPA_HEADER, STATE_KEY, type ServeOptions, compilePath, createFNetro, defineApiRoute, defineGroup, defineLayout, definePage, detectRuntime, fnetroVitePlugin, matchPath, resolveRoutes, serve };
175
+ export { type ApiRouteDef, type AppConfig, type AssetConfig, type AsyncLoader, type ClientMiddleware, type CompiledPath, DATA_KEY, type FNetroApp, type FNetroOptions, type FNetroPluginOptions, type GroupDef, type HonoMiddleware, type LayoutDef, type LoaderCtx, PARAMS_KEY, type PageDef, type ResolvedRoute, type Route, type Runtime, type SEOMeta, SEO_KEY, SPA_HEADER, STATE_KEY, type ServeOptions, compilePath, createFNetro, defineApiRoute, defineGroup, defineLayout, definePage, detectRuntime, fnetroVitePlugin, isAsyncLoader, matchPath, resolveRoutes, serve, toVueRouterPath };