olova 2.0.21 → 2.0.23

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/index.d.ts CHANGED
@@ -1,13 +1,86 @@
1
- import * as React from 'react';
2
- export { default as Link } from './Link.js';
3
- export { ReadonlyURLSearchParams, default as useSearchParams } from './useSearchParams.js';
4
- export { default as usePathname } from './usePathname.js';
5
- export { default as useParams, usePath } from './useParams.js';
6
- export { Metadata, Router, loadRoute, matchRoute } from './Router.js';
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React, { ReactNode } from 'react';
7
3
 
8
- declare const RouterContext: React.Context<{
4
+ declare function useParams(): Record<string, string>;
5
+ /**
6
+ * Returns the current pathname (without query string or hash)
7
+ * Similar to Next.js usePathname hook
8
+ */
9
+ declare function usePathname(): string;
10
+ /**
11
+ * A read-only interface for URLSearchParams
12
+ * Similar to Next.js useSearchParams hook
13
+ */
14
+ interface ReadonlyURLSearchParams {
15
+ get(name: string): string | null;
16
+ getAll(name: string): string[];
17
+ has(name: string): boolean;
18
+ keys(): IterableIterator<string>;
19
+ values(): IterableIterator<string>;
20
+ entries(): IterableIterator<[string, string]>;
21
+ forEach(callback: (value: string, key: string, parent: URLSearchParams) => void): void;
22
+ toString(): string;
23
+ size: number;
24
+ }
25
+ /**
26
+ * Returns the current URL search parameters
27
+ * Similar to Next.js useSearchParams hook
28
+ *
29
+ * Example usage:
30
+ * const searchParams = useSearchParams();
31
+ * const query = searchParams.get('q'); // ?q=hello -> 'hello'
32
+ * const tags = searchParams.getAll('tag'); // ?tag=a&tag=b -> ['a', 'b']
33
+ */
34
+ declare function useSearchParams(): ReadonlyURLSearchParams;
35
+ declare function matchRoute(path: string): {
36
+ loader: any;
9
37
  params: Record<string, string>;
10
- path: string;
11
- }>;
38
+ pattern: string;
39
+ } | null;
40
+ interface Metadata {
41
+ title?: string;
42
+ description?: string;
43
+ keywords?: string | string[];
44
+ openGraph?: {
45
+ title?: string;
46
+ description?: string;
47
+ url?: string;
48
+ siteName?: string;
49
+ images?: {
50
+ url: string;
51
+ width?: number;
52
+ height?: number;
53
+ alt?: string;
54
+ }[];
55
+ type?: string;
56
+ };
57
+ twitter?: {
58
+ card?: 'summary' | 'summary_large_image' | 'app' | 'player';
59
+ site?: string;
60
+ creator?: string;
61
+ title?: string;
62
+ description?: string;
63
+ images?: string[];
64
+ };
65
+ robots?: string;
66
+ canonical?: string;
67
+ jsonLd?: object | object[];
68
+ }
69
+ declare function loadRoute(path: string): Promise<{
70
+ module: any;
71
+ params: Record<string, string>;
72
+ metadata: Metadata | undefined;
73
+ } | null>;
74
+ interface RouterProps {
75
+ url?: string;
76
+ initialComponent?: React.ComponentType;
77
+ initialParams?: Record<string, string>;
78
+ onRouteChange?: (metadata: Metadata | undefined) => void;
79
+ }
80
+ declare function Router({ url, initialComponent, initialParams, onRouteChange }: RouterProps): react_jsx_runtime.JSX.Element;
81
+ declare function Link({ href, children, ...props }: {
82
+ href: string;
83
+ children: ReactNode;
84
+ } & React.AnchorHTMLAttributes<HTMLAnchorElement>): React.ReactElement;
12
85
 
