@devlusoft/devix 0.4.3 → 0.5.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/README.md +64 -9
- package/dist/cli/build.js +27 -17
- package/dist/cli/build.js.map +3 -3
- package/dist/cli/dev-server.js +31 -21
- package/dist/cli/dev-server.js.map +4 -4
- package/dist/cli/generate.js +29 -19
- package/dist/cli/generate.js.map +3 -3
- package/dist/cli/index.js +30 -20
- package/dist/cli/index.js.map +4 -4
- package/dist/cli/start.js +1 -1
- package/dist/cli/start.js.map +4 -4
- package/dist/config.d.ts +61 -0
- package/dist/config.js +1 -1
- package/dist/config.js.map +3 -3
- package/dist/runtime/api-context.d.ts +9 -4
- package/dist/runtime/api-context.js +1 -1
- package/dist/runtime/api-context.js.map +3 -3
- package/dist/runtime/context.d.ts +1 -0
- package/dist/runtime/context.js.map +2 -2
- package/dist/runtime/create-handler.d.ts +52 -2
- package/dist/runtime/create-handler.js +1 -1
- package/dist/runtime/create-handler.js.map +3 -3
- package/dist/runtime/error-boundary.d.ts +7 -1
- package/dist/runtime/error-boundary.js +1 -1
- package/dist/runtime/error-boundary.js.map +3 -3
- package/dist/runtime/fetch.d.ts +1 -0
- package/dist/runtime/fetch.js +1 -1
- package/dist/runtime/fetch.js.map +3 -3
- package/dist/runtime/index.d.ts +6 -2
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/index.js.map +4 -4
- package/dist/runtime/link.js +1 -1
- package/dist/runtime/link.js.map +4 -4
- package/dist/runtime/router-provider.d.ts +24 -1
- package/dist/runtime/router-provider.js +1 -1
- package/dist/runtime/router-provider.js.map +4 -4
- package/dist/runtime/server-app.d.ts +2 -1
- package/dist/runtime/server-app.js +1 -1
- package/dist/runtime/server-app.js.map +3 -3
- package/dist/runtime/server-client.d.ts +66 -0
- package/dist/runtime/server-client.js +2 -0
- package/dist/runtime/server-client.js.map +7 -0
- package/dist/runtime/url.d.ts +9 -0
- package/dist/runtime/url.js +2 -0
- package/dist/runtime/url.js.map +7 -0
- package/dist/server/api.d.ts +2 -1
- package/dist/server/api.js +1 -1
- package/dist/server/api.js.map +4 -4
- package/dist/server/handler-store.d.ts +12 -0
- package/dist/server/handler-store.js.map +2 -2
- package/dist/server/public-index.js.map +2 -2
- package/dist/server/render.d.ts +8 -0
- package/dist/server/render.js +1 -1
- package/dist/server/render.js.map +4 -4
- package/dist/server/routes.d.ts +4 -2
- package/dist/server/routes.js +1 -1
- package/dist/server/routes.js.map +4 -4
- package/dist/server/server-bound.d.ts +11 -0
- package/dist/server/server-bound.js +2 -0
- package/dist/server/server-bound.js.map +7 -0
- package/dist/server/server-proxy.d.ts +15 -0
- package/dist/server/server-proxy.js +2 -0
- package/dist/server/server-proxy.js.map +7 -0
- package/dist/server/types.d.ts +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/utils/banner.js +1 -1
- package/dist/utils/glob.d.ts +11 -0
- package/dist/utils/glob.js +2 -0
- package/dist/utils/glob.js.map +7 -0
- package/dist/utils/response.d.ts +33 -1
- package/dist/utils/response.js +1 -1
- package/dist/utils/response.js.map +3 -3
- package/dist/utils/standard-schema.d.ts +39 -0
- package/dist/utils/standard-schema.js +1 -0
- package/dist/utils/standard-schema.js.map +7 -0
- package/dist/vite/codegen/entry-client.js +5 -3
- package/dist/vite/codegen/entry-client.js.map +2 -2
- package/dist/vite/codegen/page-types.d.ts +11 -2
- package/dist/vite/codegen/page-types.js +3 -3
- package/dist/vite/codegen/page-types.js.map +3 -3
- package/dist/vite/codegen/server-entry.js +16 -8
- package/dist/vite/codegen/server-entry.js.map +2 -2
- package/dist/vite/index.js +26 -16
- package/dist/vite/index.js.map +3 -3
- package/package.json +5 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/server/render.tsx", "../../src/runtime/head.tsx", "../../src/runtime/context.tsx", "../../src/runtime/error-boundary.tsx", "../../src/runtime/server-app.tsx", "../../src/utils/patterns.ts", "../../src/server/pages-router.ts", "../../src/runtime/metadata.ts", "../../src/utils/html.ts", "../../src/utils/async.ts", "../../src/utils/response.ts"],
|
|
4
|
-
"sourcesContent": ["import {createElement} from 'react'\nimport {renderToString, renderToStaticMarkup} from 'react-dom/server'\nimport {buildHeadNodes} from '../runtime/head'\nimport {ServerApp} from '../runtime/server-app'\nimport {buildPages, matchPage, collectLayoutChain, PagesResult} from './pages-router'\nimport {resolveMetadata, mergeMetadata} from '../runtime/metadata'\nimport type {PageModule, LayoutModule, PageGlob} from './types'\nimport type {Manifest} from \"vite\";\nimport {escapeAttr, safeJsonStringify} from \"../utils/html\";\nimport {withTimeout} from \"../utils/async\";\nimport {isRedirect, isLoaderError} from \"../utils/response\";\nimport type {Viewport} from \"../types\";\n\nconst DEFAULT_VIEWPORT: Viewport = { width: 'device-width', initialScale: 1 }\n\nlet pagesCache: PagesResult | null = null\nlet pagesCacheKey: string | null = null\n\nconst DEV_CLIENT_ENTRY = '/@id/virtual:devix/entry-client'\n\nfunction extractRedirect(result: unknown): { url: string, status: number, replace: boolean } | null {\n if (typeof result === 'string') return {url: result, status: 302, replace: false}\n if (isRedirect(result)) return {url: result.url, status: result.status, replace: result.replace}\n return null\n}\n\nasync function resolvePageData(pathname: string, request: Request, glob: PageGlob, timeout: number) {\n const cacheKey = Object.keys(glob.pages).sort().join('\\0') + '|' + Object.keys(glob.layouts).sort().join('\\0')\n if (!pagesCache || pagesCacheKey !== cacheKey) {\n pagesCache = buildPages(Object.keys(glob.pages), Object.keys(glob.layouts), glob.pagesDir)\n pagesCacheKey = cacheKey\n }\n const {pages, layouts} = pagesCache\n const matched = matchPage(pathname, pages)\n if (!matched) return null\n\n const {page, params} = matched\n const layoutChain = collectLayoutChain(page.key, layouts)\n\n const [pageMod, ...layoutMods] = await Promise.all([\n glob.pages[page.key]() as Promise<PageModule>,\n ...layoutChain.map(l => glob.layouts[l.key]() as Promise<LayoutModule>),\n ])\n\n let guardData: unknown = undefined\n\n for (const mod of layoutMods) {\n if (mod.guard) {\n const result = await mod.guard({params, request, guardData})\n const r = extractRedirect(result)\n if (r !== null) return {redirect: r.url, redirectStatus: r.status, redirectReplace: r.replace}\n if (isLoaderError(result)) return {loaderError: result}\n if (result !== null && result !== undefined) guardData = result\n }\n }\n\n if (pageMod.guard) {\n const result = await pageMod.guard({params, request, guardData})\n const r = extractRedirect(result)\n if (r !== null) return {redirect: r.url, redirectStatus: r.status, redirectReplace: r.replace}\n if (isLoaderError(result)) return {loaderError: result}\n if (result !== null && result !== undefined) guardData = result\n }\n\n const ctx = {params, request, guardData}\n\n const rawLoaderData = pageMod.loader\n ? await withTimeout(pageMod.loader(ctx) as Promise<unknown>, timeout)\n : null\n\n if (isRedirect(rawLoaderData)) return {\n redirect: rawLoaderData.url,\n redirectStatus: rawLoaderData.status,\n redirectReplace: rawLoaderData.replace\n }\n if (isLoaderError(rawLoaderData)) return {loaderError: rawLoaderData}\n const loaderData = rawLoaderData\n\n const rawLayoutsData = await withTimeout(\n Promise.all(layoutMods.map(mod => mod.loader ? mod.loader(ctx) : null)),\n timeout\n )\n for (const raw of rawLayoutsData) {\n if (isRedirect(raw)) return {redirect: raw.url, redirectStatus: raw.status, redirectReplace: raw.replace}\n if (isLoaderError(raw)) return {loaderError: raw}\n }\n const layoutsData = rawLayoutsData\n\n const pageMeta = await resolveMetadata(pageMod, {...ctx, loaderData})\n const layoutsMeta = await Promise.all(\n layoutMods.map((mod, i) => resolveMetadata(mod, {...ctx, loaderData: layoutsData[i]}))\n )\n\n const metadata = mergeMetadata(...layoutsMeta.map(m => m.metadata), pageMeta.metadata)\n const viewport = pageMeta.viewport ?? layoutsMeta.findLast(m => m.viewport)?.viewport ?? DEFAULT_VIEWPORT\n\n const rootLayoutMod = layoutMods[0]\n const lang = rootLayoutMod?.generateLang\n ? await rootLayoutMod.generateLang({...ctx, loaderData: layoutsData[0]})\n : rootLayoutMod?.lang ?? 'en'\n\n return {pageMod, layoutMods, params, loaderData, layoutsData, metadata, viewport, lang}\n}\n\nexport async function runLoader(url: string, request: Request, glob: PageGlob, options?: { loaderTimeout?: number }) {\n const {pathname} = new URL(url, 'http://localhost')\n let result: Awaited<ReturnType<typeof resolvePageData>>\n try {\n const timeout = options?.loaderTimeout ?? 10_000\n result = await resolvePageData(pathname, request, glob, timeout)\n } catch (err) {\n console.error('[devix] render error:', err)\n return {error: true as const, loaderData: null, params: {}, layouts: [], metadata: null, viewport: undefined}\n }\n\n if (!result) {\n return {loaderData: null, params: {}, layouts: [], metadata: null, viewport: undefined}\n }\n\n if ('redirect' in result) {\n return {\n redirect: result.redirect,\n redirectStatus: result.redirectStatus,\n redirectReplace: result.redirectReplace\n }\n }\n\n if ('loaderError' in result) {\n return {loaderError: result.loaderError}\n }\n\n const {loaderData, params, layoutsData, metadata, viewport} = result\n return {\n loaderData,\n params,\n layouts: layoutsData.map(loaderData => ({loaderData})),\n metadata,\n viewport,\n }\n}\n\nexport async function render(\n url: string,\n request: Request,\n glob: PageGlob,\n options?: { manifest?: Manifest, loaderTimeout?: number },\n) {\n const clientEntry = options?.manifest\n ? `/${Object.values(options.manifest).find(chunk => chunk.isEntry)?.file}`\n : DEV_CLIENT_ENTRY\n\n const cssFiles = options?.manifest\n ? (Object.values(options.manifest).find(chunk => chunk.isEntry)?.css ?? [])\n : []\n const cssLinks = cssFiles.map(f => `<link rel=\"stylesheet\" href=\"/${f}\">`).join('')\n\n const {pathname} = new URL(url, 'http://localhost')\n\n let result: Awaited<ReturnType<typeof resolvePageData>>\n try {\n const timeout = options?.loaderTimeout ?? 10_000\n result = await resolvePageData(pathname, request, glob, timeout)\n } catch (err) {\n console.error('[devix] render error:', err)\n const html = `<html lang=\"en\"><head><meta charset=\"utf-8\">${cssLinks}</head><body><script>window.__DEVIX__=null;window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];</script><script type=\"module\" src=\"${clientEntry}\"></script><div id=\"devix-root\"></div></body></html>`\n return {html, statusCode: 500, headers: {}}\n }\n\n if (!result) {\n const dataScript = `<script>window.__DEVIX__=${safeJsonStringify({\n metadata: null,\n viewport: undefined,\n clientEntry\n })};window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];</script>`\n const clientScript = `<script type=\"module\" src=\"${clientEntry}\"></script>`\n const html = `<html lang=\"en\"><head><meta charset=\"utf-8\">${cssLinks}${dataScript}</head><body><div id=\"devix-root\"></div>${clientScript}</body></html>`\n return {html, statusCode: 404, headers: {}}\n }\n\n if ('redirect' in result) {\n return {html: '', statusCode: result.redirectStatus, headers: {Location: result.redirect}}\n }\n\n if ('loaderError' in result) {\n const {statusCode, message, data} = result.loaderError!\n const dataScript = `<script>window.__DEVIX__=${safeJsonStringify({metadata: null, viewport: undefined, clientEntry})};window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];window.__LOADER_ERROR__=${safeJsonStringify({statusCode, message, data})};</script>`\n const clientScript = `<script type=\"module\" src=\"${clientEntry}\"></script>`\n const html = `<html lang=\"en\"><head><meta charset=\"utf-8\">${cssLinks}${dataScript}</head><body><div id=\"devix-root\"></div>${clientScript}</body></html>`\n return {html, statusCode, headers: {}}\n }\n\n const {pageMod, layoutMods, params, loaderData, layoutsData, metadata, viewport, lang} = result\n\n const content = renderToString(createElement(ServerApp, {\n pathname,\n params,\n loaderData,\n layoutsData,\n Page: pageMod.default as any,\n layouts: layoutMods.map(m => m.default as any),\n metadata: metadata ?? null,\n viewport,\n clientEntry,\n }))\n const headTags = metadata ? renderToStaticMarkup(buildHeadNodes(metadata, viewport) as any) : ''\n\n const dataScript = `<script>window.__DEVIX__=${safeJsonStringify({\n metadata,\n viewport,\n clientEntry\n })};window.__LOADER_DATA__=${safeJsonStringify(loaderData ?? null)};window.__LAYOUTS_DATA__=${safeJsonStringify(layoutsData)};</script>`\n const clientScript = `<script type=\"module\" src=\"${clientEntry}\"></script>`\n const customHeaders: Record<string, string> = pageMod.headers ?? {}\n\n const html = `<html lang=\"${escapeAttr(lang)}\"><head><meta charset=\"utf-8\">${headTags}${cssLinks}${dataScript}</head><body><div id=\"devix-root\">${content}</div>${clientScript}</body></html>`\n\n return {html, statusCode: 200, headers: customHeaders}\n}\n\nexport async function getStaticRoutes(glob: PageGlob): Promise<string[]> {\n const {pages} = buildPages(Object.keys(glob.pages), Object.keys(glob.layouts), glob.pagesDir)\n const urls: string[] = []\n\n for (const page of pages) {\n if (page.params.length === 0) {\n urls.push(page.path)\n } else {\n const mod = await glob.pages[page.key]() as PageModule\n if (!mod.generateStaticParams) continue\n const paramSets = await mod.generateStaticParams()\n for (const params of paramSets) {\n let url = page.path\n for (const [key, value] of Object.entries(params)) {\n url = url.replace(`:${key}`, encodeURIComponent(value))\n }\n urls.push(url)\n }\n }\n }\n\n return urls\n}\n\n", "import { Metadata, MetadataIcon, Viewport } from \"../types\";\nimport { ReactNode } from \"react\";\n\ntype MetaTag =\n | { tag: 'title'; children: string }\n | { tag: 'meta'; name?: string; property?: string; content: string }\n | { tag: 'link'; rel: string; href: string; hrefLang?: string; type?: string; sizes?: string }\n\nfunction collectTags(metadata: Metadata, viewport?: Viewport): MetaTag[] {\n const tags: MetaTag[] = []\n\n if (metadata.title)\n tags.push({ tag: 'title', children: metadata.title })\n if (metadata.description)\n tags.push({ tag: 'meta', name: 'description', content: metadata.description })\n if (metadata.keywords?.length)\n tags.push({ tag: 'meta', name: 'keywords', content: metadata.keywords.join(', ') })\n\n const ogTitle = metadata.og?.title ?? metadata.title\n if (ogTitle) tags.push({ tag: 'meta', property: 'og:title', content: ogTitle })\n const ogDesc = metadata.og?.description ?? metadata.description\n if (ogDesc) tags.push({ tag: 'meta', property: 'og:description', content: ogDesc })\n if (metadata.og?.image) tags.push({ tag: 'meta', property: 'og:image', content: metadata.og.image })\n if (metadata.og?.type) tags.push({ tag: 'meta', property: 'og:type', content: metadata.og.type })\n if (metadata.og?.url) tags.push({ tag: 'meta', property: 'og:url', content: metadata.og.url })\n\n const twTitle = metadata.twitter?.title ?? metadata.title\n if (twTitle) tags.push({ tag: 'meta', name: 'twitter:title', content: twTitle })\n const twDesc = metadata.twitter?.description ?? metadata.description\n if (twDesc) tags.push({ tag: 'meta', name: 'twitter:description', content: twDesc })\n if (metadata.twitter?.card) tags.push({\n tag: 'meta', name: 'twitter:card', content:\n metadata.twitter.card\n })\n if (metadata.twitter?.image) tags.push({\n tag: 'meta', name: 'twitter:image', content:\n metadata.twitter.image\n })\n if (metadata.twitter?.creator) tags.push({\n tag: 'meta', name: 'twitter:creator', content:\n metadata.twitter.creator\n })\n\n if (metadata.canonical) tags.push({ tag: 'link', rel: 'canonical', href: metadata.canonical })\n if (metadata.robots) tags.push({ tag: 'meta', name: 'robots', content: metadata.robots })\n if (metadata.alternates) {\n for (const [lang, href] of Object.entries(metadata.alternates))\n tags.push({ tag: 'link', rel: 'alternate', href, hrefLang: lang })\n }\n\n if (metadata.icons) {\n const raw = Array.isArray(metadata.icons) ? metadata.icons : [metadata.icons]\n for (const icon of raw) {\n const resolved: MetadataIcon = typeof icon === 'string' ? { href: icon } : icon\n tags.push({\n tag: 'link',\n rel: resolved.rel ?? 'icon',\n href: resolved.href,\n ...(resolved.type && { type: resolved.type }),\n ...(resolved.sizes && { sizes: resolved.sizes }),\n })\n }\n }\n\n if (viewport) {\n const parts: string[] = []\n if (viewport.width !== undefined) parts.push(`width=${viewport.width}`)\n if (viewport.initialScale !== undefined) parts.push(`initial-scale=${viewport.initialScale}`)\n if (viewport.maximumScale !== undefined) parts.push(`maximum-scale=${viewport.maximumScale}`)\n if (viewport.userScalable !== undefined) parts.push(`user-scalable=${viewport.userScalable ? 'yes' :\n 'no'}`)\n if (parts.length) tags.push({ tag: 'meta', name: 'viewport', content: parts.join(', ') })\n if (viewport.themeColor) tags.push({\n tag: 'meta', name: 'theme-color', content: viewport.themeColor\n })\n }\n\n return tags\n}\n\nexport function HeadSlot({ metadata, viewport }: { metadata: Metadata | null, viewport?: Viewport }) {\n if (typeof window === 'undefined' || !metadata) return null\n return <>{buildHeadNodes(metadata, viewport)}</>\n}\n\nexport function buildHeadNodes(metadata: Metadata, viewport?: Viewport): ReactNode {\n const tags = collectTags(metadata, viewport)\n\n return <>\n {tags.map((t, i) => {\n if (t.tag === 'title') return <title key={i}>{t.children}</title>\n if (t.tag === 'link') return <link key={i} rel={t.rel} href={t.href} hrefLang={t.hrefLang} type={t.type} sizes={t.sizes} />\n return <meta key={i} name={t.name} property={t.property} content={t.content} />\n })}\n </>\n}", "import {createContext, Context, ComponentType} from \"react\";\nimport {Metadata, Viewport} from \"../types\";\nimport {LayoutProps, PageProps} from \"../server/types\";\n\nexport interface NavigateOptions {\n replace?: boolean\n viewTransition?: boolean\n}\n\nexport interface RouterContextValue {\n pathname: string\n params: Record<string, string>\n loaderData: unknown\n layoutsData: unknown[]\n Page: ComponentType<PageProps>\n layouts: ComponentType<LayoutProps>[]\n metadata: Metadata | null\n viewport?: Viewport\n navigate: (to: string, options?: NavigateOptions) => Promise<void>\n revalidate: () => Promise<void>\n prefetchRoute: (href: string) => void\n isNavigating: boolean\n}\n\nexport interface PageMetaContextValue {\n metadata: Metadata | null\n viewport?: Viewport\n clientEntry?: string\n}\n\nexport interface RouteDataContextValue {\n loaderData: unknown\n params: Record<string, string>\n}\n\nconst g = globalThis as any\n\ng.__devix_RouterContext__ ??= createContext<RouterContextValue | null>(null)\nexport const RouterContext: Context<RouterContextValue | null> = g.__devix_RouterContext__\n\ng.__devix_PageMetaContext__ ??= createContext<PageMetaContextValue | null>(null)\ng.__devix_RouteDataContext__ ??= createContext<RouteDataContextValue | null>(null)\n\nexport const PageMetaContext: Context<PageMetaContextValue | null> = g.__devix_PageMetaContext__\nexport const RouteDataContext: Context<RouteDataContextValue | null> = g.__devix_RouteDataContext__\n\n", "import {Component, ComponentType, ReactNode} from \"react\";\nimport {ErrorProps} from \"../server/types\";\n\ninterface Props {\n ErrorPage?: ComponentType<ErrorProps>\n children: ReactNode\n}\n\ninterface State {\n error: ErrorProps | null\n}\n\nexport class DevixErrorBoundary extends Component<Props, State> {\n state: State = { error: null }\n\n static getDerivedStateFromError(err: unknown): State {\n if (err instanceof DevixError) {\n return {\n error: {statusCode: err.statusCode, message: err.message}\n }\n }\n return {\n error: {statusCode: 500, message: err instanceof Error ? err.message : 'Unknown error'}\n }\n }\n\n render() {\n if (this.state.error && this.props.ErrorPage) {\n return <this.props.ErrorPage {...this.state.error} />\n }\n if (this.state.error) {\n return <h1>{this.state.error.statusCode}</h1>\n }\n return this.props.children\n }\n}\n\nexport class DevixError extends Error {\n statusCode: number\n constructor(statusCode: number, message: string) {\n super(message)\n this.statusCode = statusCode\n }\n}\n", "import {ComponentType, ReactNode} from 'react'\nimport {RouterContext, PageMetaContext, RouteDataContext, NavigateOptions} from './context'\nimport {HeadSlot} from './head'\nimport {DevixErrorBoundary} from './error-boundary'\nimport {LayoutProps, PageProps} from '../server/types'\nimport {Metadata, Viewport} from '../types'\n\nconst noopNavigate = (_to: string, _opts?: NavigateOptions) => Promise.resolve()\nconst noopRevalidate = () => Promise.resolve()\nconst noopPrefetch = (_href: string) => {}\n\nexport interface ServerAppProps {\n pathname: string\n params: Record<string, string>\n loaderData: unknown\n layoutsData: unknown[]\n Page: ComponentType<PageProps>\n layouts: ComponentType<LayoutProps>[]\n metadata: Metadata | null\n viewport?: Viewport\n clientEntry: string\n}\n\nexport function ServerApp({\n pathname, params, loaderData, layoutsData,\n Page, layouts, metadata, viewport, clientEntry,\n}: ServerAppProps) {\n let tree: ReactNode = (\n <RouteDataContext value={{loaderData, params}}>\n <Page data={loaderData as any} params={params} url={pathname}/>\n </RouteDataContext>\n )\n\n for (let i = layouts.length - 1; i >= 0; i--) {\n const Layout = layouts[i]\n const layoutData = layoutsData[i]\n tree = (\n <RouteDataContext value={{loaderData: layoutData, params}}>\n <Layout data={layoutData as any} params={params}>{tree}</Layout>\n </RouteDataContext>\n )\n }\n\n return (\n <PageMetaContext value={{metadata, viewport, clientEntry}}>\n <HeadSlot metadata={metadata} viewport={viewport}/>\n <RouterContext value={{\n pathname,\n params,\n loaderData,\n layoutsData,\n Page,\n layouts,\n metadata,\n viewport,\n isNavigating: false,\n navigate: noopNavigate,\n revalidate: noopRevalidate,\n prefetchRoute: noopPrefetch,\n }}>\n <DevixErrorBoundary key={pathname}>\n {tree}\n </DevixErrorBoundary>\n </RouterContext>\n </PageMetaContext>\n )\n}\n", "export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aSegs = a.path.split('/').filter(Boolean)\n const bSegs = b.path.split('/').filter(Boolean)\n const len = Math.max(aSegs.length, bSegs.length)\n for (let i = 0; i < len; i++) {\n const aVal = i < aSegs.length ? (aSegs[i].startsWith(':') ? 1 : 2) : 0\n const bVal = i < bSegs.length ? (bSegs[i].startsWith(':') ? 1 : 2) : 0\n if (aVal !== bVal) return bVal - aVal\n }\n return b.path.length - a.path.length\n })\n\n return {pages, layouts}\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n", "import {LayoutModule, PageModule} from \"../server\";\nimport {LoaderContext, Metadata, Viewport} from \"../types\"\n\nexport interface ResolvedMeta {\n metadata: Metadata\n viewport?: Viewport\n}\n\nexport async function resolveMetadata(module: PageModule | LayoutModule, ctx: LoaderContext & {\n loaderData: unknown\n}): Promise<ResolvedMeta> {\n const metadata = module.generateMetadata\n ? await module.generateMetadata(ctx)\n : module.metadata ?? {}\n\n const viewport = module.generateViewport\n ? await module.generateViewport(ctx)\n : module.viewport\n\n return {metadata, viewport}\n}\n\nexport function mergeMetadata(...sources: (Metadata | null | undefined)[]): Metadata {\n const result: Metadata = {}\n\n for (const source of sources) {\n if (!source) continue\n const { og, twitter, ...rest } = source\n Object.assign(result, rest)\n if (og) result.og = { ...result.og, ...og }\n if (twitter) result.twitter = { ...result.twitter, ...twitter }\n }\n\n return result\n}", "export function safeJsonStringify(value: unknown): string {\n return JSON.stringify(value).replace(/<\\/script>/gi, '<\\\\/script>')\n}\n\nexport function escapeAttr(value: string): string {\n return value.replace(/\"/g, '"')\n}", "export function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n let timer: ReturnType<typeof setTimeout>\n return Promise.race([\n promise.finally(() => clearTimeout(timer)),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms)\n })\n ])\n}", "export type JsonResponse<T = unknown, S extends number = number> = Response & {\n readonly __body: T\n readonly __status: S\n}\n\nexport function json<const T>(data: T): JsonResponse<T, 200>\nexport function json<const T, const S extends number>(data: T, status: S): JsonResponse<T, S>\nexport function json<const T>(data: T, status: number = 200): JsonResponse<T, any> {\n return new Response(JSON.stringify(data), {\n status,\n headers: {'Content-Type': 'application/json'},\n }) as JsonResponse<T, any>\n}\n\nexport const text = (body: string, status = 200): Response =>\n new Response(body, {status, headers: {'Content-Type': 'text/plain; charset=utf-8'}})\n\nconst REDIRECT_BRAND = Symbol.for('devix.redirect')\n\nexport interface RedirectOptions {\n status?: number\n replace?: boolean\n}\n\nexport interface Redirect {\n readonly [REDIRECT_BRAND]: true\n readonly url: string\n readonly status: number\n readonly replace: boolean\n}\n\nexport function redirect(url: string, statusOrOptions?: number | RedirectOptions): Redirect {\n const status = typeof statusOrOptions === 'number' ? statusOrOptions : (statusOrOptions?.status ?? 302)\n const replace = typeof statusOrOptions === 'object' ? (statusOrOptions?.replace ?? false) : false\n return {[REDIRECT_BRAND]: true, url, status, replace} as Redirect\n}\n\nexport function isRedirect(value: unknown): value is Redirect {\n return typeof value === 'object' && value !== null && REDIRECT_BRAND in value\n}\n\nconst ERROR_BRAND = Symbol.for('devix.loaderError')\n\nexport interface RouteError {\n readonly [ERROR_BRAND]: true\n readonly statusCode: number\n readonly message: string\n readonly data?: unknown\n}\n\nexport function error(statusCode: number, message: string, data?: unknown): RouteError {\n return { [ERROR_BRAND]: true, statusCode, message, data } as RouteError\n}\n\nexport function isLoaderError(value: unknown): value is RouteError {\n return typeof value === 'object' && value !== null && ERROR_BRAND in value\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["createElement", "renderToString", "renderToStaticMarkup", "Fragment", "jsx", "collectTags", "metadata", "viewport", "tags", "ogTitle", "ogDesc", "twTitle", "twDesc", "lang", "href", "raw", "icon", "resolved", "parts", "HeadSlot", "buildHeadNodes", "t", "i", "createContext", "g", "RouterContext", "PageMetaContext", "RouteDataContext", "Component", "jsx", "DevixErrorBoundary", "err", "DevixError", "statusCode", "message", "jsx", "jsxs", "noopNavigate", "_to", "_opts", "noopRevalidate", "noopPrefetch", "_href", "ServerApp", "pathname", "params", "loaderData", "layoutsData", "Page", "layouts", "metadata", "viewport", "clientEntry", "tree", "RouteDataContext", "i", "Layout", "layoutData", "PageMetaContext", "HeadSlot", "RouterContext", "DevixErrorBoundary", "routePattern", "rel", "keyToRoutePattern", "key", "pagesDir", "rel", "pattern", "routePattern", "keyToDir", "buildPages", "pageKeys", "layoutKeys", "pages", "layouts", "params", "m", "regexStr", "b", "aSegs", "bSegs", "len", "i", "aVal", "bVal", "collectLayoutChain", "pageKey", "pageDir", "layout", "a", "matchPage", "pathname", "page", "match", "name", "resolveMetadata", "module", "ctx", "metadata", "viewport", "mergeMetadata", "sources", "result", "source", "og", "twitter", "rest", "safeJsonStringify", "value", "escapeAttr", "withTimeout", "promise", "ms", "timer", "_", "reject", "REDIRECT_BRAND", "isRedirect", "value", "REDIRECT_BRAND", "ERROR_BRAND", "isLoaderError", "value", "ERROR_BRAND", "DEFAULT_VIEWPORT", "pagesCache", "pagesCacheKey", "DEV_CLIENT_ENTRY", "extractRedirect", "result", "isRedirect", "resolvePageData", "pathname", "request", "glob", "timeout", "cacheKey", "buildPages", "pages", "layouts", "matched", "matchPage", "page", "params", "layoutChain", "collectLayoutChain", "pageMod", "layoutMods", "
|
|
3
|
+
"sources": ["../../src/server/render.tsx", "../../src/runtime/head.tsx", "../../src/runtime/context.tsx", "../../src/runtime/error-boundary.tsx", "../../src/runtime/server-app.tsx", "../../src/utils/patterns.ts", "../../src/server/pages-router.ts", "../../src/runtime/metadata.ts", "../../src/utils/html.ts", "../../src/utils/async.ts", "../../src/utils/response.ts", "../../src/runtime/fetch.ts", "../../src/utils/glob.ts", "../../src/server/server-bound.ts"],
|
|
4
|
+
"sourcesContent": ["import {createElement} from 'react'\nimport {renderToString, renderToStaticMarkup} from 'react-dom/server'\nimport {buildHeadNodes} from '../runtime/head'\nimport {ServerApp} from '../runtime/server-app'\nimport {buildPages, matchPage, collectLayoutChain, PagesResult} from './pages-router'\nimport {resolveMetadata, mergeMetadata} from '../runtime/metadata'\nimport type {PageModule, LayoutModule, PageGlob} from './types'\nimport type {Manifest} from \"vite\";\nimport {escapeAttr, safeJsonStringify} from \"../utils/html\";\nimport {withTimeout} from \"../utils/async\";\nimport {isRedirect, isLoaderError, errorToBody} from \"../utils/response\";\nimport type {Viewport} from \"../types\";\nimport type {ServerBackendConfig} from \"../config\";\nimport {makeBoundServer} from \"./server-bound\";\n\nconst DEFAULT_VIEWPORT: Viewport = { width: 'device-width', initialScale: 1 }\n\nlet pagesCache: PagesResult | null = null\nlet pagesCacheKey: string | null = null\n\nconst DEV_CLIENT_ENTRY = '/@id/virtual:devix/entry-client'\n\nfunction extractRedirect(result: unknown): { url: string, status: number, replace: boolean } | null {\n if (typeof result === 'string') return {url: result, status: 302, replace: false}\n if (isRedirect(result)) return {url: result.url, status: result.status, replace: result.replace}\n return null\n}\n\nasync function resolvePageData(pathname: string, request: Request, glob: PageGlob, timeout: number, serverConfig?: Record<string, ServerBackendConfig>) {\n const cacheKey = Object.keys(glob.pages).sort().join('\\0') + '|' + Object.keys(glob.layouts).sort().join('\\0')\n if (!pagesCache || pagesCacheKey !== cacheKey) {\n pagesCache = buildPages(Object.keys(glob.pages), Object.keys(glob.layouts), glob.pagesDir)\n pagesCacheKey = cacheKey\n }\n const {pages, layouts} = pagesCache\n const matched = matchPage(pathname, pages)\n if (!matched) return null\n\n const {page, params} = matched\n const layoutChain = collectLayoutChain(page.key, layouts)\n\n const [pageMod, ...layoutMods] = await Promise.all([\n glob.pages[page.key]() as Promise<PageModule>,\n ...layoutChain.map(l => glob.layouts[l.key]() as Promise<LayoutModule>),\n ])\n\n let guardData: unknown = undefined\n const $server = makeBoundServer(request, serverConfig)\n\n for (const mod of layoutMods) {\n if (mod.guard) {\n const result = await mod.guard({params, request, guardData, $server})\n const r = extractRedirect(result)\n if (r !== null) return {redirect: r.url, redirectStatus: r.status, redirectReplace: r.replace}\n if (isLoaderError(result)) return {loaderError: result}\n if (result !== null && result !== undefined) guardData = result\n }\n }\n\n if (pageMod.guard) {\n const result = await pageMod.guard({params, request, guardData, $server})\n const r = extractRedirect(result)\n if (r !== null) return {redirect: r.url, redirectStatus: r.status, redirectReplace: r.replace}\n if (isLoaderError(result)) return {loaderError: result}\n if (result !== null && result !== undefined) guardData = result\n }\n\n const ctx = {params, request, guardData, $server}\n\n const rawLoaderData = pageMod.loader\n ? await withTimeout(Promise.resolve(pageMod.loader(ctx)), timeout)\n : null\n\n if (isRedirect(rawLoaderData)) return {\n redirect: rawLoaderData.url,\n redirectStatus: rawLoaderData.status,\n redirectReplace: rawLoaderData.replace\n }\n if (isLoaderError(rawLoaderData)) return {loaderError: rawLoaderData}\n const loaderData = rawLoaderData\n\n const rawLayoutsData = await withTimeout(\n Promise.all(layoutMods.map(mod => mod.loader ? mod.loader(ctx) : null)),\n timeout\n )\n for (const raw of rawLayoutsData) {\n if (isRedirect(raw)) return {redirect: raw.url, redirectStatus: raw.status, redirectReplace: raw.replace}\n if (isLoaderError(raw)) return {loaderError: raw}\n }\n const layoutsData = rawLayoutsData\n\n const pageMeta = await resolveMetadata(pageMod, {...ctx, loaderData})\n const layoutsMeta = await Promise.all(\n layoutMods.map((mod, i) => resolveMetadata(mod, {...ctx, loaderData: layoutsData[i]}))\n )\n\n const metadata = mergeMetadata(...layoutsMeta.map(m => m.metadata), pageMeta.metadata)\n const viewport = pageMeta.viewport ?? layoutsMeta.findLast(m => m.viewport)?.viewport ?? DEFAULT_VIEWPORT\n\n const rootLayoutMod = layoutMods[0]\n const lang = rootLayoutMod?.generateLang\n ? await rootLayoutMod.generateLang({...ctx, loaderData: layoutsData[0]})\n : rootLayoutMod?.lang ?? 'en'\n\n return {pageMod, layoutMods, params, loaderData, layoutsData, guardData, metadata, viewport, lang}\n}\n\nexport async function runLoader(url: string, request: Request, glob: PageGlob, options?: { loaderTimeout?: number; server?: Record<string, ServerBackendConfig> }) {\n const {pathname} = new URL(url, 'http://localhost')\n let result: Awaited<ReturnType<typeof resolvePageData>>\n try {\n const timeout = options?.loaderTimeout ?? 10_000\n result = await resolvePageData(pathname, request, glob, timeout, options?.server)\n } catch (err) {\n console.error('[devix] render error:', err)\n return {error: true as const, loaderData: null, params: {}, layouts: [], metadata: null, viewport: undefined}\n }\n\n if (!result) {\n return {loaderData: null, params: {}, layouts: [], metadata: null, viewport: undefined}\n }\n\n if ('redirect' in result) {\n return {\n redirect: result.redirect,\n redirectStatus: result.redirectStatus,\n redirectReplace: result.redirectReplace\n }\n }\n\n if ('loaderError' in result) {\n return {loaderError: result.loaderError}\n }\n\n const {loaderData, params, layoutsData, guardData, metadata, viewport} = result\n return {\n loaderData,\n params,\n layouts: layoutsData.map(loaderData => ({loaderData})),\n guardData,\n metadata,\n viewport,\n }\n}\n\nexport async function render(\n url: string,\n request: Request,\n glob: PageGlob,\n options?: { manifest?: Manifest, loaderTimeout?: number, server?: Record<string, ServerBackendConfig> },\n) {\n const clientEntry = options?.manifest\n ? `/${Object.values(options.manifest).find(chunk => chunk.isEntry)?.file}`\n : DEV_CLIENT_ENTRY\n\n const cssFiles = options?.manifest\n ? (Object.values(options.manifest).find(chunk => chunk.isEntry)?.css ?? [])\n : []\n const cssLinks = cssFiles.map(f => `<link rel=\"stylesheet\" href=\"/${f}\">`).join('')\n\n const {pathname} = new URL(url, 'http://localhost')\n\n let result: Awaited<ReturnType<typeof resolvePageData>>\n try {\n const timeout = options?.loaderTimeout ?? 10_000\n result = await resolvePageData(pathname, request, glob, timeout, options?.server)\n } catch (err) {\n console.error('[devix] render error:', err)\n const html = `<html lang=\"en\"><head><meta charset=\"utf-8\">${cssLinks}</head><body><script>window.__DEVIX__=null;window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];</script><script type=\"module\" src=\"${clientEntry}\"></script><div id=\"devix-root\"></div></body></html>`\n return {html, statusCode: 500, headers: {}}\n }\n\n if (!result) {\n const dataScript = `<script>window.__DEVIX__=${safeJsonStringify({\n metadata: null,\n viewport: undefined,\n clientEntry\n })};window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];</script>`\n const clientScript = `<script type=\"module\" src=\"${clientEntry}\"></script>`\n const html = `<html lang=\"en\"><head><meta charset=\"utf-8\">${cssLinks}${dataScript}</head><body><div id=\"devix-root\"></div>${clientScript}</body></html>`\n return {html, statusCode: 404, headers: {}}\n }\n\n if ('redirect' in result) {\n return {html: '', statusCode: result.redirectStatus, headers: {Location: result.redirect}}\n }\n\n if ('loaderError' in result) {\n const errBody = errorToBody(result.loaderError!)\n const dataScript = `<script>window.__DEVIX__=${safeJsonStringify({metadata: null, viewport: undefined, clientEntry})};window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];window.__LOADER_ERROR__=${safeJsonStringify(errBody)};</script>`\n const clientScript = `<script type=\"module\" src=\"${clientEntry}\"></script>`\n const html = `<html lang=\"en\"><head><meta charset=\"utf-8\">${cssLinks}${dataScript}</head><body><div id=\"devix-root\"></div>${clientScript}</body></html>`\n return {html, statusCode: errBody.statusCode, headers: {}}\n }\n\n const {pageMod, layoutMods, params, loaderData, layoutsData, guardData, metadata, viewport, lang} = result\n\n const content = renderToString(createElement(ServerApp, {\n pathname,\n params,\n loaderData,\n layoutsData,\n guardData,\n Page: pageMod.default as any,\n layouts: layoutMods.map(m => m.default as any),\n metadata: metadata ?? null,\n viewport,\n clientEntry,\n }))\n const headTags = metadata ? renderToStaticMarkup(buildHeadNodes(metadata, viewport) as any) : ''\n\n const dataScript = `<script>window.__DEVIX__=${safeJsonStringify({\n metadata,\n viewport,\n clientEntry\n })};window.__LOADER_DATA__=${safeJsonStringify(loaderData ?? null)};window.__LAYOUTS_DATA__=${safeJsonStringify(layoutsData)};window.__GUARD_DATA__=${safeJsonStringify(guardData ?? null)};</script>`\n const clientScript = `<script type=\"module\" src=\"${clientEntry}\"></script>`\n const customHeaders: Record<string, string> = pageMod.headers ?? {}\n\n const html = `<html lang=\"${escapeAttr(lang)}\"><head><meta charset=\"utf-8\">${headTags}${cssLinks}${dataScript}</head><body><div id=\"devix-root\">${content}</div>${clientScript}</body></html>`\n\n return {html, statusCode: 200, headers: customHeaders}\n}\n\nexport async function getStaticRoutes(glob: PageGlob): Promise<string[]> {\n const {pages} = buildPages(Object.keys(glob.pages), Object.keys(glob.layouts), glob.pagesDir)\n const urls: string[] = []\n\n for (const page of pages) {\n if (page.params.length === 0) {\n urls.push(page.path)\n } else {\n const mod = await glob.pages[page.key]() as PageModule\n if (!mod.generateStaticParams) continue\n const paramSets = await mod.generateStaticParams()\n for (const params of paramSets) {\n let url = page.path\n for (const [key, value] of Object.entries(params)) {\n url = url.replace(`:${key}`, encodeURIComponent(value))\n }\n urls.push(url)\n }\n }\n }\n\n return urls\n}\n\n", "import { Metadata, MetadataIcon, Viewport } from \"../types\";\nimport { ReactNode } from \"react\";\n\ntype MetaTag =\n | { tag: 'title'; children: string }\n | { tag: 'meta'; name?: string; property?: string; content: string }\n | { tag: 'link'; rel: string; href: string; hrefLang?: string; type?: string; sizes?: string }\n\nfunction collectTags(metadata: Metadata, viewport?: Viewport): MetaTag[] {\n const tags: MetaTag[] = []\n\n if (metadata.title)\n tags.push({ tag: 'title', children: metadata.title })\n if (metadata.description)\n tags.push({ tag: 'meta', name: 'description', content: metadata.description })\n if (metadata.keywords?.length)\n tags.push({ tag: 'meta', name: 'keywords', content: metadata.keywords.join(', ') })\n\n const ogTitle = metadata.og?.title ?? metadata.title\n if (ogTitle) tags.push({ tag: 'meta', property: 'og:title', content: ogTitle })\n const ogDesc = metadata.og?.description ?? metadata.description\n if (ogDesc) tags.push({ tag: 'meta', property: 'og:description', content: ogDesc })\n if (metadata.og?.image) tags.push({ tag: 'meta', property: 'og:image', content: metadata.og.image })\n if (metadata.og?.type) tags.push({ tag: 'meta', property: 'og:type', content: metadata.og.type })\n if (metadata.og?.url) tags.push({ tag: 'meta', property: 'og:url', content: metadata.og.url })\n\n const twTitle = metadata.twitter?.title ?? metadata.title\n if (twTitle) tags.push({ tag: 'meta', name: 'twitter:title', content: twTitle })\n const twDesc = metadata.twitter?.description ?? metadata.description\n if (twDesc) tags.push({ tag: 'meta', name: 'twitter:description', content: twDesc })\n if (metadata.twitter?.card) tags.push({\n tag: 'meta', name: 'twitter:card', content:\n metadata.twitter.card\n })\n if (metadata.twitter?.image) tags.push({\n tag: 'meta', name: 'twitter:image', content:\n metadata.twitter.image\n })\n if (metadata.twitter?.creator) tags.push({\n tag: 'meta', name: 'twitter:creator', content:\n metadata.twitter.creator\n })\n\n if (metadata.canonical) tags.push({ tag: 'link', rel: 'canonical', href: metadata.canonical })\n if (metadata.robots) tags.push({ tag: 'meta', name: 'robots', content: metadata.robots })\n if (metadata.alternates) {\n for (const [lang, href] of Object.entries(metadata.alternates))\n tags.push({ tag: 'link', rel: 'alternate', href, hrefLang: lang })\n }\n\n if (metadata.icons) {\n const raw = Array.isArray(metadata.icons) ? metadata.icons : [metadata.icons]\n for (const icon of raw) {\n const resolved: MetadataIcon = typeof icon === 'string' ? { href: icon } : icon\n tags.push({\n tag: 'link',\n rel: resolved.rel ?? 'icon',\n href: resolved.href,\n ...(resolved.type && { type: resolved.type }),\n ...(resolved.sizes && { sizes: resolved.sizes }),\n })\n }\n }\n\n if (viewport) {\n const parts: string[] = []\n if (viewport.width !== undefined) parts.push(`width=${viewport.width}`)\n if (viewport.initialScale !== undefined) parts.push(`initial-scale=${viewport.initialScale}`)\n if (viewport.maximumScale !== undefined) parts.push(`maximum-scale=${viewport.maximumScale}`)\n if (viewport.userScalable !== undefined) parts.push(`user-scalable=${viewport.userScalable ? 'yes' :\n 'no'}`)\n if (parts.length) tags.push({ tag: 'meta', name: 'viewport', content: parts.join(', ') })\n if (viewport.themeColor) tags.push({\n tag: 'meta', name: 'theme-color', content: viewport.themeColor\n })\n }\n\n return tags\n}\n\nexport function HeadSlot({ metadata, viewport }: { metadata: Metadata | null, viewport?: Viewport }) {\n if (typeof window === 'undefined' || !metadata) return null\n return <>{buildHeadNodes(metadata, viewport)}</>\n}\n\nexport function buildHeadNodes(metadata: Metadata, viewport?: Viewport): ReactNode {\n const tags = collectTags(metadata, viewport)\n\n return <>\n {tags.map((t, i) => {\n if (t.tag === 'title') return <title key={i}>{t.children}</title>\n if (t.tag === 'link') return <link key={i} rel={t.rel} href={t.href} hrefLang={t.hrefLang} type={t.type} sizes={t.sizes} />\n return <meta key={i} name={t.name} property={t.property} content={t.content} />\n })}\n </>\n}", "import {createContext, Context, ComponentType} from \"react\";\nimport {Metadata, Viewport} from \"../types\";\nimport {LayoutProps, PageProps} from \"../server/types\";\n\nexport interface NavigateOptions {\n replace?: boolean\n viewTransition?: boolean\n}\n\nexport interface RouterContextValue {\n pathname: string\n params: Record<string, string>\n loaderData: unknown\n layoutsData: unknown[]\n guardData: unknown\n Page: ComponentType<PageProps>\n layouts: ComponentType<LayoutProps>[]\n metadata: Metadata | null\n viewport?: Viewport\n navigate: (to: string, options?: NavigateOptions) => Promise<void>\n revalidate: () => Promise<void>\n prefetchRoute: (href: string) => void\n isNavigating: boolean\n}\n\nexport interface PageMetaContextValue {\n metadata: Metadata | null\n viewport?: Viewport\n clientEntry?: string\n}\n\nexport interface RouteDataContextValue {\n loaderData: unknown\n params: Record<string, string>\n}\n\nconst g = globalThis as any\n\ng.__devix_RouterContext__ ??= createContext<RouterContextValue | null>(null)\nexport const RouterContext: Context<RouterContextValue | null> = g.__devix_RouterContext__\n\ng.__devix_PageMetaContext__ ??= createContext<PageMetaContextValue | null>(null)\ng.__devix_RouteDataContext__ ??= createContext<RouteDataContextValue | null>(null)\n\nexport const PageMetaContext: Context<PageMetaContextValue | null> = g.__devix_PageMetaContext__\nexport const RouteDataContext: Context<RouteDataContextValue | null> = g.__devix_RouteDataContext__\n\n", "import {Component, ComponentType, ReactNode} from \"react\";\nimport {ErrorProps} from \"../server/types\";\n\ninterface Props {\n ErrorPage?: ComponentType<ErrorProps>\n children: ReactNode\n}\n\ninterface State {\n error: ErrorProps | null\n}\n\nexport class DevixErrorBoundary extends Component<Props, State> {\n state: State = { error: null }\n\n static getDerivedStateFromError(err: unknown): State {\n if (err instanceof DevixError) {\n return {\n error: {statusCode: err.statusCode, message: err.message}\n }\n }\n return {\n error: {statusCode: 500, message: err instanceof Error ? err.message : 'Unknown error'}\n }\n }\n\n render() {\n if (this.state.error && this.props.ErrorPage) {\n return <this.props.ErrorPage {...this.state.error} />\n }\n if (this.state.error) {\n return <h1>{this.state.error.statusCode}</h1>\n }\n return this.props.children\n }\n}\n\nexport interface DevixErrorOptions {\n code?: string\n data?: unknown\n}\n\nexport class DevixError extends Error {\n statusCode: number\n code?: string\n data?: unknown\n constructor(statusCode: number, message: string, options?: DevixErrorOptions) {\n super(message)\n this.name = 'DevixError'\n this.statusCode = statusCode\n this.code = options?.code\n this.data = options?.data\n }\n}\n", "import {ComponentType, ReactNode} from 'react'\nimport {RouterContext, PageMetaContext, RouteDataContext, NavigateOptions} from './context'\nimport {HeadSlot} from './head'\nimport {DevixErrorBoundary} from './error-boundary'\nimport {LayoutProps, PageProps} from '../server/types'\nimport {Metadata, Viewport} from '../types'\n\nconst noopNavigate = (_to: string, _opts?: NavigateOptions) => Promise.resolve()\nconst noopRevalidate = () => Promise.resolve()\nconst noopPrefetch = (_href: string) => {}\n\nexport interface ServerAppProps {\n pathname: string\n params: Record<string, string>\n loaderData: unknown\n layoutsData: unknown[]\n guardData: unknown\n Page: ComponentType<PageProps>\n layouts: ComponentType<LayoutProps>[]\n metadata: Metadata | null\n viewport?: Viewport\n clientEntry: string\n}\n\nexport function ServerApp({\n pathname, params, loaderData, layoutsData, guardData,\n Page, layouts, metadata, viewport, clientEntry,\n}: ServerAppProps) {\n let tree: ReactNode = (\n <RouteDataContext value={{loaderData, params}}>\n <Page data={loaderData as any} params={params} url={pathname}/>\n </RouteDataContext>\n )\n\n for (let i = layouts.length - 1; i >= 0; i--) {\n const Layout = layouts[i]\n const layoutData = layoutsData[i]\n tree = (\n <RouteDataContext value={{loaderData: layoutData, params}}>\n <Layout data={layoutData as any} params={params}>{tree}</Layout>\n </RouteDataContext>\n )\n }\n\n return (\n <PageMetaContext value={{metadata, viewport, clientEntry}}>\n <HeadSlot metadata={metadata} viewport={viewport}/>\n <RouterContext value={{\n pathname,\n params,\n loaderData,\n layoutsData,\n guardData,\n Page,\n layouts,\n metadata,\n viewport,\n isNavigating: false,\n navigate: noopNavigate,\n revalidate: noopRevalidate,\n prefetchRoute: noopPrefetch,\n }}>\n <DevixErrorBoundary key={pathname}>\n {tree}\n </DevixErrorBoundary>\n </RouterContext>\n </PageMetaContext>\n )\n}\n", "export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aSegs = a.path.split('/').filter(Boolean)\n const bSegs = b.path.split('/').filter(Boolean)\n const len = Math.max(aSegs.length, bSegs.length)\n for (let i = 0; i < len; i++) {\n const aVal = i < aSegs.length ? (aSegs[i].startsWith(':') ? 1 : 2) : 0\n const bVal = i < bSegs.length ? (bSegs[i].startsWith(':') ? 1 : 2) : 0\n if (aVal !== bVal) return bVal - aVal\n }\n return b.path.length - a.path.length\n })\n\n return {pages, layouts}\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n", "import {LayoutModule, PageModule} from \"../server\";\nimport {LoaderContext, Metadata, Viewport} from \"../types\"\n\nexport interface ResolvedMeta {\n metadata: Metadata\n viewport?: Viewport\n}\n\nexport async function resolveMetadata(module: PageModule | LayoutModule, ctx: LoaderContext & {\n loaderData: unknown\n}): Promise<ResolvedMeta> {\n const metadata = module.generateMetadata\n ? await module.generateMetadata(ctx)\n : module.metadata ?? {}\n\n const viewport = module.generateViewport\n ? await module.generateViewport(ctx)\n : module.viewport\n\n return {metadata, viewport}\n}\n\nexport function mergeMetadata(...sources: (Metadata | null | undefined)[]): Metadata {\n const result: Metadata = {}\n\n for (const source of sources) {\n if (!source) continue\n const { og, twitter, ...rest } = source\n Object.assign(result, rest)\n if (og) result.og = { ...result.og, ...og }\n if (twitter) result.twitter = { ...result.twitter, ...twitter }\n }\n\n return result\n}", "export function safeJsonStringify(value: unknown): string {\n return JSON.stringify(value).replace(/<\\/script>/gi, '<\\\\/script>')\n}\n\nexport function escapeAttr(value: string): string {\n return value.replace(/\"/g, '"')\n}", "export function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n let timer: ReturnType<typeof setTimeout>\n return Promise.race([\n promise.finally(() => clearTimeout(timer)),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms)\n })\n ])\n}", "export type JsonResponse<T = unknown, S extends number = number> = Response & {\n readonly __body: T\n readonly __status: S\n}\n\nexport function json<const T>(data: T): JsonResponse<T, 200>\nexport function json<const T, const S extends number>(data: T, status: S): JsonResponse<T, S>\nexport function json<const T>(data: T, status: number = 200): JsonResponse<T, any> {\n return new Response(JSON.stringify(data), {\n status,\n headers: {'Content-Type': 'application/json'},\n }) as JsonResponse<T, any>\n}\n\nexport const text = (body: string, status = 200): Response =>\n new Response(body, {status, headers: {'Content-Type': 'text/plain; charset=utf-8'}})\n\nconst REDIRECT_BRAND = Symbol.for('devix.redirect')\n\nexport interface RedirectOptions {\n status?: number\n replace?: boolean\n}\n\nexport interface Redirect {\n readonly [REDIRECT_BRAND]: true\n readonly url: string\n readonly status: number\n readonly replace: boolean\n}\n\nexport function redirect(url: string, statusOrOptions?: number | RedirectOptions): Redirect {\n const status = typeof statusOrOptions === 'number' ? statusOrOptions : (statusOrOptions?.status ?? 302)\n const replace = typeof statusOrOptions === 'object' ? (statusOrOptions?.replace ?? false) : false\n return {[REDIRECT_BRAND]: true, url, status, replace} as Redirect\n}\n\nexport function isRedirect(value: unknown): value is Redirect {\n return typeof value === 'object' && value !== null && REDIRECT_BRAND in value\n}\n\nconst ERROR_BRAND = Symbol.for('devix.loaderError')\n\nexport interface RouteError {\n readonly [ERROR_BRAND]: true\n readonly statusCode: number\n readonly message: string\n readonly code?: string\n readonly data?: unknown\n}\n\nexport interface ErrorOptions {\n code?: string\n data?: unknown\n}\n\n/**\n * Crea un error tipado que funciona en loaders, guards y handlers API.\n *\n * En loaders/guards: ret\u00F3rnalo (no lo lances) y el sistema renderiza `error.tsx`.\n * En handlers API: ret\u00F3rnalo y el sistema serializa el shape `ErrorBody` como JSON\n * con el statusCode correcto.\n *\n * ```ts\n * return error(404, 'Post no encontrado', { code: 'POST_NOT_FOUND' })\n * ```\n */\nexport function error(statusCode: number, message: string, options?: ErrorOptions): RouteError {\n return {\n [ERROR_BRAND]: true,\n statusCode,\n message,\n code: options?.code,\n data: options?.data,\n } as RouteError\n}\n\nexport function isLoaderError(value: unknown): value is RouteError {\n return typeof value === 'object' && value !== null && ERROR_BRAND in value\n}\n\n/**\n * Shape p\u00FAblico del body de un error API. Todos los errores emitidos por `error()`\n * o `DevixError` se serializan a este shape. `FetchError.body` del cliente lo recibe.\n */\nexport interface ErrorBody {\n statusCode: number\n message: string\n code?: string\n data?: unknown\n}\n\nexport function errorToBody(err: { statusCode: number; message: string; code?: string; data?: unknown }): ErrorBody {\n const body: ErrorBody = { statusCode: err.statusCode, message: err.message }\n if (err.code !== undefined) body.code = err.code\n if (err.data !== undefined) body.data = err.data\n return body\n}\n", "export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'\n\nfunction extractMessage(body: unknown): string | null {\n if (body && typeof body === 'object' && 'message' in body) {\n const m = (body as {message: unknown}).message\n if (typeof m === 'string' && m.length > 0) return m\n }\n return null\n}\n\nexport class FetchError<E = unknown> extends Error {\n constructor(\n public readonly status: number,\n public readonly statusText: string,\n public readonly response: Response,\n public readonly body?: E,\n ) {\n super(extractMessage(body) ?? `HTTP ${status}: ${statusText}`)\n this.name = 'FetchError'\n }\n\n get code(): string | undefined {\n if (this.body && typeof this.body === 'object' && 'code' in this.body) {\n const c = (this.body as {code: unknown}).code\n return typeof c === 'string' ? c : undefined\n }\n return undefined\n }\n}\n", "/**\n * Match simple de path contra un glob estilo `'/v1/**'`, `'/v1/users/*'`, `'/v1/users/:id'`.\n *\n * Reglas:\n * - `**` matchea cualquier subpath (incluye `/`).\n * - `*` matchea un \u00FAnico segmento (sin `/`).\n * - `:param` matchea un \u00FAnico segmento.\n * - Cualquier otro caracter es literal.\n */\nexport function matchPathGlob(path: string, pattern: string): boolean {\n const regex = globToRegex(pattern)\n return regex.test(path)\n}\n\nexport function matchesAnyGlob(path: string, patterns: readonly string[] | undefined): boolean {\n if (!patterns || patterns.length === 0) return false\n for (const pattern of patterns) {\n if (matchPathGlob(path, pattern)) return true\n }\n return false\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let regex = ''\n let i = 0\n while (i < pattern.length) {\n const c = pattern[i]\n if (c === '*' && pattern[i + 1] === '*') {\n regex += '.*'\n i += 2\n } else if (c === '*') {\n regex += '[^/]*'\n i += 1\n } else if (c === ':') {\n i += 1\n while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) i += 1\n regex += '[^/]+'\n } else if ('.+?^$()|[]{}\\\\'.includes(c)) {\n regex += '\\\\' + c\n i += 1\n } else {\n regex += c\n i += 1\n }\n }\n return new RegExp(`^${regex}$`)\n}\n", "import {FetchError, type HttpMethod} from '../runtime/fetch'\nimport {matchesAnyGlob} from '../utils/glob'\nimport type {ServerBackendConfig, PrepareContext} from '../config'\nimport type {BackendClient} from '../runtime/server-client'\n\n/**\n * Construye un `$server` server-side bound al request del usuario.\n *\n * Diferencias clave vs el `$server` cliente:\n * - Hace fetch directo a `backend.url + path` (sin pasar por el proxy interno).\n * - Aplica `prepare` con el `Request` del loader/handler para que pueda leer cookies.\n * - Aplica allowlist/denylist por simetr\u00EDa con el proxy cliente.\n */\nexport function makeBoundServer(\n request: Request,\n config: Record<string, ServerBackendConfig> | undefined,\n): Record<string, BackendClient<string>> {\n if (!config) return new Proxy({} as any, {\n get(_t, namespace: string) {\n throw new Error(`[devix] ctx.$server.${String(namespace)} called but no 'server' config is defined in devix.config.ts`)\n },\n })\n\n const cache = new Map<string, BackendClient<string>>()\n return new Proxy({} as any, {\n get(_t, namespace: string) {\n if (typeof namespace !== 'string') return undefined\n const backend = config[namespace]\n if (!backend) {\n throw new Error(`[devix] ctx.$server.${namespace} \u2014 namespace \"${namespace}\" not configured in devix.config.ts`)\n }\n let client = cache.get(namespace)\n if (!client) {\n client = makeBackendClientBound(namespace, backend, request)\n cache.set(namespace, client)\n }\n return client\n },\n })\n}\n\nfunction makeBackendClientBound(\n _namespace: string,\n backend: ServerBackendConfig,\n userRequest: Request,\n): BackendClient<string> {\n async function call<TResult>(method: HttpMethod, path: string, body?: unknown, options?: {headers?: HeadersInit; signal?: AbortSignal}): Promise<TResult> {\n if (!matchesAnyGlob(path, backend.allowedPaths)) {\n throw new FetchError(403, 'Path not allowed', new Response(null, {status: 403}), {\n statusCode: 403, message: 'Path not allowed', code: 'PATH_NOT_ALLOWED',\n })\n }\n if (matchesAnyGlob(path, backend.deniedPaths)) {\n throw new FetchError(403, 'Path denied', new Response(null, {status: 403}), {\n statusCode: 403, message: 'Path denied', code: 'PATH_DENIED',\n })\n }\n\n const targetUrl = new URL(path, backend.url)\n const headers = new Headers(options?.headers)\n if (backend.prepare) {\n const ctx: PrepareContext = {request: userRequest, headers, url: targetUrl}\n const result = await backend.prepare(ctx)\n if (result instanceof Response) {\n throw new FetchError(\n result.status,\n result.statusText,\n result,\n await readErrorBody(result),\n )\n }\n }\n\n let sendBody: BodyInit | undefined\n if (body !== undefined && body !== null && method !== 'GET' && method !== 'HEAD') {\n if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer) {\n sendBody = body\n } else {\n sendBody = JSON.stringify(body)\n if (!headers.has('Content-Type')) headers.set('Content-Type', 'application/json')\n }\n }\n\n const response = await fetch(targetUrl, {method, headers, body: sendBody, signal: options?.signal})\n const isEmpty = response.status === 204 || response.headers.get('Content-Length') === '0'\n\n if (!response.ok) {\n const ct = response.headers.get('Content-Type') ?? ''\n let errorBody: unknown\n if (!isEmpty && ct.includes('application/json')) {\n try { errorBody = await response.json() } catch { /* body inv\u00E1lido */ }\n }\n throw new FetchError(response.status, response.statusText, response, errorBody)\n }\n\n if (isEmpty) return null as TResult\n\n const ct = response.headers.get('Content-Type') ?? ''\n if (ct.includes('application/json')) return await response.json() as TResult\n return await response.text() as unknown as TResult\n }\n\n return {\n get: ((path: string, options?: any) => call('GET', path, undefined, options)) as BackendClient<string>['get'],\n post: ((path: string, body?: any, options?: any) => call('POST', path, body, options)) as BackendClient<string>['post'],\n put: ((path: string, body?: any, options?: any) => call('PUT', path, body, options)) as BackendClient<string>['put'],\n patch: ((path: string, body?: any, options?: any) => call('PATCH', path, body, options)) as BackendClient<string>['patch'],\n delete: ((path: string, options?: any) => call('DELETE', path, undefined, options)) as BackendClient<string>['delete'],\n }\n}\n\nasync function readErrorBody(res: Response): Promise<unknown> {\n const ct = res.headers.get('Content-Type') ?? ''\n if (ct.includes('application/json')) {\n try { return await res.json() } catch { return undefined }\n }\n return undefined\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["createElement", "renderToString", "renderToStaticMarkup", "Fragment", "jsx", "collectTags", "metadata", "viewport", "tags", "ogTitle", "ogDesc", "twTitle", "twDesc", "lang", "href", "raw", "icon", "resolved", "parts", "HeadSlot", "buildHeadNodes", "t", "i", "createContext", "g", "RouterContext", "PageMetaContext", "RouteDataContext", "Component", "jsx", "DevixErrorBoundary", "err", "DevixError", "statusCode", "message", "options", "jsx", "jsxs", "noopNavigate", "_to", "_opts", "noopRevalidate", "noopPrefetch", "_href", "ServerApp", "pathname", "params", "loaderData", "layoutsData", "guardData", "Page", "layouts", "metadata", "viewport", "clientEntry", "tree", "RouteDataContext", "i", "Layout", "layoutData", "PageMetaContext", "HeadSlot", "RouterContext", "DevixErrorBoundary", "routePattern", "rel", "keyToRoutePattern", "key", "pagesDir", "rel", "pattern", "routePattern", "keyToDir", "buildPages", "pageKeys", "layoutKeys", "pages", "layouts", "params", "m", "regexStr", "b", "aSegs", "bSegs", "len", "i", "aVal", "bVal", "collectLayoutChain", "pageKey", "pageDir", "layout", "a", "matchPage", "pathname", "page", "match", "name", "resolveMetadata", "module", "ctx", "metadata", "viewport", "mergeMetadata", "sources", "result", "source", "og", "twitter", "rest", "safeJsonStringify", "value", "escapeAttr", "withTimeout", "promise", "ms", "timer", "_", "reject", "REDIRECT_BRAND", "isRedirect", "value", "REDIRECT_BRAND", "ERROR_BRAND", "isLoaderError", "value", "ERROR_BRAND", "errorToBody", "err", "body", "extractMessage", "body", "m", "FetchError", "status", "statusText", "response", "c", "matchPathGlob", "path", "pattern", "globToRegex", "matchesAnyGlob", "patterns", "regex", "i", "c", "makeBoundServer", "request", "config", "_t", "namespace", "cache", "backend", "client", "makeBackendClientBound", "_namespace", "userRequest", "call", "method", "path", "body", "options", "matchesAnyGlob", "FetchError", "targetUrl", "headers", "ctx", "result", "readErrorBody", "sendBody", "response", "isEmpty", "ct", "errorBody", "res", "DEFAULT_VIEWPORT", "pagesCache", "pagesCacheKey", "DEV_CLIENT_ENTRY", "extractRedirect", "result", "isRedirect", "resolvePageData", "pathname", "request", "glob", "timeout", "serverConfig", "cacheKey", "buildPages", "pages", "layouts", "matched", "matchPage", "page", "params", "layoutChain", "collectLayoutChain", "pageMod", "layoutMods", "guardData", "$server", "makeBoundServer", "mod", "r", "isLoaderError", "ctx", "rawLoaderData", "withTimeout", "loaderData", "rawLayoutsData", "raw", "layoutsData", "pageMeta", "resolveMetadata", "layoutsMeta", "i", "metadata", "mergeMetadata", "m", "viewport", "rootLayoutMod", "lang", "runLoader", "url", "options", "err", "render", "clientEntry", "chunk", "cssLinks", "dataScript", "safeJsonStringify", "clientScript", "errBody", "errorToBody", "content", "renderToString", "createElement", "ServerApp", "headTags", "renderToStaticMarkup", "buildHeadNodes", "customHeaders", "escapeAttr", "getStaticRoutes", "urls", "paramSets", "key", "value"]
|
|
7
7
|
}
|
package/dist/server/routes.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Hono } from 'hono';
|
|
2
2
|
import type { Manifest } from 'vite';
|
|
3
|
+
import type { ServerBackendConfig } from "../config";
|
|
3
4
|
interface ServerOptions {
|
|
4
5
|
renderModule: any;
|
|
5
6
|
apiModule: any;
|
|
6
7
|
manifest?: Manifest;
|
|
7
8
|
loaderTimeout?: number;
|
|
9
|
+
server?: Record<string, ServerBackendConfig>;
|
|
8
10
|
}
|
|
9
|
-
export declare function registerApiRoutes(app: Hono, { apiModule, renderModule, loaderTimeout }: ServerOptions): void;
|
|
10
|
-
export declare function registerSsrRoute(app: Hono, { renderModule, manifest, loaderTimeout }: ServerOptions): void;
|
|
11
|
+
export declare function registerApiRoutes(app: Hono, { apiModule, renderModule, loaderTimeout, server }: ServerOptions): void;
|
|
12
|
+
export declare function registerSsrRoute(app: Hono, { renderModule, manifest, loaderTimeout, server }: ServerOptions): void;
|
|
11
13
|
export {};
|
package/dist/server/routes.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function h(o,{
|
|
1
|
+
function p(e){let r={statusCode:e.statusCode,message:e.message};return e.code!==void 0&&(r.code=e.code),e.data!==void 0&&(r.data=e.data),r}function m(e,r){return g(r).test(e)}function f(e,r){if(!r||r.length===0)return!1;for(let t of r)if(m(e,t))return!0;return!1}function g(e){let r="",t=0;for(;t<e.length;){let n=e[t];if(n==="*"&&e[t+1]==="*")r+=".*",t+=2;else if(n==="*")r+="[^/]*",t+=1;else if(n===":"){for(t+=1;t<e.length&&/[a-zA-Z0-9_]/.test(e[t]);)t+=1;r+="[^/]+"}else".+?^$()|[]{}\\".includes(n)?(r+="\\"+n,t+=1):(r+=n,t+=1)}return new RegExp(`^${r}$`)}var y="/_devix/server";function l(e,r,t){let n=p({statusCode:e,message:r,code:t});return new Response(JSON.stringify(n),{status:e,headers:{"Content-Type":"application/json"}})}function x(e){if(!e.startsWith(y+"/"))return null;let r=e.slice(y.length+1),t=r.indexOf("/");return t===-1?{namespace:r,path:"/"}:{namespace:r.slice(0,t),path:r.slice(t)}}async function h(e,r){let t=new URL(e.url),n=x(t.pathname);if(!n)return l(404,"Not found","PROXY_NOT_FOUND");let i=r?.[n.namespace];if(!i)return l(404,`Backend "${n.namespace}" not configured`,"BACKEND_NOT_FOUND");if(!f(n.path,i.allowedPaths))return l(403,"Path not allowed","PATH_NOT_ALLOWED");if(f(n.path,i.deniedPaths))return l(403,"Path denied","PATH_DENIED");let o=new URL(n.path+t.search,i.url),a=new Headers;if(i.prepare){let s={request:e,headers:a,url:o};try{let c=await i.prepare(s);if(c instanceof Response)return c}catch(c){return console.error(`[devix] server.${n.namespace}.prepare error:`,c),l(500,"Proxy prepare failed","PREPARE_ERROR")}}if(!a.has("Accept")){let s=e.headers.get("Accept");s&&a.set("Accept",s)}let u=e.headers.get("Content-Type");u&&!a.has("Content-Type")&&a.set("Content-Type",u);let d=null;e.method!=="GET"&&e.method!=="HEAD"&&(d=await e.arrayBuffer(),d.byteLength===0&&(d=null));try{let s=await fetch(o,{method:e.method,headers:a,body:d,redirect:"manual"});return new Response(s.body,{status:s.status,statusText:s.statusText,headers:b(s.headers)})}catch(s){return console.error(`[devix] server.${n.namespace} fetch error:`,s),l(502,"Bad Gateway","BACKEND_UNREACHABLE")}}var E=new Set(["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailers","transfer-encoding","upgrade"]);function b(e){let r=new Headers;return e.forEach((t,n)=>{E.has(n.toLowerCase())||r.set(n,t)}),r}function A(e,{apiModule:r,renderModule:t,loaderTimeout:n,server:i}){i&&e.all("/_devix/server/*",async o=>{try{return await h(o.req.raw,i)}catch(a){return console.error("[devix] proxy fatal error:",a),o.json({statusCode:500,message:"Internal Server Error"},500)}}),e.all("/api/*",async o=>{try{return await r.handleApiRequest(o.req.url,o.req.raw,i)}catch(a){return console.error(a),o.json({statusCode:500,message:"Internal Server Error"},500)}}),e.get("/_data/*",async o=>{try{let{pathname:a,search:u}=new URL(o.req.url,"http://localhost"),d=a.replace(/^\/_data/,"")+u,s=await t.runLoader(d,o.req.raw,{loaderTimeout:n,server:i});if(s.error)return o.json({statusCode:500,message:"Internal Server Error"},500);if("loaderError"in s){let c=p(s.loaderError);return o.json(c,c.statusCode)}return o.json(s)}catch(a){return console.error(a),o.json({statusCode:500,message:"Internal Server Error"},500)}})}function v(e,{renderModule:r,manifest:t,loaderTimeout:n,server:i}){e.get("*",async o=>{try{let{html:a,statusCode:u,headers:d}=await r.render(o.req.url,o.req.raw,{manifest:t,loaderTimeout:n,server:i}),s=o.html(`<!DOCTYPE html>${a}`,u);for(let[c,R]of Object.entries(d))s.headers.set(c,R);return s}catch(a){return console.error(a),o.text("Internal Server Error",500)}})}export{A as registerApiRoutes,v as registerSsrRoute};
|
|
2
2
|
//# sourceMappingURL=routes.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/server/routes.ts"],
|
|
4
|
-
"sourcesContent": ["import type {Hono} from 'hono'\nimport type {Manifest} from 'vite'\n\ninterface ServerOptions {\n renderModule: any\n apiModule: any\n manifest?: Manifest\n loaderTimeout?: number\n}\n\nexport function registerApiRoutes(app: Hono, {apiModule, renderModule, loaderTimeout}: ServerOptions) {\n app.all('/api/*', async (c) => {\n try {\n return await apiModule.handleApiRequest(c.req.url, c.req.raw)\n } catch (e) {\n console.error(e)\n return c.json({error: 'internal error'}, 500)\n }\n })\n\n app.get('/_data/*', async (c) => {\n try {\n const {pathname, search} = new URL(c.req.url, 'http://localhost')\n const url = pathname.replace(/^\\/_data/, '') + search\n\n const data = await renderModule.runLoader(url, c.req.raw, {loaderTimeout})\n if (data.error) return c.json({error: 'internal error'}, 500)\n if ('loaderError' in data) {\n const {statusCode, message, data: errorData} = data.loaderError\n return c.json({statusCode, message, data: errorData}, statusCode)\n }\n return c.json(data)\n } catch (e) {\n console.error(e)\n return c.json({error: 'internal error'}, 500)\n }\n })\n}\n\nexport function registerSsrRoute(app: Hono, {renderModule, manifest, loaderTimeout}: ServerOptions) {\n app.get('*', async (c) => {\n try {\n const {html, statusCode, headers} = await renderModule.render(c.req.url, c.req.raw, {manifest, loaderTimeout})\n const res = c.html(`<!DOCTYPE html>${html}`, statusCode)\n for (const [key, value] of Object.entries(headers as Record<string, string>)) {\n res.headers.set(key, value)\n }\n return res\n } catch (e) {\n console.error(e)\n return c.text('Internal Server Error', 500)\n }\n })\n}"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["registerApiRoutes", "app", "apiModule", "renderModule", "loaderTimeout", "c", "pathname", "search", "url", "data", "
|
|
3
|
+
"sources": ["../../src/utils/response.ts", "../../src/utils/glob.ts", "../../src/server/server-proxy.ts", "../../src/server/routes.ts"],
|
|
4
|
+
"sourcesContent": ["export type JsonResponse<T = unknown, S extends number = number> = Response & {\n readonly __body: T\n readonly __status: S\n}\n\nexport function json<const T>(data: T): JsonResponse<T, 200>\nexport function json<const T, const S extends number>(data: T, status: S): JsonResponse<T, S>\nexport function json<const T>(data: T, status: number = 200): JsonResponse<T, any> {\n return new Response(JSON.stringify(data), {\n status,\n headers: {'Content-Type': 'application/json'},\n }) as JsonResponse<T, any>\n}\n\nexport const text = (body: string, status = 200): Response =>\n new Response(body, {status, headers: {'Content-Type': 'text/plain; charset=utf-8'}})\n\nconst REDIRECT_BRAND = Symbol.for('devix.redirect')\n\nexport interface RedirectOptions {\n status?: number\n replace?: boolean\n}\n\nexport interface Redirect {\n readonly [REDIRECT_BRAND]: true\n readonly url: string\n readonly status: number\n readonly replace: boolean\n}\n\nexport function redirect(url: string, statusOrOptions?: number | RedirectOptions): Redirect {\n const status = typeof statusOrOptions === 'number' ? statusOrOptions : (statusOrOptions?.status ?? 302)\n const replace = typeof statusOrOptions === 'object' ? (statusOrOptions?.replace ?? false) : false\n return {[REDIRECT_BRAND]: true, url, status, replace} as Redirect\n}\n\nexport function isRedirect(value: unknown): value is Redirect {\n return typeof value === 'object' && value !== null && REDIRECT_BRAND in value\n}\n\nconst ERROR_BRAND = Symbol.for('devix.loaderError')\n\nexport interface RouteError {\n readonly [ERROR_BRAND]: true\n readonly statusCode: number\n readonly message: string\n readonly code?: string\n readonly data?: unknown\n}\n\nexport interface ErrorOptions {\n code?: string\n data?: unknown\n}\n\n/**\n * Crea un error tipado que funciona en loaders, guards y handlers API.\n *\n * En loaders/guards: ret\u00F3rnalo (no lo lances) y el sistema renderiza `error.tsx`.\n * En handlers API: ret\u00F3rnalo y el sistema serializa el shape `ErrorBody` como JSON\n * con el statusCode correcto.\n *\n * ```ts\n * return error(404, 'Post no encontrado', { code: 'POST_NOT_FOUND' })\n * ```\n */\nexport function error(statusCode: number, message: string, options?: ErrorOptions): RouteError {\n return {\n [ERROR_BRAND]: true,\n statusCode,\n message,\n code: options?.code,\n data: options?.data,\n } as RouteError\n}\n\nexport function isLoaderError(value: unknown): value is RouteError {\n return typeof value === 'object' && value !== null && ERROR_BRAND in value\n}\n\n/**\n * Shape p\u00FAblico del body de un error API. Todos los errores emitidos por `error()`\n * o `DevixError` se serializan a este shape. `FetchError.body` del cliente lo recibe.\n */\nexport interface ErrorBody {\n statusCode: number\n message: string\n code?: string\n data?: unknown\n}\n\nexport function errorToBody(err: { statusCode: number; message: string; code?: string; data?: unknown }): ErrorBody {\n const body: ErrorBody = { statusCode: err.statusCode, message: err.message }\n if (err.code !== undefined) body.code = err.code\n if (err.data !== undefined) body.data = err.data\n return body\n}\n", "/**\n * Match simple de path contra un glob estilo `'/v1/**'`, `'/v1/users/*'`, `'/v1/users/:id'`.\n *\n * Reglas:\n * - `**` matchea cualquier subpath (incluye `/`).\n * - `*` matchea un \u00FAnico segmento (sin `/`).\n * - `:param` matchea un \u00FAnico segmento.\n * - Cualquier otro caracter es literal.\n */\nexport function matchPathGlob(path: string, pattern: string): boolean {\n const regex = globToRegex(pattern)\n return regex.test(path)\n}\n\nexport function matchesAnyGlob(path: string, patterns: readonly string[] | undefined): boolean {\n if (!patterns || patterns.length === 0) return false\n for (const pattern of patterns) {\n if (matchPathGlob(path, pattern)) return true\n }\n return false\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let regex = ''\n let i = 0\n while (i < pattern.length) {\n const c = pattern[i]\n if (c === '*' && pattern[i + 1] === '*') {\n regex += '.*'\n i += 2\n } else if (c === '*') {\n regex += '[^/]*'\n i += 1\n } else if (c === ':') {\n i += 1\n while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) i += 1\n regex += '[^/]+'\n } else if ('.+?^$()|[]{}\\\\'.includes(c)) {\n regex += '\\\\' + c\n i += 1\n } else {\n regex += c\n i += 1\n }\n }\n return new RegExp(`^${regex}$`)\n}\n", "import type {ServerBackendConfig, PrepareContext} from '../config'\nimport {matchesAnyGlob} from '../utils/glob'\nimport {errorToBody} from '../utils/response'\n\nconst PROXY_PREFIX = '/_devix/server'\n\nfunction jsonError(statusCode: number, message: string, code?: string): Response {\n const body = errorToBody({statusCode, message, code})\n return new Response(JSON.stringify(body), {\n status: statusCode,\n headers: {'Content-Type': 'application/json'},\n })\n}\n\n/**\n * Parsea `/_devix/server/<namespace>/<path>` \u2192 `{namespace, path}`.\n * Retorna null si el path no es un request al proxy.\n */\nexport function parseProxyPath(pathname: string): {namespace: string; path: string} | null {\n if (!pathname.startsWith(PROXY_PREFIX + '/')) return null\n const rest = pathname.slice(PROXY_PREFIX.length + 1)\n const slash = rest.indexOf('/')\n if (slash === -1) {\n return {namespace: rest, path: '/'}\n }\n return {namespace: rest.slice(0, slash), path: rest.slice(slash)}\n}\n\n/**\n * Maneja un request entrante al proxy interno. Aplica allowlist/denylist,\n * ejecuta `prepare`, y reenv\u00EDa al backend configurado.\n */\nexport async function handleProxyRequest(\n request: Request,\n config: Record<string, ServerBackendConfig> | undefined,\n): Promise<Response> {\n const url = new URL(request.url)\n const parsed = parseProxyPath(url.pathname)\n if (!parsed) {\n return jsonError(404, 'Not found', 'PROXY_NOT_FOUND')\n }\n\n const backend = config?.[parsed.namespace]\n if (!backend) {\n return jsonError(404, `Backend \"${parsed.namespace}\" not configured`, 'BACKEND_NOT_FOUND')\n }\n\n if (!matchesAnyGlob(parsed.path, backend.allowedPaths)) {\n return jsonError(403, 'Path not allowed', 'PATH_NOT_ALLOWED')\n }\n if (matchesAnyGlob(parsed.path, backend.deniedPaths)) {\n return jsonError(403, 'Path denied', 'PATH_DENIED')\n }\n\n const targetUrl = new URL(parsed.path + url.search, backend.url)\n const headers = new Headers()\n\n if (backend.prepare) {\n const ctx: PrepareContext = {request, headers, url: targetUrl}\n try {\n const result = await backend.prepare(ctx)\n if (result instanceof Response) return result\n } catch (err) {\n console.error(`[devix] server.${parsed.namespace}.prepare error:`, err)\n return jsonError(500, 'Proxy prepare failed', 'PREPARE_ERROR')\n }\n }\n\n if (!headers.has('Accept')) {\n const accept = request.headers.get('Accept')\n if (accept) headers.set('Accept', accept)\n }\n const ct = request.headers.get('Content-Type')\n if (ct && !headers.has('Content-Type')) headers.set('Content-Type', ct)\n\n let body: BodyInit | null = null\n if (request.method !== 'GET' && request.method !== 'HEAD') {\n body = await request.arrayBuffer()\n if ((body as ArrayBuffer).byteLength === 0) body = null\n }\n\n try {\n const backendRes = await fetch(targetUrl, {\n method: request.method,\n headers,\n body,\n redirect: 'manual',\n })\n return new Response(backendRes.body, {\n status: backendRes.status,\n statusText: backendRes.statusText,\n headers: filterHopByHop(backendRes.headers),\n })\n } catch (err) {\n console.error(`[devix] server.${parsed.namespace} fetch error:`, err)\n return jsonError(502, 'Bad Gateway', 'BACKEND_UNREACHABLE')\n }\n}\n\nconst HOP_BY_HOP = new Set([\n 'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization',\n 'te', 'trailers', 'transfer-encoding', 'upgrade',\n])\n\nfunction filterHopByHop(src: Headers): Headers {\n const dst = new Headers()\n src.forEach((value, key) => {\n if (!HOP_BY_HOP.has(key.toLowerCase())) dst.set(key, value)\n })\n return dst\n}\n\nexport const PROXY_PATH_PREFIX = PROXY_PREFIX\n", "import type {Hono} from 'hono'\nimport type {ContentfulStatusCode} from 'hono/utils/http-status'\nimport type {Manifest} from 'vite'\nimport {errorToBody} from \"../utils/response\"\nimport type {ServerBackendConfig} from \"../config\"\nimport {handleProxyRequest} from \"./server-proxy\"\n\ninterface ServerOptions {\n renderModule: any\n apiModule: any\n manifest?: Manifest\n loaderTimeout?: number\n server?: Record<string, ServerBackendConfig>\n}\n\nexport function registerApiRoutes(app: Hono, {apiModule, renderModule, loaderTimeout, server}: ServerOptions) {\n if (server) {\n app.all('/_devix/server/*', async (c) => {\n try {\n return await handleProxyRequest(c.req.raw, server)\n } catch (e) {\n console.error('[devix] proxy fatal error:', e)\n return c.json({statusCode: 500, message: 'Internal Server Error'}, 500)\n }\n })\n }\n\n app.all('/api/*', async (c) => {\n try {\n return await apiModule.handleApiRequest(c.req.url, c.req.raw, server)\n } catch (e) {\n console.error(e)\n return c.json({statusCode: 500, message: 'Internal Server Error'}, 500)\n }\n })\n\n app.get('/_data/*', async (c) => {\n try {\n const {pathname, search} = new URL(c.req.url, 'http://localhost')\n const url = pathname.replace(/^\\/_data/, '') + search\n\n const data = await renderModule.runLoader(url, c.req.raw, {loaderTimeout, server})\n if (data.error) return c.json({statusCode: 500, message: 'Internal Server Error'}, 500)\n if ('loaderError' in data) {\n const body = errorToBody(data.loaderError)\n return c.json(body, body.statusCode as ContentfulStatusCode)\n }\n return c.json(data)\n } catch (e) {\n console.error(e)\n return c.json({statusCode: 500, message: 'Internal Server Error'}, 500)\n }\n })\n}\n\nexport function registerSsrRoute(app: Hono, {renderModule, manifest, loaderTimeout, server}: ServerOptions) {\n app.get('*', async (c) => {\n try {\n const {html, statusCode, headers} = await renderModule.render(c.req.url, c.req.raw, {manifest, loaderTimeout, server})\n const res = c.html(`<!DOCTYPE html>${html}`, statusCode)\n for (const [key, value] of Object.entries(headers as Record<string, string>)) {\n res.headers.set(key, value)\n }\n return res\n } catch (e) {\n console.error(e)\n return c.text('Internal Server Error', 500)\n }\n })\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["errorToBody", "err", "body", "matchPathGlob", "path", "pattern", "globToRegex", "matchesAnyGlob", "patterns", "regex", "i", "c", "PROXY_PREFIX", "jsonError", "statusCode", "message", "code", "body", "errorToBody", "parseProxyPath", "pathname", "rest", "slash", "handleProxyRequest", "request", "config", "url", "parsed", "backend", "matchesAnyGlob", "targetUrl", "headers", "ctx", "result", "err", "accept", "ct", "backendRes", "filterHopByHop", "HOP_BY_HOP", "src", "dst", "value", "key", "registerApiRoutes", "app", "apiModule", "renderModule", "loaderTimeout", "server", "c", "handleProxyRequest", "e", "pathname", "search", "url", "data", "body", "errorToBody", "registerSsrRoute", "manifest", "html", "statusCode", "headers", "res", "key", "value"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ServerBackendConfig } from '../config';
|
|
2
|
+
import type { BackendClient } from '../runtime/server-client';
|
|
3
|
+
/**
|
|
4
|
+
* Construye un `$server` server-side bound al request del usuario.
|
|
5
|
+
*
|
|
6
|
+
* Diferencias clave vs el `$server` cliente:
|
|
7
|
+
* - Hace fetch directo a `backend.url + path` (sin pasar por el proxy interno).
|
|
8
|
+
* - Aplica `prepare` con el `Request` del loader/handler para que pueda leer cookies.
|
|
9
|
+
* - Aplica allowlist/denylist por simetría con el proxy cliente.
|
|
10
|
+
*/
|
|
11
|
+
export declare function makeBoundServer(request: Request, config: Record<string, ServerBackendConfig> | undefined): Record<string, BackendClient<string>>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function y(r){if(r&&typeof r=="object"&&"message"in r){let e=r.message;if(typeof e=="string"&&e.length>0)return e}return null}var c=class extends Error{constructor(n,o,t,s){super(y(s)??`HTTP ${n}: ${o}`);this.status=n;this.statusText=o;this.response=t;this.body=s;this.name="FetchError"}get code(){if(this.body&&typeof this.body=="object"&&"code"in this.body){let n=this.body.code;return typeof n=="string"?n:void 0}}};function T(r,e){return x(e).test(r)}function g(r,e){if(!e||e.length===0)return!1;for(let n of e)if(T(r,n))return!0;return!1}function x(r){let e="",n=0;for(;n<r.length;){let o=r[n];if(o==="*"&&r[n+1]==="*")e+=".*",n+=2;else if(o==="*")e+="[^/]*",n+=1;else if(o===":"){for(n+=1;n<r.length&&/[a-zA-Z0-9_]/.test(r[n]);)n+=1;e+="[^/]+"}else".+?^$()|[]{}\\".includes(o)?(e+="\\"+o,n+=1):(e+=o,n+=1)}return new RegExp(`^${e}$`)}function v(r,e){if(!e)return new Proxy({},{get(o,t){throw new Error(`[devix] ctx.$server.${String(t)} called but no 'server' config is defined in devix.config.ts`)}});let n=new Map;return new Proxy({},{get(o,t){if(typeof t!="string")return;let s=e[t];if(!s)throw new Error(`[devix] ctx.$server.${t} \u2014 namespace "${t}" not configured in devix.config.ts`);let i=n.get(t);return i||(i=C(t,s,r),n.set(t,i)),i}})}function C(r,e,n){async function o(t,s,i,p){if(!g(s,e.allowedPaths))throw new c(403,"Path not allowed",new Response(null,{status:403}),{statusCode:403,message:"Path not allowed",code:"PATH_NOT_ALLOWED"});if(g(s,e.deniedPaths))throw new c(403,"Path denied",new Response(null,{status:403}),{statusCode:403,message:"Path denied",code:"PATH_DENIED"});let h=new URL(s,e.url),l=new Headers(p?.headers);if(e.prepare){let f={request:n,headers:l,url:h},u=await e.prepare(f);if(u instanceof Response)throw new c(u.status,u.statusText,u,await E(u))}let d;i!=null&&t!=="GET"&&t!=="HEAD"&&(i instanceof FormData||i instanceof Blob||i instanceof ArrayBuffer?d=i:(d=JSON.stringify(i),l.has("Content-Type")||l.set("Content-Type","application/json")));let a=await fetch(h,{method:t,headers:l,body:d,signal:p?.signal}),w=a.status===204||a.headers.get("Content-Length")==="0";if(!a.ok){let f=a.headers.get("Content-Type")??"",u;if(!w&&f.includes("application/json"))try{u=await a.json()}catch{}throw new c(a.status,a.statusText,a,u)}return w?null:(a.headers.get("Content-Type")??"").includes("application/json")?await a.json():await a.text()}return{get:((t,s)=>o("GET",t,void 0,s)),post:((t,s,i)=>o("POST",t,s,i)),put:((t,s,i)=>o("PUT",t,s,i)),patch:((t,s,i)=>o("PATCH",t,s,i)),delete:((t,s)=>o("DELETE",t,void 0,s))}}async function E(r){if((r.headers.get("Content-Type")??"").includes("application/json"))try{return await r.json()}catch{return}}export{v as makeBoundServer};
|
|
2
|
+
//# sourceMappingURL=server-bound.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/runtime/fetch.ts", "../../src/utils/glob.ts", "../../src/server/server-bound.ts"],
|
|
4
|
+
"sourcesContent": ["export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'\n\nfunction extractMessage(body: unknown): string | null {\n if (body && typeof body === 'object' && 'message' in body) {\n const m = (body as {message: unknown}).message\n if (typeof m === 'string' && m.length > 0) return m\n }\n return null\n}\n\nexport class FetchError<E = unknown> extends Error {\n constructor(\n public readonly status: number,\n public readonly statusText: string,\n public readonly response: Response,\n public readonly body?: E,\n ) {\n super(extractMessage(body) ?? `HTTP ${status}: ${statusText}`)\n this.name = 'FetchError'\n }\n\n get code(): string | undefined {\n if (this.body && typeof this.body === 'object' && 'code' in this.body) {\n const c = (this.body as {code: unknown}).code\n return typeof c === 'string' ? c : undefined\n }\n return undefined\n }\n}\n", "/**\n * Match simple de path contra un glob estilo `'/v1/**'`, `'/v1/users/*'`, `'/v1/users/:id'`.\n *\n * Reglas:\n * - `**` matchea cualquier subpath (incluye `/`).\n * - `*` matchea un \u00FAnico segmento (sin `/`).\n * - `:param` matchea un \u00FAnico segmento.\n * - Cualquier otro caracter es literal.\n */\nexport function matchPathGlob(path: string, pattern: string): boolean {\n const regex = globToRegex(pattern)\n return regex.test(path)\n}\n\nexport function matchesAnyGlob(path: string, patterns: readonly string[] | undefined): boolean {\n if (!patterns || patterns.length === 0) return false\n for (const pattern of patterns) {\n if (matchPathGlob(path, pattern)) return true\n }\n return false\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let regex = ''\n let i = 0\n while (i < pattern.length) {\n const c = pattern[i]\n if (c === '*' && pattern[i + 1] === '*') {\n regex += '.*'\n i += 2\n } else if (c === '*') {\n regex += '[^/]*'\n i += 1\n } else if (c === ':') {\n i += 1\n while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) i += 1\n regex += '[^/]+'\n } else if ('.+?^$()|[]{}\\\\'.includes(c)) {\n regex += '\\\\' + c\n i += 1\n } else {\n regex += c\n i += 1\n }\n }\n return new RegExp(`^${regex}$`)\n}\n", "import {FetchError, type HttpMethod} from '../runtime/fetch'\nimport {matchesAnyGlob} from '../utils/glob'\nimport type {ServerBackendConfig, PrepareContext} from '../config'\nimport type {BackendClient} from '../runtime/server-client'\n\n/**\n * Construye un `$server` server-side bound al request del usuario.\n *\n * Diferencias clave vs el `$server` cliente:\n * - Hace fetch directo a `backend.url + path` (sin pasar por el proxy interno).\n * - Aplica `prepare` con el `Request` del loader/handler para que pueda leer cookies.\n * - Aplica allowlist/denylist por simetr\u00EDa con el proxy cliente.\n */\nexport function makeBoundServer(\n request: Request,\n config: Record<string, ServerBackendConfig> | undefined,\n): Record<string, BackendClient<string>> {\n if (!config) return new Proxy({} as any, {\n get(_t, namespace: string) {\n throw new Error(`[devix] ctx.$server.${String(namespace)} called but no 'server' config is defined in devix.config.ts`)\n },\n })\n\n const cache = new Map<string, BackendClient<string>>()\n return new Proxy({} as any, {\n get(_t, namespace: string) {\n if (typeof namespace !== 'string') return undefined\n const backend = config[namespace]\n if (!backend) {\n throw new Error(`[devix] ctx.$server.${namespace} \u2014 namespace \"${namespace}\" not configured in devix.config.ts`)\n }\n let client = cache.get(namespace)\n if (!client) {\n client = makeBackendClientBound(namespace, backend, request)\n cache.set(namespace, client)\n }\n return client\n },\n })\n}\n\nfunction makeBackendClientBound(\n _namespace: string,\n backend: ServerBackendConfig,\n userRequest: Request,\n): BackendClient<string> {\n async function call<TResult>(method: HttpMethod, path: string, body?: unknown, options?: {headers?: HeadersInit; signal?: AbortSignal}): Promise<TResult> {\n if (!matchesAnyGlob(path, backend.allowedPaths)) {\n throw new FetchError(403, 'Path not allowed', new Response(null, {status: 403}), {\n statusCode: 403, message: 'Path not allowed', code: 'PATH_NOT_ALLOWED',\n })\n }\n if (matchesAnyGlob(path, backend.deniedPaths)) {\n throw new FetchError(403, 'Path denied', new Response(null, {status: 403}), {\n statusCode: 403, message: 'Path denied', code: 'PATH_DENIED',\n })\n }\n\n const targetUrl = new URL(path, backend.url)\n const headers = new Headers(options?.headers)\n if (backend.prepare) {\n const ctx: PrepareContext = {request: userRequest, headers, url: targetUrl}\n const result = await backend.prepare(ctx)\n if (result instanceof Response) {\n throw new FetchError(\n result.status,\n result.statusText,\n result,\n await readErrorBody(result),\n )\n }\n }\n\n let sendBody: BodyInit | undefined\n if (body !== undefined && body !== null && method !== 'GET' && method !== 'HEAD') {\n if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer) {\n sendBody = body\n } else {\n sendBody = JSON.stringify(body)\n if (!headers.has('Content-Type')) headers.set('Content-Type', 'application/json')\n }\n }\n\n const response = await fetch(targetUrl, {method, headers, body: sendBody, signal: options?.signal})\n const isEmpty = response.status === 204 || response.headers.get('Content-Length') === '0'\n\n if (!response.ok) {\n const ct = response.headers.get('Content-Type') ?? ''\n let errorBody: unknown\n if (!isEmpty && ct.includes('application/json')) {\n try { errorBody = await response.json() } catch { /* body inv\u00E1lido */ }\n }\n throw new FetchError(response.status, response.statusText, response, errorBody)\n }\n\n if (isEmpty) return null as TResult\n\n const ct = response.headers.get('Content-Type') ?? ''\n if (ct.includes('application/json')) return await response.json() as TResult\n return await response.text() as unknown as TResult\n }\n\n return {\n get: ((path: string, options?: any) => call('GET', path, undefined, options)) as BackendClient<string>['get'],\n post: ((path: string, body?: any, options?: any) => call('POST', path, body, options)) as BackendClient<string>['post'],\n put: ((path: string, body?: any, options?: any) => call('PUT', path, body, options)) as BackendClient<string>['put'],\n patch: ((path: string, body?: any, options?: any) => call('PATCH', path, body, options)) as BackendClient<string>['patch'],\n delete: ((path: string, options?: any) => call('DELETE', path, undefined, options)) as BackendClient<string>['delete'],\n }\n}\n\nasync function readErrorBody(res: Response): Promise<unknown> {\n const ct = res.headers.get('Content-Type') ?? ''\n if (ct.includes('application/json')) {\n try { return await res.json() } catch { return undefined }\n }\n return undefined\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["extractMessage", "body", "m", "FetchError", "status", "statusText", "response", "c", "matchPathGlob", "path", "pattern", "globToRegex", "matchesAnyGlob", "patterns", "regex", "i", "c", "makeBoundServer", "request", "config", "_t", "namespace", "cache", "backend", "client", "makeBackendClientBound", "_namespace", "userRequest", "call", "method", "path", "body", "options", "matchesAnyGlob", "FetchError", "targetUrl", "headers", "ctx", "result", "readErrorBody", "sendBody", "response", "isEmpty", "ct", "errorBody", "res"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ServerBackendConfig } from '../config';
|
|
2
|
+
/**
|
|
3
|
+
* Parsea `/_devix/server/<namespace>/<path>` → `{namespace, path}`.
|
|
4
|
+
* Retorna null si el path no es un request al proxy.
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseProxyPath(pathname: string): {
|
|
7
|
+
namespace: string;
|
|
8
|
+
path: string;
|
|
9
|
+
} | null;
|
|
10
|
+
/**
|
|
11
|
+
* Maneja un request entrante al proxy interno. Aplica allowlist/denylist,
|
|
12
|
+
* ejecuta `prepare`, y reenvía al backend configurado.
|
|
13
|
+
*/
|
|
14
|
+
export declare function handleProxyRequest(request: Request, config: Record<string, ServerBackendConfig> | undefined): Promise<Response>;
|
|
15
|
+
export declare const PROXY_PATH_PREFIX = "/_devix/server";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function y(e,n){return g(n).test(e)}function u(e,n){if(!n||n.length===0)return!1;for(let t of n)if(y(e,t))return!0;return!1}function g(e){let n="",t=0;for(;t<e.length;){let r=e[t];if(r==="*"&&e[t+1]==="*")n+=".*",t+=2;else if(r==="*")n+="[^/]*",t+=1;else if(r===":"){for(t+=1;t<e.length&&/[a-zA-Z0-9_]/.test(e[t]);)t+=1;n+="[^/]+"}else".+?^$()|[]{}\\".includes(r)?(n+="\\"+r,t+=1):(n+=r,t+=1)}return new RegExp(`^${n}$`)}function R(e){let n={statusCode:e.statusCode,message:e.message};return e.code!==void 0&&(n.code=e.code),e.data!==void 0&&(n.data=e.data),n}var p="/_devix/server";function i(e,n,t){let r=R({statusCode:e,message:n,code:t});return new Response(JSON.stringify(r),{status:e,headers:{"Content-Type":"application/json"}})}function h(e){if(!e.startsWith(p+"/"))return null;let n=e.slice(p.length+1),t=n.indexOf("/");return t===-1?{namespace:n,path:"/"}:{namespace:n.slice(0,t),path:n.slice(t)}}async function P(e,n){let t=new URL(e.url),r=h(t.pathname);if(!r)return i(404,"Not found","PROXY_NOT_FOUND");let s=n?.[r.namespace];if(!s)return i(404,`Backend "${r.namespace}" not configured`,"BACKEND_NOT_FOUND");if(!u(r.path,s.allowedPaths))return i(403,"Path not allowed","PATH_NOT_ALLOWED");if(u(r.path,s.deniedPaths))return i(403,"Path denied","PATH_DENIED");let l=new URL(r.path+t.search,s.url),a=new Headers;if(s.prepare){let o={request:e,headers:a,url:l};try{let d=await s.prepare(o);if(d instanceof Response)return d}catch(d){return console.error(`[devix] server.${r.namespace}.prepare error:`,d),i(500,"Proxy prepare failed","PREPARE_ERROR")}}if(!a.has("Accept")){let o=e.headers.get("Accept");o&&a.set("Accept",o)}let f=e.headers.get("Content-Type");f&&!a.has("Content-Type")&&a.set("Content-Type",f);let c=null;e.method!=="GET"&&e.method!=="HEAD"&&(c=await e.arrayBuffer(),c.byteLength===0&&(c=null));try{let o=await fetch(l,{method:e.method,headers:a,body:c,redirect:"manual"});return new Response(o.body,{status:o.status,statusText:o.statusText,headers:m(o.headers)})}catch(o){return console.error(`[devix] server.${r.namespace} fetch error:`,o),i(502,"Bad Gateway","BACKEND_UNREACHABLE")}}var x=new Set(["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailers","transfer-encoding","upgrade"]);function m(e){let n=new Headers;return e.forEach((t,r)=>{x.has(r.toLowerCase())||n.set(r,t)}),n}var _=p;export{_ as PROXY_PATH_PREFIX,P as handleProxyRequest,h as parseProxyPath};
|
|
2
|
+
//# sourceMappingURL=server-proxy.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/glob.ts", "../../src/utils/response.ts", "../../src/server/server-proxy.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Match simple de path contra un glob estilo `'/v1/**'`, `'/v1/users/*'`, `'/v1/users/:id'`.\n *\n * Reglas:\n * - `**` matchea cualquier subpath (incluye `/`).\n * - `*` matchea un \u00FAnico segmento (sin `/`).\n * - `:param` matchea un \u00FAnico segmento.\n * - Cualquier otro caracter es literal.\n */\nexport function matchPathGlob(path: string, pattern: string): boolean {\n const regex = globToRegex(pattern)\n return regex.test(path)\n}\n\nexport function matchesAnyGlob(path: string, patterns: readonly string[] | undefined): boolean {\n if (!patterns || patterns.length === 0) return false\n for (const pattern of patterns) {\n if (matchPathGlob(path, pattern)) return true\n }\n return false\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let regex = ''\n let i = 0\n while (i < pattern.length) {\n const c = pattern[i]\n if (c === '*' && pattern[i + 1] === '*') {\n regex += '.*'\n i += 2\n } else if (c === '*') {\n regex += '[^/]*'\n i += 1\n } else if (c === ':') {\n i += 1\n while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) i += 1\n regex += '[^/]+'\n } else if ('.+?^$()|[]{}\\\\'.includes(c)) {\n regex += '\\\\' + c\n i += 1\n } else {\n regex += c\n i += 1\n }\n }\n return new RegExp(`^${regex}$`)\n}\n", "export type JsonResponse<T = unknown, S extends number = number> = Response & {\n readonly __body: T\n readonly __status: S\n}\n\nexport function json<const T>(data: T): JsonResponse<T, 200>\nexport function json<const T, const S extends number>(data: T, status: S): JsonResponse<T, S>\nexport function json<const T>(data: T, status: number = 200): JsonResponse<T, any> {\n return new Response(JSON.stringify(data), {\n status,\n headers: {'Content-Type': 'application/json'},\n }) as JsonResponse<T, any>\n}\n\nexport const text = (body: string, status = 200): Response =>\n new Response(body, {status, headers: {'Content-Type': 'text/plain; charset=utf-8'}})\n\nconst REDIRECT_BRAND = Symbol.for('devix.redirect')\n\nexport interface RedirectOptions {\n status?: number\n replace?: boolean\n}\n\nexport interface Redirect {\n readonly [REDIRECT_BRAND]: true\n readonly url: string\n readonly status: number\n readonly replace: boolean\n}\n\nexport function redirect(url: string, statusOrOptions?: number | RedirectOptions): Redirect {\n const status = typeof statusOrOptions === 'number' ? statusOrOptions : (statusOrOptions?.status ?? 302)\n const replace = typeof statusOrOptions === 'object' ? (statusOrOptions?.replace ?? false) : false\n return {[REDIRECT_BRAND]: true, url, status, replace} as Redirect\n}\n\nexport function isRedirect(value: unknown): value is Redirect {\n return typeof value === 'object' && value !== null && REDIRECT_BRAND in value\n}\n\nconst ERROR_BRAND = Symbol.for('devix.loaderError')\n\nexport interface RouteError {\n readonly [ERROR_BRAND]: true\n readonly statusCode: number\n readonly message: string\n readonly code?: string\n readonly data?: unknown\n}\n\nexport interface ErrorOptions {\n code?: string\n data?: unknown\n}\n\n/**\n * Crea un error tipado que funciona en loaders, guards y handlers API.\n *\n * En loaders/guards: ret\u00F3rnalo (no lo lances) y el sistema renderiza `error.tsx`.\n * En handlers API: ret\u00F3rnalo y el sistema serializa el shape `ErrorBody` como JSON\n * con el statusCode correcto.\n *\n * ```ts\n * return error(404, 'Post no encontrado', { code: 'POST_NOT_FOUND' })\n * ```\n */\nexport function error(statusCode: number, message: string, options?: ErrorOptions): RouteError {\n return {\n [ERROR_BRAND]: true,\n statusCode,\n message,\n code: options?.code,\n data: options?.data,\n } as RouteError\n}\n\nexport function isLoaderError(value: unknown): value is RouteError {\n return typeof value === 'object' && value !== null && ERROR_BRAND in value\n}\n\n/**\n * Shape p\u00FAblico del body de un error API. Todos los errores emitidos por `error()`\n * o `DevixError` se serializan a este shape. `FetchError.body` del cliente lo recibe.\n */\nexport interface ErrorBody {\n statusCode: number\n message: string\n code?: string\n data?: unknown\n}\n\nexport function errorToBody(err: { statusCode: number; message: string; code?: string; data?: unknown }): ErrorBody {\n const body: ErrorBody = { statusCode: err.statusCode, message: err.message }\n if (err.code !== undefined) body.code = err.code\n if (err.data !== undefined) body.data = err.data\n return body\n}\n", "import type {ServerBackendConfig, PrepareContext} from '../config'\nimport {matchesAnyGlob} from '../utils/glob'\nimport {errorToBody} from '../utils/response'\n\nconst PROXY_PREFIX = '/_devix/server'\n\nfunction jsonError(statusCode: number, message: string, code?: string): Response {\n const body = errorToBody({statusCode, message, code})\n return new Response(JSON.stringify(body), {\n status: statusCode,\n headers: {'Content-Type': 'application/json'},\n })\n}\n\n/**\n * Parsea `/_devix/server/<namespace>/<path>` \u2192 `{namespace, path}`.\n * Retorna null si el path no es un request al proxy.\n */\nexport function parseProxyPath(pathname: string): {namespace: string; path: string} | null {\n if (!pathname.startsWith(PROXY_PREFIX + '/')) return null\n const rest = pathname.slice(PROXY_PREFIX.length + 1)\n const slash = rest.indexOf('/')\n if (slash === -1) {\n return {namespace: rest, path: '/'}\n }\n return {namespace: rest.slice(0, slash), path: rest.slice(slash)}\n}\n\n/**\n * Maneja un request entrante al proxy interno. Aplica allowlist/denylist,\n * ejecuta `prepare`, y reenv\u00EDa al backend configurado.\n */\nexport async function handleProxyRequest(\n request: Request,\n config: Record<string, ServerBackendConfig> | undefined,\n): Promise<Response> {\n const url = new URL(request.url)\n const parsed = parseProxyPath(url.pathname)\n if (!parsed) {\n return jsonError(404, 'Not found', 'PROXY_NOT_FOUND')\n }\n\n const backend = config?.[parsed.namespace]\n if (!backend) {\n return jsonError(404, `Backend \"${parsed.namespace}\" not configured`, 'BACKEND_NOT_FOUND')\n }\n\n if (!matchesAnyGlob(parsed.path, backend.allowedPaths)) {\n return jsonError(403, 'Path not allowed', 'PATH_NOT_ALLOWED')\n }\n if (matchesAnyGlob(parsed.path, backend.deniedPaths)) {\n return jsonError(403, 'Path denied', 'PATH_DENIED')\n }\n\n const targetUrl = new URL(parsed.path + url.search, backend.url)\n const headers = new Headers()\n\n if (backend.prepare) {\n const ctx: PrepareContext = {request, headers, url: targetUrl}\n try {\n const result = await backend.prepare(ctx)\n if (result instanceof Response) return result\n } catch (err) {\n console.error(`[devix] server.${parsed.namespace}.prepare error:`, err)\n return jsonError(500, 'Proxy prepare failed', 'PREPARE_ERROR')\n }\n }\n\n if (!headers.has('Accept')) {\n const accept = request.headers.get('Accept')\n if (accept) headers.set('Accept', accept)\n }\n const ct = request.headers.get('Content-Type')\n if (ct && !headers.has('Content-Type')) headers.set('Content-Type', ct)\n\n let body: BodyInit | null = null\n if (request.method !== 'GET' && request.method !== 'HEAD') {\n body = await request.arrayBuffer()\n if ((body as ArrayBuffer).byteLength === 0) body = null\n }\n\n try {\n const backendRes = await fetch(targetUrl, {\n method: request.method,\n headers,\n body,\n redirect: 'manual',\n })\n return new Response(backendRes.body, {\n status: backendRes.status,\n statusText: backendRes.statusText,\n headers: filterHopByHop(backendRes.headers),\n })\n } catch (err) {\n console.error(`[devix] server.${parsed.namespace} fetch error:`, err)\n return jsonError(502, 'Bad Gateway', 'BACKEND_UNREACHABLE')\n }\n}\n\nconst HOP_BY_HOP = new Set([\n 'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization',\n 'te', 'trailers', 'transfer-encoding', 'upgrade',\n])\n\nfunction filterHopByHop(src: Headers): Headers {\n const dst = new Headers()\n src.forEach((value, key) => {\n if (!HOP_BY_HOP.has(key.toLowerCase())) dst.set(key, value)\n })\n return dst\n}\n\nexport const PROXY_PATH_PREFIX = PROXY_PREFIX\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["matchPathGlob", "path", "pattern", "globToRegex", "matchesAnyGlob", "patterns", "regex", "i", "c", "errorToBody", "err", "body", "PROXY_PREFIX", "jsonError", "statusCode", "message", "code", "body", "errorToBody", "parseProxyPath", "pathname", "rest", "slash", "handleProxyRequest", "request", "config", "url", "parsed", "backend", "matchesAnyGlob", "targetUrl", "headers", "ctx", "result", "err", "accept", "ct", "backendRes", "filterHopByHop", "HOP_BY_HOP", "src", "dst", "value", "key", "PROXY_PATH_PREFIX"]
|
|
7
|
+
}
|
package/dist/server/types.d.ts
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -34,13 +34,35 @@ export interface Viewport {
|
|
|
34
34
|
userScalable?: boolean;
|
|
35
35
|
themeColor?: string;
|
|
36
36
|
}
|
|
37
|
+
import type { BackendClient } from './runtime/server-client';
|
|
37
38
|
export interface LoaderContext<TParams = Record<string, string>> {
|
|
38
39
|
params: TParams;
|
|
39
40
|
request: Request;
|
|
40
41
|
guardData: unknown;
|
|
42
|
+
/**
|
|
43
|
+
* Cliente para llamar a backends remotos configurados en `devix.config.ts`.
|
|
44
|
+
* Bound al request actual — `prepare` recibe el `Request` del usuario para
|
|
45
|
+
* leer cookies, sesión, etc.
|
|
46
|
+
*/
|
|
47
|
+
$server: Record<string, BackendClient<string>>;
|
|
41
48
|
}
|
|
42
49
|
import type { Redirect } from './utils/response';
|
|
43
50
|
export type LoaderFunction<TData = unknown, TParams = Record<string, string>> = (ctx: LoaderContext<TParams>) => Promise<TData | Redirect | void> | TData | Redirect | void;
|
|
51
|
+
/**
|
|
52
|
+
* Tipo público para guards. Útil para helpers reutilizables donde el tipo
|
|
53
|
+
* concreto del retorno no importa.
|
|
54
|
+
*
|
|
55
|
+
* ⚠️ No anotes tu guard con este tipo si quieres inferencia de `guardData`.
|
|
56
|
+
* El retorno `object` aplana el tipo concreto. Forma recomendada:
|
|
57
|
+
*
|
|
58
|
+
* ```ts
|
|
59
|
+
* export async function guard({ request }: LoaderContext) {
|
|
60
|
+
* const session = await getSession(request)
|
|
61
|
+
* if (!session) return '/login'
|
|
62
|
+
* return session // ← TS infiere Session
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
44
66
|
export type GuardFunction<TParams = Record<string, string>> = (ctx: LoaderContext<TParams>) => Promise<string | Redirect | object | null> | string | Redirect | object | null;
|
|
45
67
|
type GuardData<TGuard> = TGuard extends (...args: any[]) => infer R ? Exclude<Awaited<R>, string | Redirect | null | undefined> : unknown;
|
|
46
68
|
export type LoaderContextWithGuard<TGuard extends GuardFunction | undefined = undefined, TParams = Record<string, string>> = LoaderContext<TParams> & {
|
package/dist/utils/banner.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import o from"picocolors";import{networkInterfaces as r}from"node:os";function s(e){let l=r();for(let n of Object.values(l))for(let t of n??[])if(t.family==="IPv4"&&!t.internal)return`http://${t.address}:${e}/`;return null}function $(e){let l="0.
|
|
1
|
+
import o from"picocolors";import{networkInterfaces as r}from"node:os";function s(e){let l=r();for(let n of Object.values(l))for(let t of n??[])if(t.family==="IPv4"&&!t.internal)return`http://${t.address}:${e}/`;return null}function $(e){let l="0.5.0",n=s(e);console.log(),console.log(` ${o.bold(o.yellow("devix"))} ${o.dim(`v${l}`)}`),console.log(),console.log(` ${o.green("\u279C")} ${o.bold("Local:")} ${o.cyan(`http://localhost:${e}/`)}`),console.log(n?` ${o.green("\u279C")} ${o.bold("Network:")} ${o.cyan(n)}`:` ${o.green("\u279C")} ${o.bold("Network:")} ${o.dim("use --host to expose")}`),console.log()}export{$ as printDevBanner};
|
|
2
2
|
//# sourceMappingURL=banner.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Match simple de path contra un glob estilo `'/v1/**'`, `'/v1/users/*'`, `'/v1/users/:id'`.
|
|
3
|
+
*
|
|
4
|
+
* Reglas:
|
|
5
|
+
* - `**` matchea cualquier subpath (incluye `/`).
|
|
6
|
+
* - `*` matchea un único segmento (sin `/`).
|
|
7
|
+
* - `:param` matchea un único segmento.
|
|
8
|
+
* - Cualquier otro caracter es literal.
|
|
9
|
+
*/
|
|
10
|
+
export declare function matchPathGlob(path: string, pattern: string): boolean;
|
|
11
|
+
export declare function matchesAnyGlob(path: string, patterns: readonly string[] | undefined): boolean;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function i(t,n){return o(n).test(t)}function r(t,n){if(!n||n.length===0)return!1;for(let e of n)if(i(t,e))return!0;return!1}function o(t){let n="",e=0;for(;e<t.length;){let l=t[e];if(l==="*"&&t[e+1]==="*")n+=".*",e+=2;else if(l==="*")n+="[^/]*",e+=1;else if(l===":"){for(e+=1;e<t.length&&/[a-zA-Z0-9_]/.test(t[e]);)e+=1;n+="[^/]+"}else".+?^$()|[]{}\\".includes(l)?(n+="\\"+l,e+=1):(n+=l,e+=1)}return new RegExp(`^${n}$`)}export{i as matchPathGlob,r as matchesAnyGlob};
|
|
2
|
+
//# sourceMappingURL=glob.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/glob.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Match simple de path contra un glob estilo `'/v1/**'`, `'/v1/users/*'`, `'/v1/users/:id'`.\n *\n * Reglas:\n * - `**` matchea cualquier subpath (incluye `/`).\n * - `*` matchea un \u00FAnico segmento (sin `/`).\n * - `:param` matchea un \u00FAnico segmento.\n * - Cualquier otro caracter es literal.\n */\nexport function matchPathGlob(path: string, pattern: string): boolean {\n const regex = globToRegex(pattern)\n return regex.test(path)\n}\n\nexport function matchesAnyGlob(path: string, patterns: readonly string[] | undefined): boolean {\n if (!patterns || patterns.length === 0) return false\n for (const pattern of patterns) {\n if (matchPathGlob(path, pattern)) return true\n }\n return false\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let regex = ''\n let i = 0\n while (i < pattern.length) {\n const c = pattern[i]\n if (c === '*' && pattern[i + 1] === '*') {\n regex += '.*'\n i += 2\n } else if (c === '*') {\n regex += '[^/]*'\n i += 1\n } else if (c === ':') {\n i += 1\n while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) i += 1\n regex += '[^/]+'\n } else if ('.+?^$()|[]{}\\\\'.includes(c)) {\n regex += '\\\\' + c\n i += 1\n } else {\n regex += c\n i += 1\n }\n }\n return new RegExp(`^${regex}$`)\n}\n"],
|
|
5
|
+
"mappings": "AASO,SAASA,EAAcC,EAAcC,EAA0B,CAElE,OADcC,EAAYD,CAAO,EACpB,KAAKD,CAAI,CAC1B,CAEO,SAASG,EAAeH,EAAcI,EAAkD,CAC3F,GAAI,CAACA,GAAYA,EAAS,SAAW,EAAG,MAAO,GAC/C,QAAWH,KAAWG,EAClB,GAAIL,EAAcC,EAAMC,CAAO,EAAG,MAAO,GAE7C,MAAO,EACX,CAEA,SAASC,EAAYD,EAAyB,CAC1C,IAAII,EAAQ,GACRC,EAAI,EACR,KAAOA,EAAIL,EAAQ,QAAQ,CACvB,IAAMM,EAAIN,EAAQK,CAAC,EACnB,GAAIC,IAAM,KAAON,EAAQK,EAAI,CAAC,IAAM,IAChCD,GAAS,KACTC,GAAK,UACEC,IAAM,IACbF,GAAS,QACTC,GAAK,UACEC,IAAM,IAAK,CAElB,IADAD,GAAK,EACEA,EAAIL,EAAQ,QAAU,eAAe,KAAKA,EAAQK,CAAC,CAAC,GAAGA,GAAK,EACnED,GAAS,OACb,KAAW,iBAAiB,SAASE,CAAC,GAClCF,GAAS,KAAOE,EAChBD,GAAK,IAELD,GAASE,EACTD,GAAK,EAEb,CACA,OAAO,IAAI,OAAO,IAAID,CAAK,GAAG,CAClC",
|
|
6
|
+
"names": ["matchPathGlob", "path", "pattern", "globToRegex", "matchesAnyGlob", "patterns", "regex", "i", "c"]
|
|
7
|
+
}
|