13
- export { RouterContext };
86
+ export { Link as L, type Metadata, Router as R, usePathname as a, useSearchParams as b, loadRoute as l, matchRoute as m, useParams as u };
package/dist/index.js CHANGED
@@ -1,32 +1 @@
1
- import {
2
- Link
3
- } from "./chunk-CYX762OE.js";
4
- import {
5
- Router,
6
- loadRoute,
7
- matchRoute
8
- } from "./chunk-Y3CEUWVD.js";
9
- import {
10
- useParams,
11
- usePath
12
- } from "./chunk-K6EDUQDD.js";
13
- import {
14
- RouterContext
15
- } from "./chunk-LOK5UEME.js";
16
- import {
17
- usePathname
18
- } from "./chunk-XGX5YRJV.js";
19
- import {
20
- useSearchParams
21
- } from "./chunk-NEMX72XA.js";
22
- export {
23
- Link,
24
- Router,
25
- RouterContext,
26
- loadRoute,
27
- matchRoute,
28
- useParams,
29
- usePath,
30
- usePathname,
31
- useSearchParams
32
- };
1
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,3 @@
1
+ export { L as Link, Metadata, R as Router, l as loadRoute, m as matchRoute, u as useParams, a as usePathname, b as useSearchParams } from './index.js';
2
+ import 'react/jsx-runtime';
3
+ import 'react';
@@ -1,25 +1,60 @@
1
- import {
2
- RouterContext
3
- } from "./chunk-LOK5UEME.js";
4
-
5
- // Router.tsx
6
- import React, { useState, useEffect } from "react";
7
- import { routes } from "virtual:olova-routes";
8
- function parseMarkdown(md) {
9
- return md.replace(/^### (.*$)/gim, "<h3>$1</h3>").replace(/^## (.*$)/gim, "<h2>$1</h2>").replace(/^# (.*$)/gim, "<h1>$1</h1>").replace(/\*\*\*(.*?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>").replace(/\*(.*?)\*/g, "<em>$1</em>").replace(/```([\s\S]*?)```/g, "<pre><code>$1</code></pre>").replace(/`(.*?)`/g, "<code>$1</code>").replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>').replace(/\n\n/g, "</p><p>").replace(/\n/g, "<br>").replace(/^(.*)$/, "<p>$1</p>");
1
+ // src/client/router.tsx
2
+ import React, { useState, useEffect, createContext, useContext } from "react";
3
+ import { routes } from "olova/routes";
4
+ import { jsx } from "react/jsx-runtime";
5
+ var RouterContext = createContext({ params: {}, path: "/" });
6
+ function useParams() {
7
+ return useContext(RouterContext).params;
10
8
  }
11
- function HtmlContent({ html }) {
12
- return React.createElement("div", {
13
- dangerouslySetInnerHTML: { __html: html },
14
- className: "olova-html-content"
9
+ function usePathname() {
10
+ const [pathname, setPathname] = useState(() => {
11
+ if (typeof window === "undefined") return "/";
12
+ return window.location.pathname;
15
13
  });
14
+ useEffect(() => {
15
+ if (typeof window === "undefined") return;
16
+ const handleNavigation = () => {
17
+ setPathname(window.location.pathname);
18
+ };
19
+ window.addEventListener("popstate", handleNavigation);
20
+ window.addEventListener("pushstate", handleNavigation);
21
+ return () => {
22
+ window.removeEventListener("popstate", handleNavigation);
23
+ window.removeEventListener("pushstate", handleNavigation);
24
+ };
25
+ }, []);
26
+ return pathname;
16
27
  }
17
- function MarkdownContent({ markdown }) {
18
- const html = parseMarkdown(markdown);
19
- return React.createElement("article", {
20
- dangerouslySetInnerHTML: { __html: html },
21
- className: "olova-markdown-content"
28
+ function useSearchParams() {
29
+ const [searchParams, setSearchParams] = useState(() => {
30
+ if (typeof window === "undefined") return new URLSearchParams();
31
+ return new URLSearchParams(window.location.search);
22
32
  });
33
+ useEffect(() => {
34
+ if (typeof window === "undefined") return;
35
+ const handleNavigation = () => {
36
+ setSearchParams(new URLSearchParams(window.location.search));
37
+ };
38
+ window.addEventListener("popstate", handleNavigation);
39
+ window.addEventListener("pushstate", handleNavigation);
40
+ return () => {
41
+ window.removeEventListener("popstate", handleNavigation);
42
+ window.removeEventListener("pushstate", handleNavigation);
43
+ };
44
+ }, []);
45
+ return {
46
+ get: (name) => searchParams.get(name),
47
+ getAll: (name) => searchParams.getAll(name),
48
+ has: (name) => searchParams.has(name),
49
+ keys: () => searchParams.keys(),
50
+ values: () => searchParams.values(),
51
+ entries: () => searchParams.entries(),
52
+ forEach: (callback) => searchParams.forEach(callback),
53
+ toString: () => searchParams.toString(),
54
+ get size() {
55
+ return Array.from(searchParams.keys()).length;
56
+ }
57
+ };
23
58
  }
24
59
  var normalizePath = (path) => {
25
60
  let p = path.split("?")[0].split("#")[0];
@@ -47,6 +82,22 @@ function matchRoute(path) {
47
82
  }
48
83
  return null;
49
84
  }
85
+ function parseMarkdown(md) {
86
+ return md.replace(/^### (.*$)/gim, "<h3>$1</h3>").replace(/^## (.*$)/gim, "<h2>$1</h2>").replace(/^# (.*$)/gim, "<h1>$1</h1>").replace(/\*\*\*(.*?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>").replace(/\*(.*?)\*/g, "<em>$1</em>").replace(/```([\s\S]*?)```/g, "<pre><code>$1</code></pre>").replace(/`(.*?)`/g, "<code>$1</code>").replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>').replace(/\n\n/g, "</p><p>").replace(/\n/g, "<br>").replace(/^(.*)$/, "<p>$1</p>");
87
+ }
88
+ function HtmlContent({ html }) {
89
+ return React.createElement("div", {
90
+ dangerouslySetInnerHTML: { __html: html },
91
+ className: "olova-html-content"
92
+ });
93
+ }
94
+ function MarkdownContent({ markdown }) {
95
+ const html = parseMarkdown(markdown);
96
+ return React.createElement("article", {
97
+ dangerouslySetInnerHTML: { __html: html },
98
+ className: "olova-markdown-content"
99
+ });
100
+ }
50
101
  async function loadRoute(path) {
51
102
  const match = matchRoute(path);
52
103
  if (match) {
@@ -124,7 +175,7 @@ function Router({ url, initialComponent, initialParams, onRouteChange }) {
124
175
  onRouteChange(fallbackResult.metadata);
125
176
  }
126
177
  } else {
127
- setComponent(() => () => React.createElement("div", null, "404 Not Found"));
178
+ setComponent(() => () => /* @__PURE__ */ jsx("div", { children: "404 Not Found" }));
128
179
  setParams({});
129
180
  if (onRouteChange) {
130
181
  onRouteChange(void 0);
@@ -138,16 +189,29 @@ function Router({ url, initialComponent, initialParams, onRouteChange }) {
138
189
  isCancelled = true;
139
190
  };
140
191
  }, [path, onRouteChange]);
141
- if (!Component) return React.createElement("div", null, "Loading...");
142
- return React.createElement(
143
- RouterContext.Provider,
144
- { value: { params, path } },
145
- React.createElement(Component, params)
146
- );
192
+ if (!Component) return /* @__PURE__ */ jsx("div", { children: "Loading..." });
193
+ return /* @__PURE__ */ jsx(RouterContext.Provider, { value: { params, path }, children: /* @__PURE__ */ jsx(Component, { ...params }) });
194
+ }
195
+ function Link({ href, children, ...props }) {
196
+ const handleClick = (e) => {
197
+ if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
198
+ if (href.startsWith("http") || href.startsWith("//")) return;
199
+ e.preventDefault();
200
+ const currentUrl = window.location.pathname + window.location.search;
201
+ const targetUrl = href.startsWith("/") ? href : "/" + href;
202
+ if (currentUrl === targetUrl) return;
203
+ window.history.pushState({}, "", href);
204
+ window.dispatchEvent(new Event("pushstate"));
205
+ };
206
+ return /* @__PURE__ */ jsx("a", { href, onClick: handleClick, ...props, children });
147
207
  }
148
-
149
208
  export {
150
- matchRoute,
209
+ Link,
210
+ Router,
151
211
  loadRoute,
152
- Router
212
+ matchRoute,
213
+ useParams,
214
+ usePathname,
215
+ useSearchParams
153
216
  };
217
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/router.tsx"],"sourcesContent":["import React, { useState, useEffect, createContext, useContext, type ReactNode } from 'react';\n\n// @ts-ignore\nimport { routes } from 'olova/routes';\n\nconst RouterContext = createContext<{ params: Record<string, string>, path: string }>({ params: {}, path: '/' });\n\nexport function useParams() {\n return useContext(RouterContext).params;\n}\n\nexport function usePath() {\n return useContext(RouterContext).path;\n}\n\n/**\n * Returns the current pathname (without query string or hash)\n * Similar to Next.js usePathname hook\n */\nexport function usePathname(): string {\n const [pathname, setPathname] = useState(() => {\n if (typeof window === 'undefined') return '/';\n return window.location.pathname;\n });\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const handleNavigation = () => {\n setPathname(window.location.pathname);\n };\n\n window.addEventListener('popstate', handleNavigation);\n window.addEventListener('pushstate', handleNavigation);\n\n return () => {\n window.removeEventListener('popstate', handleNavigation);\n window.removeEventListener('pushstate', handleNavigation);\n };\n }, []);\n\n return pathname;\n}\n\n/**\n * A read-only interface for URLSearchParams\n * Similar to Next.js useSearchParams hook\n */\ninterface ReadonlyURLSearchParams {\n get(name: string): string | null;\n getAll(name: string): string[];\n has(name: string): boolean;\n keys(): IterableIterator<string>;\n values(): IterableIterator<string>;\n entries(): IterableIterator<[string, string]>;\n forEach(callback: (value: string, key: string, parent: URLSearchParams) => void): void;\n toString(): string;\n size: number;\n}\n\n/**\n * Returns the current URL search parameters\n * Similar to Next.js useSearchParams hook\n * \n * Example usage:\n * const searchParams = useSearchParams();\n * const query = searchParams.get('q'); // ?q=hello -> 'hello'\n * const tags = searchParams.getAll('tag'); // ?tag=a&tag=b -> ['a', 'b']\n */\nexport function useSearchParams(): ReadonlyURLSearchParams {\n const [searchParams, setSearchParams] = useState<URLSearchParams>(() => {\n if (typeof window === 'undefined') return new URLSearchParams();\n return new URLSearchParams(window.location.search);\n });\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const handleNavigation = () => {\n setSearchParams(new URLSearchParams(window.location.search));\n };\n\n window.addEventListener('popstate', handleNavigation);\n window.addEventListener('pushstate', handleNavigation);\n\n return () => {\n window.removeEventListener('popstate', handleNavigation);\n window.removeEventListener('pushstate', handleNavigation);\n };\n }, []);\n\n // Return a readonly interface that wraps URLSearchParams\n return {\n get: (name: string) => searchParams.get(name),\n getAll: (name: string) => searchParams.getAll(name),\n has: (name: string) => searchParams.has(name),\n keys: () => searchParams.keys(),\n values: () => searchParams.values(),\n entries: () => searchParams.entries(),\n forEach: (callback) => searchParams.forEach(callback),\n toString: () => searchParams.toString(),\n get size() { return Array.from(searchParams.keys()).length; }\n };\n}\n\n// Helper to normalize paths\nconst normalizePath = (path: string) => {\n let p = path.split('?')[0].split('#')[0];\n if (p.length > 1 && p.endsWith('/')) p = p.slice(0, -1);\n return p || '/';\n};\n\n// Route matching with param extraction\nexport function matchRoute(path: string) {\n const normalizedPath = normalizePath(path);\n const routeKeys = Object.keys(routes);\n \n for (const route of routeKeys) {\n // Handle exact match first\n if (route === normalizedPath) {\n return { loader: routes[route], params: {}, pattern: route };\n }\n \n // Convert :param and $param to regex group\n const regexPath = route\n .replace(/:[^\\/]+/g, '([^/]+)')\n .replace(/\\$[^\\/]+/g, '([^/]+)');\n \n const regex = new RegExp(`^${regexPath}$`);\n const match = normalizedPath.match(regex);\n \n if (match) {\n const params: Record<string, string> = {};\n const paramNames = (route.match(/[:$][^\\/]+/g) || []).map(s => s.slice(1));\n paramNames.forEach((name, i) => {\n params[name] = match[i + 1];\n });\n return { loader: routes[route], params, pattern: route };\n }\n }\n return null;\n}\n\n// Metadata type - like Next.js\nexport interface Metadata {\n title?: string;\n description?: string;\n keywords?: string | string[];\n openGraph?: {\n title?: string;\n description?: string;\n url?: string;\n siteName?: string;\n images?: { url: string; width?: number; height?: number; alt?: string }[];\n type?: string;\n };\n twitter?: {\n card?: 'summary' | 'summary_large_image' | 'app' | 'player';\n site?: string;\n creator?: string;\n title?: string;\n description?: string;\n images?: string[];\n };\n robots?: string;\n canonical?: string;\n jsonLd?: object | object[];\n}\n\n// Simple markdown to HTML converter (basic support)\nfunction parseMarkdown(md: string): string {\n return md\n // Headers\n .replace(/^### (.*$)/gim, '<h3>$1</h3>')\n .replace(/^## (.*$)/gim, '<h2>$1</h2>')\n .replace(/^# (.*$)/gim, '<h1>$1</h1>')\n // Bold and italic\n .replace(/\\*\\*\\*(.*?)\\*\\*\\*/g, '<strong><em>$1</em></strong>')\n .replace(/\\*\\*(.*?)\\*\\*/g, '<strong>$1</strong>')\n .replace(/\\*(.*?)\\*/g, '<em>$1</em>')\n // Code blocks\n .replace(/```([\\s\\S]*?)```/g, '<pre><code>$1</code></pre>')\n .replace(/`(.*?)`/g, '<code>$1</code>')\n // Links\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\">$1</a>')\n // Line breaks and paragraphs\n .replace(/\\n\\n/g, '</p><p>')\n .replace(/\\n/g, '<br>')\n // Wrap in paragraph\n .replace(/^(.*)$/, '<p>$1</p>');\n}\n\n// React component for rendering HTML content\nfunction HtmlContent({ html }: { html: string }) {\n return React.createElement('div', { \n dangerouslySetInnerHTML: { __html: html },\n className: 'olova-html-content'\n });\n}\n\n// React component for rendering Markdown content\nfunction MarkdownContent({ markdown }: { markdown: string }) {\n const html = parseMarkdown(markdown);\n return React.createElement('article', { \n dangerouslySetInnerHTML: { __html: html },\n className: 'olova-markdown-content'\n });\n}\n\nexport async function loadRoute(path: string) {\n const match = matchRoute(path);\n if (match) {\n console.log(`[Router] Loading route: ${path} (pattern: ${match.pattern})`);\n const module = await match.loader();\n \n // Handle HTML files\n if (module.__isHtml) {\n return { \n module: {\n default: () => HtmlContent({ html: module.__rawHtml }),\n },\n params: match.params,\n metadata: undefined\n };\n }\n \n // Handle Markdown files\n if (module.__isMd) {\n return { \n module: {\n default: () => MarkdownContent({ markdown: module.default }),\n },\n params: match.params,\n metadata: undefined\n };\n }\n \n return { \n module,\n params: match.params,\n metadata: module.metadata as Metadata | undefined\n };\n }\n console.warn(`[Router] No match for: ${path}`);\n return null;\n}\n\ninterface RouterProps {\n url?: string;\n initialComponent?: React.ComponentType;\n initialParams?: Record<string, string>;\n onRouteChange?: (metadata: Metadata | undefined) => void;\n}\n\nexport function Router({ url, initialComponent, initialParams, onRouteChange }: RouterProps) {\n const [path, setPath] = useState(() => normalizePath(url || (typeof window !== 'undefined' ? window.location.pathname : '/')));\n const [Component, setComponent] = useState<React.ComponentType | null>(() => initialComponent || null);\n const [params, setParams] = useState<Record<string, string>>(() => initialParams || {});\n const hasHydrated = React.useRef(false);\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const handleNavigation = () => {\n const newPath = normalizePath(window.location.pathname);\n console.log(`[Router] Navigation event: ${newPath}`);\n setPath(newPath);\n };\n\n window.addEventListener('popstate', handleNavigation);\n window.addEventListener('pushstate', handleNavigation);\n\n return () => {\n window.removeEventListener('popstate', handleNavigation);\n window.removeEventListener('pushstate', handleNavigation);\n };\n }, []);\n\n useEffect(() => {\n // Skip loading on mount if we already have the initial component for the current path\n if (!hasHydrated.current && initialComponent && path === normalizePath(url || '')) {\n console.log(`[Router] Hydration skipped for: ${path}`);\n hasHydrated.current = true;\n return;\n }\n\n let isCancelled = false;\n const load = async () => {\n const result = await loadRoute(path);\n if (!isCancelled) {\n if (result) {\n setComponent(() => result.module.default);\n setParams(result.params);\n // Call onRouteChange with new metadata for SEO updates\n if (onRouteChange) {\n onRouteChange(result.metadata);\n }\n } else {\n // Try to load custom 404 page\n const fallbackResult = await loadRoute('/404');\n if (fallbackResult) {\n console.log('[Router] Serving custom 404 page');\n setComponent(() => fallbackResult.module.default);\n setParams(fallbackResult.params);\n if (onRouteChange) {\n onRouteChange(fallbackResult.metadata);\n }\n } else {\n // Default 404 if no custom page exists\n setComponent(() => () => <div>404 Not Found</div>);\n setParams({});\n if (onRouteChange) {\n onRouteChange(undefined);\n }\n }\n }\n }\n };\n\n load();\n return () => { isCancelled = true; };\n }, [path, onRouteChange]);\n\n if (!Component) return <div>Loading...</div>;\n \n return (\n <RouterContext.Provider value={{ params, path }}>\n <Component {...params} />\n </RouterContext.Provider>\n );\n}\n\n// Link component - always uses SPA navigation (like Next.js)\n// Pre-rendered HTML is only for initial page load and SEO crawlers\nexport function Link({ href, children, ...props }: { href: string, children: ReactNode } & React.AnchorHTMLAttributes<HTMLAnchorElement>): React.ReactElement {\n const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {\n // Allow modifier keys for new tab, etc.\n if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n // Allow external links\n if (href.startsWith('http') || href.startsWith('//')) return;\n\n e.preventDefault();\n \n // Compare full URLs (including query strings) to allow search param changes\n const currentUrl = window.location.pathname + window.location.search;\n const targetUrl = href.startsWith('/') ? href : '/' + href;\n \n if (currentUrl === targetUrl) return;\n \n // SPA navigation - no page reload\n window.history.pushState({}, '', href);\n window.dispatchEvent(new Event('pushstate'));\n };\n\n return (\n <a href={href} onClick={handleClick} {...props}>\n {children}\n </a>\n );\n}"],"mappings":"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","names":[]}
@@ -0,0 +1,3 @@
1
+ declare const routes: Record<string, () => Promise<any>>;
2
+
3
+ export { routes };
package/dist/routes.js ADDED
@@ -0,0 +1,6 @@
1
+ // src/routes.ts
2
+ var routes = {};
3
+ export {
4
+ routes
5
+ };
6
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/routes.ts"],"sourcesContent":["// Stub for the virtual routes module - actual routes are injected by the router plugin at build time\r\n// This is externalized so the import resolves to 'olova/routes' in user projects\r\nexport const routes: Record<string, () => Promise<any>> = {};\r\n"],"mappings":";AAEO,IAAM,SAA6C,CAAC;","names":[]}
package/dist/vite.d.ts ADDED
@@ -0,0 +1,100 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ declare function olovaPlugins(): Plugin[];
4
+
5
+ declare function minifyHtml(html: string): string;
6
+ declare function generateBuildId(): string;
7
+ declare function generateResourceHints(): string;
8
+ declare function generateCriticalCSS(): string;
9
+ declare function generateServiceWorkerScript(): string;
10
+ declare function generateServiceWorkerContent(buildId: string, assets: string[]): string;
11
+ declare function generatePerformanceMeta(): string;
12
+
13
+ interface OlovaHydrationData {
14
+ route: string;
15
+ metadata?: Record<string, unknown>;
16
+ params?: Record<string, string>;
17
+ chunks?: string[];
18
+ isStatic?: boolean;
19
+ }
20
+ declare function generateOlovaHydration(data: OlovaHydrationData, buildId: string): string;
21
+ /**
22
+ * Generate JSON-LD structured data script for SEO
23
+ * This is injected into <head> for search engine crawlers
24
+ */
25
+ declare function generateJsonLd(data: OlovaHydrationData): string;
26
+ /**
27
+ * Parse flight data from the page (client-side utility)
28
+ * Use this to access hydration data in your components
29
+ */
30
+ declare function parseFlightData(): Record<string, unknown> | null;
31
+
32
+ declare const colors: {
33
+ reset: string;
34
+ bold: string;
35
+ dim: string;
36
+ italic: string;
37
+ underline: string;
38
+ black: string;
39
+ red: string;
40
+ green: string;
41
+ yellow: string;
42
+ blue: string;
43
+ magenta: string;
44
+ cyan: string;
45
+ white: string;
46
+ gray: string;
47
+ bgBlack: string;
48
+ bgRed: string;
49
+ bgGreen: string;
50
+ bgYellow: string;
51
+ bgBlue: string;
52
+ bgMagenta: string;
53
+ bgCyan: string;
54
+ bgWhite: string;
55
+ };
56
+ declare const symbols: {
57
+ success: string;
58
+ error: string;
59
+ warning: string;
60
+ info: string;
61
+ arrow: string;
62
+ arrowRight: string;
63
+ bullet: string;
64
+ filled: string;
65
+ lambda: string;
66
+ triangle: string;
67
+ square: string;
68
+ diamond: string;
69
+ star: string;
70
+ check: string;
71
+ cross: string;
72
+ pointer: string;
73
+ };
74
+ declare function formatTime(ms: number): string;
75
+ declare function formatBytes(bytes: number): string;
76
+ declare const logger: {
77
+ banner: (name: string, version?: string) => void;
78
+ header: (text: string) => void;
79
+ info: (text: string) => void;
80
+ success: (text: string, time?: number) => void;
81
+ error: (text: string) => void;
82
+ warn: (text: string) => void;
83
+ step: (text: string, time?: number) => void;
84
+ route: (route: string, type: "static" | "ssr" | "isr", size?: number, time?: number) => void;
85
+ indent: (text: string, level?: number) => void;
86
+ newline: () => void;
87
+ dim: (text: string) => string;
88
+ bold: (text: string) => string;
89
+ cyan: (text: string) => string;
90
+ green: (text: string) => string;
91
+ yellow: (text: string) => string;
92
+ red: (text: string) => string;
93
+ magenta: (text: string) => string;
94
+ };
95
+ declare function createTimer(): {
96
+ elapsed: () => number;
97
+ format: () => string;
98
+ };
99
+
100
+ export { type OlovaHydrationData, colors, createTimer, formatBytes, formatTime, generateBuildId, generateCriticalCSS, generateJsonLd, generateOlovaHydration, generatePerformanceMeta, generateResourceHints, generateServiceWorkerContent, generateServiceWorkerScript, logger, minifyHtml, olovaPlugins, parseFlightData, symbols };