vinojs 0.1.2 → 0.2.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 +23 -18
- package/dist/client.d.mts +74 -8
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +194 -53
- package/dist/client.mjs.map +1 -1
- package/dist/component-wrap.mjs +1 -1
- package/dist/config-CXHX9qZs.mjs +17 -0
- package/dist/config-CXHX9qZs.mjs.map +1 -0
- package/dist/{constants-BVT2bJEd.mjs → constants-DyXAsId-.mjs} +2 -3
- package/dist/constants-DyXAsId-.mjs.map +1 -0
- package/dist/definePage-DC6gJKwW.mjs +468 -0
- package/dist/definePage-DC6gJKwW.mjs.map +1 -0
- package/dist/{defineServerFn-H-bz7xBX.mjs → defineServerFn-DH6B99bH.mjs} +2 -17
- package/dist/defineServerFn-DH6B99bH.mjs.map +1 -0
- package/dist/factory-0LjmIY5F.mjs +123 -0
- package/dist/factory-0LjmIY5F.mjs.map +1 -0
- package/dist/factory.d.mts +38 -2
- package/dist/factory.d.mts.map +1 -0
- package/dist/factory.mjs +4 -153
- package/dist/hydration.d.mts +3 -0
- package/dist/hydration.mjs +2 -0
- package/dist/jsx-dev-runtime.client.d.mts +2 -0
- package/dist/jsx-dev-runtime.client.mjs +2 -0
- package/dist/jsx-dev-runtime.d.mts +2 -0
- package/dist/jsx-dev-runtime.mjs +2 -0
- package/dist/jsx-runtime-5OIvn_Qa.mjs +335 -0
- package/dist/jsx-runtime-5OIvn_Qa.mjs.map +1 -0
- package/dist/jsx-runtime-BLN--agM.d.mts +20 -0
- package/dist/jsx-runtime-BLN--agM.d.mts.map +1 -0
- package/dist/jsx-runtime.client.d.mts +2 -0
- package/dist/jsx-runtime.client.mjs +2 -0
- package/dist/jsx-runtime.d.mts +2 -0
- package/dist/jsx-runtime.mjs +2 -0
- package/dist/mount.d.mts +17 -0
- package/dist/mount.d.mts.map +1 -0
- package/dist/mount.mjs +107 -0
- package/dist/mount.mjs.map +1 -0
- package/dist/render-Cif1RZMC.d.mts +169 -0
- package/dist/render-Cif1RZMC.d.mts.map +1 -0
- package/dist/{types-CQITdkpF.d.mts → types-jfsZLl9U.d.mts} +10 -8
- package/dist/types-jfsZLl9U.d.mts.map +1 -0
- package/dist/vino.d.mts +1 -37
- package/dist/vino.d.mts.map +1 -1
- package/dist/vino.mjs +2 -201
- package/dist/vite.d.mts +1 -1
- package/dist/vite.d.mts.map +1 -1
- package/dist/vite.mjs +175 -40
- package/dist/vite.mjs.map +1 -1
- package/package.json +29 -5
- package/dist/compile-glNMkyyx.mjs +0 -111
- package/dist/compile-glNMkyyx.mjs.map +0 -1
- package/dist/constants-BVT2bJEd.mjs.map +0 -1
- package/dist/definePage--9Pz7rHs.mjs +0 -73
- package/dist/definePage--9Pz7rHs.mjs.map +0 -1
- package/dist/defineServerFn-H-bz7xBX.mjs.map +0 -1
- package/dist/factory-CVT0-OZw.d.mts +0 -187
- package/dist/factory-CVT0-OZw.d.mts.map +0 -1
- package/dist/factory.mjs.map +0 -1
- package/dist/types-CQITdkpF.d.mts.map +0 -1
- package/dist/vino.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definePage-DC6gJKwW.mjs","names":["jsx"],"sources":["../src/hydration/render.ts","../src/hydration/hydrate.ts","../src/factory/definePage.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\nimport type { Child, FC } from \"hono/jsx\";\nimport { jsxDEV as jsx } from \"hono/jsx/jsx-dev-runtime\";\nimport { jsxRenderer } from \"hono/jsx-renderer\";\nimport { PAGE_SLOT_ID, PAYLOAD_SCRIPT_ID } from \"../vino/constants.ts\";\nimport type { ManifestPage, PageConfig, PageModule, RenderMode, VinoPayload } from \"./types.ts\";\n\nfunction DefaultLayout(props: { children?: Child }) {\n return jsx(\"html\", {\n children: [\n jsx(\"head\", {\n children: [\n jsx(\"meta\", { charset: \"utf-8\" }),\n jsx(\"meta\", { name: \"viewport\", content: \"width=device-width, initial-scale=1\" }),\n ],\n }),\n jsx(\"body\", { children: props.children }),\n ],\n });\n}\n\nexport function isHonoApp(value: unknown): value is Hono {\n return value instanceof Hono;\n}\n\nexport function payloadScript(payload: VinoPayload): string {\n const json = JSON.stringify(payload).replaceAll(\"<\", \"\\\\u003c\");\n return `<script id=\"${PAYLOAD_SCRIPT_ID}\" type=\"application/json\">${json}</script>`;\n}\n\nexport function injectDocument(\n html: string,\n payload: VinoPayload,\n isDev: boolean,\n scriptSrc: string,\n): string {\n const vite = isDev ? `<script type=\"module\" src=\"/@vite/client\"></script>` : \"\";\n const client = `<script type=\"module\" src=\"${scriptSrc}\"></script>`;\n const inject = `${vite}${payloadScript(payload)}${client}`;\n if (html.includes(\"</body>\")) return html.replace(\"</body>\", `${inject}</body>`);\n if (html.includes(\"</html>\")) return html.replace(\"</html>\", `${inject}</html>`);\n return `<!DOCTYPE html>${html}${inject}`;\n}\n\nasync function ensureJsxRenderer(c: Context): Promise<void> {\n await jsxRenderer(undefined, { docType: true })(c, async () => {});\n}\n\nfunction needsPageSlot(page: ManifestPage, config: PageConfig, mode: RenderMode): boolean {\n if (mode === \"content\") return true;\n if (page.isClientPage) return true;\n if (config.clientRouting === true) return true;\n return false;\n}\n\n/** Page hydrate/swap slot. Use in layouts so nav stays outside `#vino-page`. */\nfunction vinoRoot(props: { children?: Child }): Child {\n return jsx(\"div\", { id: PAGE_SLOT_ID, children: props.children });\n}\n\nexport const VinoRoot = vinoRoot as FC<{ children?: Child }>;\n\nexport function wrapSlot(children: Child): Child {\n return vinoRoot({ children });\n}\n\nconst SLOT_MARK = `id=\"${PAGE_SLOT_ID}\"`;\nconst BODY_INNER = /<body([^>]*)>([\\s\\S]*)<\\/body>/i;\n\n/** Wrap body children (or a fragment) in `#vino-page` when the slot is missing. */\nexport function wrapBodySlot(html: string): string {\n if (html.includes(SLOT_MARK)) return html;\n const match = html.match(BODY_INNER);\n if (match) {\n return html.replace(match[0], `<body${match[1]}><div id=\"${PAGE_SLOT_ID}\">${match[2]}</div></body>`);\n }\n return `<div id=\"${PAGE_SLOT_ID}\">${html}</div>`;\n}\n\n/**\n * Extract the `#vino-page` element (with nested markup) for content-only navigations.\n * Returns null when the slot is missing.\n */\nexport function extractPageSlot(html: string): string | null {\n const marker = `id=\"${PAGE_SLOT_ID}\"`;\n const markerIdx = html.indexOf(marker);\n if (markerIdx === -1) return null;\n const tagStart = html.lastIndexOf(\"<\", markerIdx);\n if (tagStart === -1) return null;\n\n const openEnd = html.indexOf(\">\", markerIdx);\n if (openEnd === -1) return null;\n if (html[openEnd - 1] === \"/\") return html.slice(tagStart, openEnd + 1);\n\n let depth = 1;\n let i = openEnd + 1;\n while (i < html.length && depth > 0) {\n const nextOpen = html.indexOf(\"<\", i);\n if (nextOpen === -1) break;\n if (html.startsWith(\"</div\", nextOpen)) {\n depth -= 1;\n const closeEnd = html.indexOf(\">\", nextOpen);\n if (closeEnd === -1) break;\n if (depth === 0) return html.slice(tagStart, closeEnd + 1);\n i = closeEnd + 1;\n continue;\n }\n if (html.startsWith(\"<div\", nextOpen) || html.startsWith(\"<DIV\", nextOpen)) {\n const closeAngle = html.indexOf(\">\", nextOpen);\n if (closeAngle === -1) break;\n if (html[closeAngle - 1] !== \"/\") depth += 1;\n i = closeAngle + 1;\n continue;\n }\n i = nextOpen + 1;\n }\n return null;\n}\n\nexport function isHydratedDocument(html: string): boolean {\n return html.includes(`id=\"${PAYLOAD_SCRIPT_ID}\"`);\n}\n\nfunction buildPayload(options: {\n page: ManifestPage;\n params: Record<string, string>;\n data: unknown;\n config: PageConfig;\n mode: RenderMode;\n requestPath?: string;\n title?: string;\n}): VinoPayload {\n const { page, params, data, config, requestPath, title } = options;\n const path = requestPath ?? (page.path === \"\" ? \"/\" : page.path);\n return {\n path,\n params,\n data,\n clientRouting: config.clientRouting === true,\n clientPage: page.isClientPage ? page.path : null,\n title,\n };\n}\n\nexport async function renderPageHtml(options: {\n c: Context;\n page: ManifestPage;\n pageMod: PageModule;\n pageNode?: Child | null;\n data: unknown;\n params: Record<string, string>;\n config: PageConfig;\n isDev: boolean;\n clientScriptSrc: string;\n mode?: RenderMode;\n title?: string;\n}): Promise<{ html: string; payload: VinoPayload }> {\n const {\n c,\n page,\n pageNode = null,\n data,\n params,\n config,\n isDev,\n clientScriptSrc,\n mode = \"full\",\n title,\n } = options;\n\n const payload = buildPayload({\n page,\n params,\n data,\n config,\n mode,\n requestPath: c.req.path,\n title,\n });\n\n if (mode === \"content\") {\n if (pageNode == null) throw new Error(\"content render requires pageNode\");\n const node = wrapSlot(pageNode);\n await ensureJsxRenderer(c);\n const rendered = await c.render(node as never);\n let html = await rendered.text();\n html = html.replace(/^<!DOCTYPE html>/i, \"\");\n html = `${html}${payloadScript(payload)}`;\n return { html, payload };\n }\n\n let node: Child = pageNode as Child;\n if (needsPageSlot(page, config, mode)) {\n node = wrapSlot(node);\n }\n\n const layouts = await Promise.all(page.loadLayouts.map((load) => load()));\n for (const layout of [...layouts].reverse()) {\n const Layout = layout.default;\n node = jsx(Layout, { data, params, children: node });\n }\n if (layouts.length === 0) {\n node = jsx(DefaultLayout, { children: node });\n }\n\n await ensureJsxRenderer(c);\n const rendered = await c.render(node as never);\n let html = await rendered.text();\n\n html = injectDocument(html, payload, isDev, clientScriptSrc);\n if (!html.startsWith(\"<!\")) html = `<!DOCTYPE html>${html}`;\n return { html, payload };\n}\n","import type { Context, Env, MiddlewareHandler } from \"hono\";\nimport type { Child } from \"hono/jsx\";\nimport { jsxRenderer } from \"hono/jsx-renderer\";\nimport {\n readPageRun,\n type PageDefinition,\n type PageDefinitionFields,\n} from \"../factory/definePage.ts\";\nimport { NAV_HEADER } from \"../vino/constants.ts\";\nimport {\n extractPageSlot,\n injectDocument,\n isHydratedDocument,\n payloadScript,\n wrapBodySlot,\n wrapSlot,\n} from \"./render.ts\";\nimport type { PageConfig, RenderMode, VinoPayload } from \"./types.ts\";\n\n/** Context flag: skip hydration middleware (`defineServerPage`). */\nexport const SKIP_HYDRATION = \"vino.skipHydration\";\n\nconst skipped = new WeakSet<object>();\n\n/** Mark this request so `hydration()` leaves the HTML alone. */\nexport function skipHydration(c: Context): void {\n skipped.add(c);\n}\n\nexport interface PageHydration {\n /** Passed to the client page as `{ data, params }`. */\n data?: unknown;\n /** Payload `clientPage` key. Defaults to the request path. Set `null` to skip page mount. */\n clientPage?: string | null;\n}\n\nconst pageHydration = new WeakMap<object, PageHydration>();\n\n/** Attach data / client-page id for this request's hydration payload. */\nexport function setPageHydration(c: Context, payload: PageHydration): void {\n pageHydration.set(c, payload);\n}\n\nexport function readPageHydration(c: Context): PageHydration | undefined {\n return pageHydration.get(c);\n}\n\nexport interface HydrationOptions {\n /** Module URL for the client bundle. Set to `false` to skip the script tag. */\n clientScript?: string | false;\n isDev?: boolean;\n /**\n * Enable content-only client navigations (`X-Vino-Nav`).\n * When true, `createClient` intercepts same-origin links and swaps `#vino-page`.\n */\n clientRouting?: boolean;\n}\n\ntype JsxRendererComponent = Parameters<typeof jsxRenderer>[0];\n\n/** Options for `vinoRenderer`: hydration + Hono `jsxRenderer`. */\nexport interface VinoRendererOptions extends HydrationOptions {\n docType?: boolean | string;\n stream?: boolean | Record<string, string>;\n component?: JsxRendererComponent;\n}\n\nconst defaultHydration: HydrationOptions = {\n clientScript: false,\n isDev: false,\n clientRouting: false,\n};\n\nconst boundHydration = new WeakMap<object, HydrationOptions>();\n\n/** App-wide defaults for standalone `definePage` hydration (no Vite). */\nexport function setHydrationDefaults(options: HydrationOptions): void {\n Object.assign(defaultHydration, options);\n}\n\nexport function bindHydrationOptions<T extends object>(value: T, options?: HydrationOptions): T {\n if (options && Object.keys(options).length > 0) {\n boundHydration.set(value, options);\n }\n return value;\n}\n\nexport function readBoundHydration(value: unknown): HydrationOptions | undefined {\n if (value === null || (typeof value !== \"object\" && typeof value !== \"function\")) return undefined;\n return boundHydration.get(value);\n}\n\nfunction resolveHydrationOptions(page: object): HydrationOptions {\n return { ...defaultHydration, ...readBoundHydration(page) };\n}\n\nfunction isHtmlResponse(res: Response): boolean {\n if (res.status < 200 || res.status >= 300) return false;\n const type = res.headers.get(\"content-type\") ?? \"\";\n return type.includes(\"text/html\");\n}\n\nfunction readSkipHydration(c: Context): boolean {\n if (skipped.has(c)) return true;\n try {\n return Boolean(c.get(SKIP_HYDRATION as never));\n } catch {\n return false;\n }\n}\n\nasync function rewriteHtmlResponse(c: Context, html: string, status: number, headers: Headers): Promise<void> {\n const next = new Headers(headers);\n next.delete(\"content-length\");\n if (!next.has(\"content-type\")) next.set(\"content-type\", \"text/html; charset=UTF-8\");\n c.res = new Response(html, { status, headers: next });\n}\n\n/**\n * After the handler, wrap `#vino-page` and inject payload + client script\n * on `text/html` responses. Skips JSON, `defineServerPage`, and docs that\n * already contain the payload script.\n */\nexport function hydration(options?: HydrationOptions): MiddlewareHandler {\n const opts: HydrationOptions = { ...defaultHydration, ...options };\n return async (c, next) => {\n await next();\n const res = c.res;\n if (!res || !isHtmlResponse(res)) return;\n if (readSkipHydration(c)) return;\n\n const html = await res.text();\n if (isHydratedDocument(html)) {\n await rewriteHtmlResponse(c, html, res.status, res.headers);\n return;\n }\n\n const wrapped = wrapBodySlot(html);\n const mode = resolveRenderMode(c);\n const extra = readPageHydration(c);\n const payload: VinoPayload = {\n path: c.req.path,\n params: c.req.param(),\n data: extra?.data,\n clientRouting: opts.clientRouting === true,\n clientPage: extra?.clientPage !== undefined ? extra.clientPage : c.req.path,\n };\n\n const scriptSrc = opts.clientScript;\n let nextHtml = wrapped;\n if (mode === \"content\") {\n const slot = extractPageSlot(wrapped) ?? wrapped;\n nextHtml = `${slot}${payloadScript(payload)}`;\n } else if (scriptSrc === false) {\n nextHtml = `${wrapped}${payloadScript(payload)}`;\n } else if (scriptSrc) {\n nextHtml = injectDocument(wrapped, payload, opts.isDev === true, scriptSrc);\n } else {\n nextHtml = `${wrapped}${payloadScript(payload)}`;\n }\n if (mode !== \"content\" && !nextHtml.startsWith(\"<!\") && nextHtml.includes(\"<html\")) {\n nextHtml = `<!DOCTYPE html>${nextHtml}`;\n }\n await rewriteHtmlResponse(c, nextHtml, res.status, res.headers);\n };\n}\n\n/**\n * Combined `jsxRenderer` + `hydration`: enables `c.render` and post-processes\n * HTML with `#vino-page`, payload, and optional client script.\n *\n * `hydrationRenderer(Layout, { clientScript })` or\n * `hydrationRenderer({ component: Layout, clientScript })`.\n */\nexport function hydrationRenderer(\n component: JsxRendererComponent,\n options?: HydrationOptions & Pick<VinoRendererOptions, \"docType\" | \"stream\">,\n): MiddlewareHandler;\nexport function hydrationRenderer(options: VinoRendererOptions): MiddlewareHandler;\nexport function hydrationRenderer(\n componentOrOptions: JsxRendererComponent | VinoRendererOptions,\n options?: HydrationOptions & Pick<VinoRendererOptions, \"docType\" | \"stream\">,\n): MiddlewareHandler {\n const objectForm = componentOrOptions !== null && typeof componentOrOptions === \"object\";\n const component = objectForm ? componentOrOptions.component : componentOrOptions;\n const opts: VinoRendererOptions = objectForm ? componentOrOptions : (options ?? {});\n const { clientScript, isDev, clientRouting, docType = true, stream } = opts;\n const hydrateMw = hydration({ clientScript, isDev, clientRouting });\n const renderMw = jsxRenderer(component, { docType, stream });\n\n return async (c, next) => {\n await hydrateMw(c, async () => {\n await renderMw(c, next);\n });\n };\n}\n\nfunction resolveRenderMode(c: Context): RenderMode {\n if (c.req.header(NAV_HEADER)) return \"content\";\n return \"full\";\n}\n\nexport function buildStandalonePayload(options: {\n path: string;\n params: Record<string, string>;\n data: unknown;\n config?: PageConfig;\n mode?: RenderMode;\n title?: string;\n}): VinoPayload {\n const { path, params, data, config = {}, mode = \"full\", title } = options;\n return {\n path,\n params,\n data,\n clientRouting: config.clientRouting === true,\n clientPage: path,\n title,\n };\n}\n\nasync function renderNode(c: Context, node: Child): Promise<string> {\n try {\n const rendered = await c.render(node as never);\n return rendered.text();\n } catch {\n return c.html(node as never);\n }\n}\n\nexport async function renderHydratedPage<Data, E extends Env>(\n c: Context,\n fields: PageDefinitionFields<Data, E>,\n hydration: HydrationOptions,\n): Promise<Response> {\n const mode = resolveRenderMode(c);\n const params = c.req.param();\n const data = fields.data ? await fields.data(c as never) : undefined;\n const path = c.req.path;\n const payload = buildStandalonePayload({\n path,\n params,\n data,\n config: fields.config,\n mode,\n });\n const pageNode = fields.render({ data: data as Data, params });\n\n if (mode === \"content\") {\n const html = `${await renderNode(c, wrapSlot(pageNode))}${payloadScript(payload)}`;\n return c.html(html);\n }\n\n let html = await renderNode(c, wrapSlot(pageNode));\n const scriptSrc = hydration.clientScript;\n if (scriptSrc) {\n html = injectDocument(html, payload, hydration.isDev === true, scriptSrc);\n } else {\n html = `${html}${payloadScript(payload)}`;\n }\n if (!html.startsWith(\"<!\")) html = `<!DOCTYPE html>${html}`;\n return c.html(html);\n}\n\n/** Terminal handler for `definePage`: SSR + slot, payload, and optional client script. */\nexport function createHydratablePageHandler<Data = unknown, E extends Env = Env>(\n fields: PageDefinitionFields<Data, E>,\n page: PageDefinition<Data, E>,\n): MiddlewareHandler<E> {\n return async (c) => {\n const run = readPageRun(c);\n if (run) return run();\n return renderHydratedPage(c, fields, resolveHydrationOptions(page));\n };\n}\n","import type { Context, Env, MiddlewareHandler, Next } from \"hono\";\nimport type { Child } from \"hono/jsx\";\nimport { createHydratablePageHandler, skipHydration } from \"../hydration/hydrate.ts\";\nimport type { ServerFn } from \"./defineServerFn.ts\";\nimport type { DataLoader, PageConfig, PageProps } from \"../hydration/types.ts\";\n\nexport const PAGE_KIND = \"vino:page\" as const;\nexport const SERVER_PAGE_KIND = \"vino:server-page\" as const;\n\nexport type PageRender<Data = unknown> = (props: PageProps<Data>) => Child;\n\nexport type PageDataFn<E extends Env = Env> = DataLoader<E> | ServerFn<unknown, E>;\n\nexport interface DefinePageOptions<Data = unknown, E extends Env = Env> {\n /** JSX page component. Alias: `page`. */\n render?: PageRender<Data>;\n page?: PageRender<Data>;\n /** Loader or `defineServerFn(...)` */\n data?: DataLoader<E> | ServerFn<Data, E>;\n config?: PageConfig;\n /** Extra Hono middleware, composed before the page handler. */\n use?: MiddlewareHandler<E>[];\n}\n\n/** Options object that infers `data` return type into `render` / `page`. */\nexport type InferDefinePageOptions<\n D extends (...args: never[]) => unknown,\n E extends Env = Env,\n Data = Awaited<ReturnType<D>>,\n> = {\n data?: D;\n config?: PageConfig;\n use?: MiddlewareHandler<E>[];\n} & (\n | { render: PageRender<Data>; page?: PageRender<Data> }\n | { page: PageRender<Data>; render?: PageRender<Data> }\n);\n\n/**\n * `definePage` / `defineServerPage` call signature, with `Env` fixed so `data(c)`\n * is typed without blocking inference of the loader return type.\n */\nexport interface DefinePageFn<E extends Env = Env> {\n <Data = unknown>(page: PageRender<Data>): PageDefinition<Data, E>;\n <D extends PageDataFn<E>>(options: InferDefinePageOptions<D, E>): PageDefinition<Awaited<ReturnType<D>>, E>;\n <Data = unknown>(options: DefinePageOptions<Data, E>): PageDefinition<Data, E>;\n <Data = unknown>(\n middleware: MiddlewareHandler<E>,\n page: PageRender<Data> | DefinePageOptions<Data, E>,\n ): PageDefinition<Data, E>;\n}\n\nexport interface PageDefinitionFields<Data = unknown, E extends Env = Env> {\n readonly kind: typeof PAGE_KIND | typeof SERVER_PAGE_KIND;\n readonly client: boolean;\n readonly render: PageRender<Data>;\n readonly data?: DataLoader<E> | ServerFn<Data, E>;\n readonly config?: PageConfig;\n}\n\n/**\n * Hono handler list plus page metadata (`kind`, `render`, `data`, `config`).\n */\nexport type PageDefinition<Data = unknown, E extends Env = Env> = [\n MiddlewareHandler<E>,\n ...MiddlewareHandler<E>[],\n] &\n PageDefinitionFields<Data, E>;\n\nconst pageRuns = new WeakMap<Context, () => Promise<Response>>();\n\n/** Bind the filesystem-route renderer used by the terminal page handler. */\nexport function bindPageRun(c: Context, run: () => Promise<Response>): void {\n pageRuns.set(c, run);\n}\n\n/** Bound `mountVino` renderer for the current request, if any. */\nexport function readPageRun(c: Context): (() => Promise<Response>) | undefined {\n return pageRuns.get(c);\n}\n\n/**\n * Strip page metadata so the list spreads onto `app.get(path, ...handlers)`.\n */\nexport function asHandlers<Data, E extends Env>(\n page: PageDefinition<Data, E>,\n): [MiddlewareHandler<E>, ...MiddlewareHandler<E>[]] {\n return page;\n}\n\nfunction requestParams(c: Context): Record<string, string> {\n try {\n return c.req.param();\n } catch {\n return {};\n }\n}\n\nasync function renderStandalone<Data, E extends Env>(\n c: Context,\n fields: PageDefinitionFields<Data, E>,\n): Promise<Response> {\n const params = requestParams(c);\n const data = fields.data ? await fields.data(c as never) : undefined;\n const node = fields.render({ data: data as Data, params });\n try {\n return await c.render(node as never);\n } catch {\n return c.html(node as never);\n }\n}\n\nfunction createPageHandler<Data, E extends Env>(fields: PageDefinitionFields<Data, E>): MiddlewareHandler<E> {\n return async (c) => {\n skipHydration(c);\n const run = readPageRun(c);\n if (run) return run();\n return renderStandalone(c, fields);\n };\n}\n\ntype DispatchHandler = (c: Context, next: Next) => unknown;\n\n/**\n * Run a `createHandlers`-style list on the current context.\n */\nexport async function dispatchHandlers(\n handlers: readonly DispatchHandler[],\n c: Context,\n next?: Next,\n): Promise<Response> {\n let index = -1;\n const dispatch = async (i: number): Promise<void> => {\n if (i <= index) throw new Error(\"next() called multiple times\");\n index = i;\n const handler = handlers[i];\n if (handler) {\n const out = await handler(c, () => dispatch(i + 1));\n if (out instanceof Response && !c.finalized) c.res = out;\n } else if (next) {\n await next();\n }\n };\n await dispatch(0);\n return c.res;\n}\n\nexport function isPageDefinition(value: unknown): value is PageDefinition {\n if (value === null || (typeof value !== \"object\" && typeof value !== \"function\")) return false;\n const candidate = value as PageDefinition;\n return (\n (candidate.kind === PAGE_KIND || candidate.kind === SERVER_PAGE_KIND) &&\n typeof candidate.render === \"function\"\n );\n}\n\nexport function isClientPageDefinition(value: unknown): value is PageDefinition {\n return isPageDefinition(value) && value.kind === PAGE_KIND;\n}\n\nexport function isServerPageDefinition(value: unknown): value is PageDefinition {\n return isPageDefinition(value) && value.kind === SERVER_PAGE_KIND;\n}\n\nexport function readPageDefinition(value: unknown): PageDefinition | undefined {\n return isPageDefinition(value) ? value : undefined;\n}\n\nexport function resolvePageRender(value: unknown): PageRender | undefined {\n if (isPageDefinition(value)) return value.render;\n if (typeof value === \"function\") return value as PageRender;\n return undefined;\n}\n\n/** True when source calls `definePage(...)` (hydratable pages). */\nexport function usesDefinePage(code: string): boolean {\n return /(?:^|[^\\w$])definePage\\s*(?:<[^>]*>\\s*)?\\(/.test(code);\n}\n\nfunction isPageSpec(value: unknown): value is PageRender | DefinePageOptions {\n return typeof value === \"function\" || (value !== null && typeof value === \"object\" && !Array.isArray(value));\n}\n\nfunction createHandlers<E extends Env>(...handlers: (MiddlewareHandler<E> | undefined)[]): MiddlewareHandler<E>[] {\n return handlers.filter((handler): handler is MiddlewareHandler<E> => handler !== undefined);\n}\n\nfunction asPageDefinition<Data, E extends Env>(\n fields: PageDefinitionFields<Data, E>,\n leading: (MiddlewareHandler<E> | undefined)[],\n): PageDefinition<Data, E> {\n const list: MiddlewareHandler<E>[] = [];\n const terminal = fields.client\n ? createHydratablePageHandler(fields, list as PageDefinition<Data, E>)\n : createPageHandler(fields);\n list.push(...createHandlers(...leading, terminal));\n if (list.length === 0) {\n throw new TypeError(\"[vino] definePage() produced no handlers\");\n }\n return Object.assign(list, fields) as PageDefinition<Data, E>;\n}\n\nfunction pageDefinition(\n args: unknown[],\n kind: typeof PAGE_KIND | typeof SERVER_PAGE_KIND,\n fnName: string,\n): PageDefinition {\n const spec = args.at(-1);\n if (args.length === 0 || !isPageSpec(spec)) {\n throw new TypeError(`[vino] ${fnName}() requires a JSX function or { render }`);\n }\n const leading = args\n .slice(0, -1)\n .filter((handler): handler is MiddlewareHandler => typeof handler === \"function\");\n\n if (typeof spec === \"function\") {\n const fields = { kind, client: kind === PAGE_KIND, render: spec };\n return asPageDefinition(fields, leading);\n }\n\n const render = spec.render ?? spec.page;\n if (typeof render !== \"function\") {\n throw new TypeError(`[vino] ${fnName}() requires a JSX function or { render }`);\n }\n const fields = { kind, client: kind === PAGE_KIND, render, data: spec.data, config: spec.config };\n return asPageDefinition(fields, [...leading, ...(spec.use ?? [])]);\n}\n\n/**\n * Declare a page that SSRs with `hono/jsx`, then hydrates `#vino-page`\n * with the vino client signal runtime (`vinojs/client`).\n *\n * Returns a Hono handler list (same shape as `createHandlers`) with `render` /\n * `data` / `config` attached.\n *\n * @example\n * export default definePage(() => {\n * const [n, setN] = createSignal(0)\n * return <button onClick={() => setN(n() + 1)}>{n}</button>\n * })\n */\nexport const definePage = ((...args: never[]) => pageDefinition(args, PAGE_KIND, \"definePage\")) as DefinePageFn;\n\n/**\n * Declare a page that SSRs only. The output is never hydrated.\n */\nexport const defineServerPage = ((...args: never[]) =>\n pageDefinition(args, SERVER_PAGE_KIND, \"defineServerPage\")) as DefinePageFn;\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/factory/defineServerFn.ts
|
|
2
2
|
const SERVER_FN_KIND = "vino:server-fn";
|
|
3
3
|
function isServerFn(value) {
|
|
4
4
|
return typeof value === "function" && value.kind === "vino:server-fn";
|
|
@@ -15,21 +15,6 @@ function usesDefineServerFn(code) {
|
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* Mark a function as server-only.
|
|
18
|
-
*
|
|
19
|
-
* Pass the result to `definePage({ data })` (or `defineServerPage`) as a
|
|
20
|
-
* loader. The same function can later be imported and invoked
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* // [slug].server.ts
|
|
24
|
-
* export default defineServerFn(c => {
|
|
25
|
-
* const slug = c.req.param("slug") ?? ""
|
|
26
|
-
* return { slug }
|
|
27
|
-
* })
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* // [slug].tsx
|
|
31
|
-
* import data from "./[slug].server"
|
|
32
|
-
* export default definePage({ data, render: ({ data }) => <h1>{data.slug}</h1> })
|
|
33
18
|
*/
|
|
34
19
|
function defineServerFn(fn) {
|
|
35
20
|
function serverFn(c) {
|
|
@@ -44,4 +29,4 @@ function defineServerFn(fn) {
|
|
|
44
29
|
//#endregion
|
|
45
30
|
export { readServerFn as a, isServerFn as i, SERVER_FN_KIND as n, usesDefineServerFn as o, defineServerFn as r, DEFINE_SERVER_FN_CALL as t };
|
|
46
31
|
|
|
47
|
-
//# sourceMappingURL=defineServerFn-
|
|
32
|
+
//# sourceMappingURL=defineServerFn-DH6B99bH.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineServerFn-DH6B99bH.mjs","names":[],"sources":["../src/factory/defineServerFn.ts"],"sourcesContent":["import type { Context, Env } from \"hono\";\n\nexport const SERVER_FN_KIND = \"vino:server-fn\" as const;\n\nexport type ServerFnHandler<T = unknown, E extends Env = Env> = (\n c: Context<E, string>,\n) => T | Promise<T>;\n\n/**\n * A server-only function. Callable as a `definePage({ data })` loader\n */\nexport type ServerFn<T = unknown, E extends Env = Env> = ServerFnHandler<T, E> & {\n readonly kind: typeof SERVER_FN_KIND;\n};\n\n/**\n * `defineServerFn` call signature, with `Env` fixed so `fn(c)` is typed without\n * blocking inference of the return type.\n */\nexport type DefineServerFnFn<E extends Env = Env> = <T>(fn: ServerFnHandler<T, E>) => ServerFn<T, E>;\n\nexport function isServerFn(value: unknown): value is ServerFn {\n return typeof value === \"function\" && (value as ServerFn).kind === SERVER_FN_KIND;\n}\n\nexport function readServerFn(value: unknown): ServerFn | undefined {\n return isServerFn(value) ? value : undefined;\n}\n\n/** Call-site of `defineServerFn(...)`, not `function defineServerFn(`. */\nexport const DEFINE_SERVER_FN_CALL =\n /(?<!function\\s)(?<![$\\w])defineServerFn\\s*(?:<[^>]*>\\s*)?\\(/g;\n\n/** True when source *calls* `defineServerFn(...)`. */\nexport function usesDefineServerFn(code: string): boolean {\n DEFINE_SERVER_FN_CALL.lastIndex = 0;\n return DEFINE_SERVER_FN_CALL.test(code);\n}\n\n/**\n * Mark a function as server-only.\n */\nexport function defineServerFn<T, E extends Env = Env>(fn: ServerFnHandler<T, E>): ServerFn<T, E> {\n function serverFn(c: Context<E, string>) {\n return fn(c);\n }\n Object.defineProperty(serverFn, \"kind\", {\n value: SERVER_FN_KIND,\n enumerable: true,\n });\n return serverFn as ServerFn<T, E>;\n}\n"],"mappings":";AAEA,MAAa,iBAAiB;AAmB9B,SAAgB,WAAW,OAAmC;CAC5D,OAAO,OAAO,UAAU,cAAe,MAAmB,SAAA;AAC5D;AAEA,SAAgB,aAAa,OAAsC;CACjE,OAAO,WAAW,KAAK,IAAI,QAAQ,KAAA;AACrC;;AAGA,MAAa,wBACX;;AAGF,SAAgB,mBAAmB,MAAuB;CACxD,sBAAsB,YAAY;CAClC,OAAO,sBAAsB,KAAK,IAAI;AACxC;;;;AAKA,SAAgB,eAAuC,IAA2C;CAChG,SAAS,SAAS,GAAuB;EACvC,OAAO,GAAG,CAAC;CACb;CACA,OAAO,eAAe,UAAU,QAAQ;EACtC,OAAO;EACP,YAAY;CACd,CAAC;CACD,OAAO;AACT"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { a as definePage, d as readPageDefinition, g as hydration, h as bindHydrationOptions, o as defineServerPage, s as dispatchHandlers } from "./definePage-DC6gJKwW.mjs";
|
|
2
|
+
import { r as defineServerFn } from "./defineServerFn-DH6B99bH.mjs";
|
|
3
|
+
import { Hono } from "hono";
|
|
4
|
+
//#region src/factory/factory.ts
|
|
5
|
+
/**
|
|
6
|
+
* Factory helper for Vino, analogous to `hono/factory`.
|
|
7
|
+
*
|
|
8
|
+
* Bind `Env` once so `definePage` / `defineServerPage` / `defineServerFn` type
|
|
9
|
+
* `c` without blocking inference of loader return data. `createApp()` builds a
|
|
10
|
+
* Hono instance with that `Env`. Each factory's `initApp` also runs for pages
|
|
11
|
+
* defined with that factory, so multiple Envs can share one mounted app.
|
|
12
|
+
*/
|
|
13
|
+
const boundInit = /* @__PURE__ */ new WeakMap();
|
|
14
|
+
const appliedInit = /* @__PURE__ */ new WeakMap();
|
|
15
|
+
const middlewareCache = /* @__PURE__ */ new WeakMap();
|
|
16
|
+
function storedInitApp(initApp) {
|
|
17
|
+
return initApp;
|
|
18
|
+
}
|
|
19
|
+
function bindInitApp(value, initApp) {
|
|
20
|
+
if (initApp) boundInit.set(value, initApp);
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
/** `initApp` stamped onto a `definePage` / `defineServerFn` result. */
|
|
24
|
+
function readBoundInitApp(value) {
|
|
25
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return void 0;
|
|
26
|
+
return boundInit.get(value);
|
|
27
|
+
}
|
|
28
|
+
function readPageModuleInitApp(pageDefault, data) {
|
|
29
|
+
return readBoundInitApp(pageDefault) ?? readBoundInitApp(data ?? readPageDefinition(pageDefault)?.data);
|
|
30
|
+
}
|
|
31
|
+
function markInitApplied(c, initApp) {
|
|
32
|
+
let set = appliedInit.get(c);
|
|
33
|
+
if (!set) {
|
|
34
|
+
set = /* @__PURE__ */ new Set();
|
|
35
|
+
appliedInit.set(c, set);
|
|
36
|
+
}
|
|
37
|
+
set.add(initApp);
|
|
38
|
+
}
|
|
39
|
+
function isInitApplied(c, initApp) {
|
|
40
|
+
return appliedInit.get(c)?.has(initApp) ?? false;
|
|
41
|
+
}
|
|
42
|
+
function middlewareFromInitApp(initApp) {
|
|
43
|
+
let list = middlewareCache.get(initApp);
|
|
44
|
+
if (!list) {
|
|
45
|
+
const app = new Hono();
|
|
46
|
+
initApp(app);
|
|
47
|
+
list = app.routes.filter((route) => route.method === "ALL").map((route) => route.handler);
|
|
48
|
+
middlewareCache.set(initApp, list);
|
|
49
|
+
}
|
|
50
|
+
return list;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* `initApp` as a single Hono middleware, for `createHandlers`-style lists.
|
|
54
|
+
* Skips if this `initApp` already ran on `c` (e.g. via `createApp()`).
|
|
55
|
+
*/
|
|
56
|
+
function initAppMiddleware(initApp) {
|
|
57
|
+
return async (c, next) => {
|
|
58
|
+
if (isInitApplied(c, initApp)) {
|
|
59
|
+
await next();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
markInitApplied(c, initApp);
|
|
63
|
+
const handlers = middlewareFromInitApp(initApp);
|
|
64
|
+
if (handlers.length === 0) {
|
|
65
|
+
await next();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
await dispatchHandlers(handlers, c, next);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Run a factory `initApp`'s `app.use()` middleware on the current context.
|
|
73
|
+
*/
|
|
74
|
+
async function applyInitApp(initApp, c, next) {
|
|
75
|
+
if (!initApp || isInitApplied(c, initApp)) return next();
|
|
76
|
+
await initAppMiddleware(initApp)(c, async () => {
|
|
77
|
+
const response = await next();
|
|
78
|
+
if (!c.finalized) c.res = response;
|
|
79
|
+
});
|
|
80
|
+
return c.res;
|
|
81
|
+
}
|
|
82
|
+
function withFactoryHandlers(def, initApp, hydrationOptions) {
|
|
83
|
+
bindInitApp(def, initApp);
|
|
84
|
+
bindHydrationOptions(def, hydrationOptions);
|
|
85
|
+
if (initApp) def.unshift(initAppMiddleware(initApp));
|
|
86
|
+
return def;
|
|
87
|
+
}
|
|
88
|
+
var Factory = class {
|
|
89
|
+
initApp;
|
|
90
|
+
defaultAppOptions;
|
|
91
|
+
hydration;
|
|
92
|
+
constructor(init) {
|
|
93
|
+
this.initApp = init?.initApp;
|
|
94
|
+
this.defaultAppOptions = init?.defaultAppOptions;
|
|
95
|
+
this.hydration = init?.hydration;
|
|
96
|
+
}
|
|
97
|
+
createApp = (options) => {
|
|
98
|
+
const app = new Hono(options && this.defaultAppOptions ? {
|
|
99
|
+
...this.defaultAppOptions,
|
|
100
|
+
...options
|
|
101
|
+
} : options ?? this.defaultAppOptions);
|
|
102
|
+
if (this.hydration !== false) app.use(hydration(this.hydration ?? {}));
|
|
103
|
+
if (this.initApp) {
|
|
104
|
+
const initApp = this.initApp;
|
|
105
|
+
app.use(async (c, next) => {
|
|
106
|
+
markInitApplied(c, initApp);
|
|
107
|
+
await next();
|
|
108
|
+
});
|
|
109
|
+
initApp(app);
|
|
110
|
+
}
|
|
111
|
+
return app;
|
|
112
|
+
};
|
|
113
|
+
definePage = ((...args) => withFactoryHandlers(definePage(...args), storedInitApp(this.initApp), this.hydration === false ? void 0 : this.hydration));
|
|
114
|
+
defineServerPage = ((...args) => withFactoryHandlers(defineServerPage(...args), storedInitApp(this.initApp)));
|
|
115
|
+
defineServerFn = ((fn) => bindInitApp(defineServerFn(fn), storedInitApp(this.initApp)));
|
|
116
|
+
};
|
|
117
|
+
function createFactory(options) {
|
|
118
|
+
return new Factory(options);
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
export { readBoundInitApp as a, initAppMiddleware as i, applyInitApp as n, readPageModuleInitApp as o, createFactory as r, Factory as t };
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=factory-0LjmIY5F.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory-0LjmIY5F.mjs","names":["definePageImpl","defineServerPageImpl","defineServerFnImpl"],"sources":["../src/factory/factory.ts"],"sourcesContent":["/**\n * Factory helper for Vino, analogous to `hono/factory`.\n *\n * Bind `Env` once so `definePage` / `defineServerPage` / `defineServerFn` type\n * `c` without blocking inference of loader return data. `createApp()` builds a\n * Hono instance with that `Env`. Each factory's `initApp` also runs for pages\n * defined with that factory, so multiple Envs can share one mounted app.\n */\n\nimport { Hono } from \"hono\";\nimport type { Context, Env, MiddlewareHandler } from \"hono\";\nimport {\n definePage as definePageImpl,\n defineServerPage as defineServerPageImpl,\n dispatchHandlers,\n readPageDefinition,\n type DefinePageFn,\n type PageDefinition,\n} from \"./definePage.ts\";\nimport {\n defineServerFn as defineServerFnImpl,\n type DefineServerFnFn,\n type ServerFnHandler,\n} from \"./defineServerFn.ts\";\nimport { bindHydrationOptions, hydration, type HydrationOptions } from \"../hydration/hydrate.ts\";\n\n/** Initialize every app created by `factory.createApp()`, and pages from `definePage`. */\nexport type InitApp<E extends Env = Env> = (app: Hono<E>) => void;\n\ntype HonoCtorOptions = NonNullable<ConstructorParameters<typeof Hono>[0]>;\ntype InitMiddleware = (c: Context, next: () => Promise<void>) => Promise<unknown>;\n\nexport interface FactoryOptions<E extends Env = Env> {\n initApp?: InitApp<E>;\n defaultAppOptions?: HonoCtorOptions;\n /** Defaults for hydration middleware / `definePage`. `false` disables auto-install. */\n hydration?: HydrationOptions | false;\n}\n\nconst boundInit = new WeakMap<object, InitApp>();\nconst appliedInit = new WeakMap<Context, Set<InitApp>>();\nconst middlewareCache = new WeakMap<InitApp, InitMiddleware[]>();\n\nfunction storedInitApp<E extends Env>(initApp: InitApp<E> | undefined): InitApp | undefined {\n return initApp as unknown as InitApp | undefined;\n}\n\nfunction bindInitApp<T extends object>(value: T, initApp?: InitApp): T {\n if (initApp) boundInit.set(value, initApp);\n return value;\n}\n\n/** `initApp` stamped onto a `definePage` / `defineServerFn` result. */\nexport function readBoundInitApp(value: unknown): InitApp | undefined {\n if (value === null || (typeof value !== \"object\" && typeof value !== \"function\")) return undefined;\n return boundInit.get(value);\n}\n\nexport function readPageModuleInitApp(pageDefault: unknown, data?: unknown): InitApp | undefined {\n return readBoundInitApp(pageDefault) ?? readBoundInitApp(data ?? readPageDefinition(pageDefault)?.data);\n}\n\nfunction markInitApplied(c: Context, initApp: InitApp): void {\n let set = appliedInit.get(c);\n if (!set) {\n set = new Set();\n appliedInit.set(c, set);\n }\n set.add(initApp);\n}\n\nfunction isInitApplied(c: Context, initApp: InitApp): boolean {\n return appliedInit.get(c)?.has(initApp) ?? false;\n}\n\nfunction middlewareFromInitApp(initApp: InitApp): InitMiddleware[] {\n let list = middlewareCache.get(initApp);\n if (!list) {\n const app = new Hono();\n initApp(app);\n list = app.routes.filter((route) => route.method === \"ALL\").map((route) => route.handler as InitMiddleware);\n middlewareCache.set(initApp, list);\n }\n return list;\n}\n\n/**\n * `initApp` as a single Hono middleware, for `createHandlers`-style lists.\n * Skips if this `initApp` already ran on `c` (e.g. via `createApp()`).\n */\nexport function initAppMiddleware(initApp: InitApp): MiddlewareHandler {\n return async (c, next) => {\n if (isInitApplied(c, initApp)) {\n await next();\n return;\n }\n markInitApplied(c, initApp);\n const handlers = middlewareFromInitApp(initApp);\n if (handlers.length === 0) {\n await next();\n return;\n }\n await dispatchHandlers(handlers as MiddlewareHandler[], c, next);\n };\n}\n\n/**\n * Run a factory `initApp`'s `app.use()` middleware on the current context.\n */\nexport async function applyInitApp(\n initApp: InitApp | undefined,\n c: Context,\n next: () => Promise<Response>,\n): Promise<Response> {\n if (!initApp || isInitApplied(c, initApp)) return next();\n const middleware: InitMiddleware = initAppMiddleware(initApp);\n await middleware(c, async () => {\n const response = await next();\n if (!c.finalized) c.res = response;\n });\n return c.res;\n}\n\nfunction withFactoryHandlers<T extends PageDefinition>(\n def: T,\n initApp?: InitApp,\n hydrationOptions?: HydrationOptions,\n): T {\n bindInitApp(def, initApp);\n bindHydrationOptions(def, hydrationOptions);\n if (initApp) def.unshift(initAppMiddleware(initApp));\n return def;\n}\n\nexport class Factory<E extends Env = Env> {\n private initApp?: InitApp<E>;\n private defaultAppOptions?: HonoCtorOptions;\n private hydration?: HydrationOptions | false;\n\n constructor(init?: FactoryOptions<E>) {\n this.initApp = init?.initApp;\n this.defaultAppOptions = init?.defaultAppOptions;\n this.hydration = init?.hydration;\n }\n\n createApp = (options?: HonoCtorOptions): Hono<E> => {\n const app = new Hono<E>(\n options && this.defaultAppOptions\n ? { ...this.defaultAppOptions, ...options }\n : (options ?? this.defaultAppOptions),\n );\n if (this.hydration !== false) {\n app.use(hydration(this.hydration ?? {}));\n }\n if (this.initApp) {\n const initApp = this.initApp;\n app.use(async (c, next) => {\n markInitApplied(c, initApp as unknown as InitApp);\n await next();\n });\n initApp(app);\n }\n return app;\n };\n\n definePage: DefinePageFn<E> = ((...args: unknown[]) =>\n withFactoryHandlers(\n (definePageImpl as (...a: unknown[]) => PageDefinition)(...args),\n storedInitApp(this.initApp),\n this.hydration === false ? undefined : this.hydration,\n )) as unknown as DefinePageFn<E>;\n\n defineServerPage: DefinePageFn<E> = ((...args: unknown[]) =>\n withFactoryHandlers(\n (defineServerPageImpl as (...a: unknown[]) => PageDefinition)(...args),\n storedInitApp(this.initApp),\n )) as unknown as DefinePageFn<E>;\n\n defineServerFn: DefineServerFnFn<E> = ((fn: ServerFnHandler<never, E>) =>\n bindInitApp(defineServerFnImpl(fn), storedInitApp(this.initApp))) as DefineServerFnFn<E>;\n}\n\nexport function createFactory<E extends Env = Env>(options?: FactoryOptions<E>): Factory<E> {\n return new Factory<E>(options);\n}\n\nexport type { HydrationOptions, VinoRendererOptions } from \"../hydration/hydrate.ts\";\nexport { readBoundHydration, setHydrationDefaults, setPageHydration, readPageHydration, hydration, skipHydration, SKIP_HYDRATION, hydrationRenderer as vinoRenderer } from \"../hydration/hydrate.ts\";\nexport { VinoRoot } from \"../hydration/render.ts\";\n"],"mappings":"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"}
|
package/dist/factory.d.mts
CHANGED
|
@@ -1,2 +1,38 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
|
|
1
|
+
import { A as DefineServerFnFn, C as dispatchHandlers, D as readPageDefinition, E as isServerPageDefinition, F as isServerFn, I as readServerFn, L as usesDefineServerFn, M as ServerFn, N as ServerFnHandler, O as resolvePageRender, P as defineServerFn, S as defineServerPage, T as isPageDefinition, _ as PageRender, a as VinoRendererOptions, b as bindPageRun, d as setPageHydration, f as skipHydration, g as PageDefinition, h as PAGE_KIND, i as SKIP_HYDRATION, j as SERVER_FN_KIND, k as usesDefinePage, l as readPageHydration, m as DefinePageOptions, n as HydrationOptions, o as hydration, p as DefinePageFn, r as PageHydration, s as hydrationRenderer, t as VinoRoot, v as SERVER_PAGE_KIND, w as isClientPageDefinition, x as definePage, y as asHandlers } from "./render-Cif1RZMC.mjs";
|
|
2
|
+
import { Context, Env, Hono, MiddlewareHandler } from "hono";
|
|
3
|
+
//#region src/factory/factory.d.ts
|
|
4
|
+
/** Initialize every app created by `factory.createApp()`, and pages from `definePage`. */
|
|
5
|
+
type InitApp<E extends Env = Env> = (app: Hono<E>) => void;
|
|
6
|
+
type HonoCtorOptions = NonNullable<ConstructorParameters<typeof Hono>[0]>;
|
|
7
|
+
interface FactoryOptions<E extends Env = Env> {
|
|
8
|
+
initApp?: InitApp<E>;
|
|
9
|
+
defaultAppOptions?: HonoCtorOptions;
|
|
10
|
+
/** Defaults for hydration middleware / `definePage`. `false` disables auto-install. */
|
|
11
|
+
hydration?: HydrationOptions | false;
|
|
12
|
+
}
|
|
13
|
+
/** `initApp` stamped onto a `definePage` / `defineServerFn` result. */
|
|
14
|
+
declare function readBoundInitApp(value: unknown): InitApp | undefined;
|
|
15
|
+
declare function readPageModuleInitApp(pageDefault: unknown, data?: unknown): InitApp | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* `initApp` as a single Hono middleware, for `createHandlers`-style lists.
|
|
18
|
+
* Skips if this `initApp` already ran on `c` (e.g. via `createApp()`).
|
|
19
|
+
*/
|
|
20
|
+
declare function initAppMiddleware(initApp: InitApp): MiddlewareHandler;
|
|
21
|
+
/**
|
|
22
|
+
* Run a factory `initApp`'s `app.use()` middleware on the current context.
|
|
23
|
+
*/
|
|
24
|
+
declare function applyInitApp(initApp: InitApp | undefined, c: Context, next: () => Promise<Response>): Promise<Response>;
|
|
25
|
+
declare class Factory<E extends Env = Env> {
|
|
26
|
+
private initApp?;
|
|
27
|
+
private defaultAppOptions?;
|
|
28
|
+
private hydration?;
|
|
29
|
+
constructor(init?: FactoryOptions<E>);
|
|
30
|
+
createApp: (options?: HonoCtorOptions) => Hono<E>;
|
|
31
|
+
definePage: DefinePageFn<E>;
|
|
32
|
+
defineServerPage: DefinePageFn<E>;
|
|
33
|
+
defineServerFn: DefineServerFnFn<E>;
|
|
34
|
+
}
|
|
35
|
+
declare function createFactory<E extends Env = Env>(options?: FactoryOptions<E>): Factory<E>;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { type DefinePageFn, type DefinePageOptions, type DefineServerFnFn, Factory, type FactoryOptions, type HydrationOptions, type InitApp, PAGE_KIND, type PageDefinition, type PageHydration, type PageRender, SERVER_FN_KIND, SERVER_PAGE_KIND, SKIP_HYDRATION, type ServerFn, type ServerFnHandler, type VinoRendererOptions, VinoRoot, applyInitApp, asHandlers, bindPageRun, createFactory, definePage, defineServerFn, defineServerPage, dispatchHandlers, hydration, initAppMiddleware, isClientPageDefinition, isPageDefinition, isServerFn, isServerPageDefinition, readBoundInitApp, readPageDefinition, readPageHydration, readPageModuleInitApp, readServerFn, resolvePageRender, setPageHydration, skipHydration, usesDefinePage, usesDefineServerFn, hydrationRenderer as vinoRenderer };
|
|
38
|
+
//# sourceMappingURL=factory.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.mts","names":[],"sources":["../src/factory/factory.ts"],"mappings":";;;;KA2BY,QAAQ,UAAU,MAAM,QAAQ,KAAK,KAAK;KAEjD,kBAAkB,YAAY,6BAA6B;UAG/C,eAAe,UAAU,MAAM;EAC9C,UAAU,QAAQ;EAClB,oBAAoB;;EAEpB,YAAY;;;iBAiBE,iBAAiB,iBAAiB;iBAKlC,sBAAsB,sBAAsB,iBAAiB;;;;;iBAgC7D,kBAAkB,SAAS,UAAU;;;;iBAmB/B,aACpB,SAAS,qBACT,GAAG,SACH,YAAY,QAAQ,YACnB,QAAQ;cAqBE,QAAQ,UAAU,MAAM;UAC3B;UACA;UACA;EAEI,YAAA,OAAO,eAAe;EAMlC,YAAa,UAAU,oBAAkB,KAAK;EAoB9C,YAAY,aAAa;EAOzB,kBAAkB,aAAa;EAM/B,gBAAgB,iBAAiB;;iBAInB,cAAc,UAAU,MAAM,KAAK,UAAU,eAAe,KAAK,QAAQ"}
|
package/dist/factory.mjs
CHANGED
|
@@ -1,153 +1,4 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import { r as defineServerFn } from "./defineServerFn-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Factory helper for Vino, analogous to `hono/factory`.
|
|
7
|
-
*
|
|
8
|
-
* Bind `Env` once so `definePage` / `defineServerPage` / `defineServerFn` type
|
|
9
|
-
* `c` without blocking inference of loader return data. `createApp()` builds a
|
|
10
|
-
* Hono instance with that `Env`. Each factory's `initApp` also runs for pages
|
|
11
|
-
* defined with that factory, so multiple Envs can share one mounted app.
|
|
12
|
-
*/
|
|
13
|
-
const boundInit = /* @__PURE__ */ new WeakMap();
|
|
14
|
-
const appliedInit = /* @__PURE__ */ new WeakMap();
|
|
15
|
-
const middlewareCache = /* @__PURE__ */ new WeakMap();
|
|
16
|
-
function storedInitApp(initApp) {
|
|
17
|
-
return initApp;
|
|
18
|
-
}
|
|
19
|
-
function bindInitApp(value, initApp) {
|
|
20
|
-
if (initApp) boundInit.set(value, initApp);
|
|
21
|
-
return value;
|
|
22
|
-
}
|
|
23
|
-
/** `initApp` stamped onto a `definePage` / `defineServerFn` result. */
|
|
24
|
-
function readBoundInitApp(value) {
|
|
25
|
-
if (value === null || typeof value !== "object" && typeof value !== "function") return void 0;
|
|
26
|
-
return boundInit.get(value);
|
|
27
|
-
}
|
|
28
|
-
function readPageModuleInitApp(pageDefault, data) {
|
|
29
|
-
return readBoundInitApp(pageDefault) ?? readBoundInitApp(data ?? readPageDefinition(pageDefault)?.data);
|
|
30
|
-
}
|
|
31
|
-
function markInitApplied(c, initApp) {
|
|
32
|
-
let set = appliedInit.get(c);
|
|
33
|
-
if (!set) {
|
|
34
|
-
set = /* @__PURE__ */ new Set();
|
|
35
|
-
appliedInit.set(c, set);
|
|
36
|
-
}
|
|
37
|
-
set.add(initApp);
|
|
38
|
-
}
|
|
39
|
-
function isInitApplied(c, initApp) {
|
|
40
|
-
return appliedInit.get(c)?.has(initApp) ?? false;
|
|
41
|
-
}
|
|
42
|
-
function middlewareFromInitApp(initApp) {
|
|
43
|
-
let list = middlewareCache.get(initApp);
|
|
44
|
-
if (!list) {
|
|
45
|
-
const app = new Hono();
|
|
46
|
-
initApp(app);
|
|
47
|
-
list = app.routes.filter((route) => route.method === "ALL").map((route) => route.handler);
|
|
48
|
-
middlewareCache.set(initApp, list);
|
|
49
|
-
}
|
|
50
|
-
return list;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Run a factory `initApp`'s `app.use()` middleware on the current context.
|
|
54
|
-
* Skips if this `initApp` already ran on `c` (e.g. via `createApp()`).
|
|
55
|
-
* Params and `c.set` stay on the same context so page loaders still see them.
|
|
56
|
-
*/
|
|
57
|
-
async function applyInitApp(initApp, c, next) {
|
|
58
|
-
if (!initApp || isInitApplied(c, initApp)) return next();
|
|
59
|
-
markInitApplied(c, initApp);
|
|
60
|
-
const handlers = middlewareFromInitApp(initApp);
|
|
61
|
-
if (handlers.length === 0) return next();
|
|
62
|
-
let response;
|
|
63
|
-
const run = async (i) => {
|
|
64
|
-
const handler = handlers[i];
|
|
65
|
-
if (!handler) {
|
|
66
|
-
response = await next();
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
const out = await handler(c, () => run(i + 1));
|
|
70
|
-
if (out instanceof Response) response = out;
|
|
71
|
-
};
|
|
72
|
-
await run(0);
|
|
73
|
-
return response ?? c.res;
|
|
74
|
-
}
|
|
75
|
-
var Factory = class {
|
|
76
|
-
initApp;
|
|
77
|
-
defaultAppOptions;
|
|
78
|
-
constructor(init) {
|
|
79
|
-
this.initApp = init?.initApp;
|
|
80
|
-
this.defaultAppOptions = init?.defaultAppOptions;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Create a Hono app typed with this factory's `Env`.
|
|
84
|
-
* Runs `initApp` (if provided) before returning, so middleware is registered
|
|
85
|
-
* before you call `mountVino(app)`.
|
|
86
|
-
*/
|
|
87
|
-
createApp = (options) => {
|
|
88
|
-
const app = new Hono(options && this.defaultAppOptions ? {
|
|
89
|
-
...this.defaultAppOptions,
|
|
90
|
-
...options
|
|
91
|
-
} : options ?? this.defaultAppOptions);
|
|
92
|
-
if (this.initApp) {
|
|
93
|
-
const initApp = this.initApp;
|
|
94
|
-
app.use(async (c, next) => {
|
|
95
|
-
markInitApplied(c, initApp);
|
|
96
|
-
await next();
|
|
97
|
-
});
|
|
98
|
-
initApp(app);
|
|
99
|
-
}
|
|
100
|
-
return app;
|
|
101
|
-
};
|
|
102
|
-
/** Same as `definePage`, with `c` typed as `Context<E>` and this factory's `initApp`. */
|
|
103
|
-
definePage = ((page) => bindInitApp(definePage(page), storedInitApp(this.initApp)));
|
|
104
|
-
/** Same as `defineServerPage`, with `c` typed as `Context<E>` and this factory's `initApp`. */
|
|
105
|
-
defineServerPage = ((page) => bindInitApp(defineServerPage(page), storedInitApp(this.initApp)));
|
|
106
|
-
/** Same as `defineServerFn`, with `c` typed as `Context<E>` and this factory's `initApp`. */
|
|
107
|
-
defineServerFn = ((fn) => bindInitApp(defineServerFn(fn), storedInitApp(this.initApp)));
|
|
108
|
-
};
|
|
109
|
-
/**
|
|
110
|
-
* Create a factory that binds `Env` onto page helpers and `createApp()`.
|
|
111
|
-
*
|
|
112
|
-
* Pages keep the `initApp` of the factory that defined them, so a blog factory
|
|
113
|
-
* can set `c.var.db` only for `blogFactory.definePage` routes while the root
|
|
114
|
-
* app still uses the global factory.
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* // src/factory.ts
|
|
118
|
-
* export const factory = createFactory<Env>({
|
|
119
|
-
* initApp: (app) => {
|
|
120
|
-
* app.use(async (c, next) => {
|
|
121
|
-
* c.set("db", drizzle(c.env.DB))
|
|
122
|
-
* await next()
|
|
123
|
-
* })
|
|
124
|
-
* },
|
|
125
|
-
* })
|
|
126
|
-
* export const blogFactory = createFactory<BlogEnv>({
|
|
127
|
-
* initApp: (app) => {
|
|
128
|
-
* app.use(async (c, next) => {
|
|
129
|
-
* c.set("posts", createPosts(c.env.BLOG_DB))
|
|
130
|
-
* await next()
|
|
131
|
-
* })
|
|
132
|
-
* },
|
|
133
|
-
* })
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
* // src/server.ts
|
|
137
|
-
* const app = factory.createApp()
|
|
138
|
-
* mountVino(app)
|
|
139
|
-
*
|
|
140
|
-
* @example
|
|
141
|
-
* // src/pages/blog/[slug].tsx
|
|
142
|
-
* export default blogFactory.definePage({
|
|
143
|
-
* data: (c) => c.var.posts.get(c.req.param("slug")),
|
|
144
|
-
* render: ({ data }) => <h1>{data.title}</h1>,
|
|
145
|
-
* })
|
|
146
|
-
*/
|
|
147
|
-
function createFactory(options) {
|
|
148
|
-
return new Factory(options);
|
|
149
|
-
}
|
|
150
|
-
//#endregion
|
|
151
|
-
export { Factory, applyInitApp, createFactory, readBoundInitApp, readPageModuleInitApp };
|
|
152
|
-
|
|
153
|
-
//# sourceMappingURL=factory.mjs.map
|
|
1
|
+
import { C as VinoRoot, S as skipHydration, _ as hydrationRenderer, a as definePage, c as isClientPageDefinition, d as readPageDefinition, f as resolvePageRender, g as hydration, i as bindPageRun, l as isPageDefinition, m as SKIP_HYDRATION, n as SERVER_PAGE_KIND, o as defineServerPage, p as usesDefinePage, r as asHandlers, s as dispatchHandlers, t as PAGE_KIND, u as isServerPageDefinition, x as setPageHydration, y as readPageHydration } from "./definePage-DC6gJKwW.mjs";
|
|
2
|
+
import { a as readServerFn, i as isServerFn, n as SERVER_FN_KIND, o as usesDefineServerFn, r as defineServerFn } from "./defineServerFn-DH6B99bH.mjs";
|
|
3
|
+
import { a as readBoundInitApp, i as initAppMiddleware, n as applyInitApp, o as readPageModuleInitApp, r as createFactory, t as Factory } from "./factory-0LjmIY5F.mjs";
|
|
4
|
+
export { Factory, PAGE_KIND, SERVER_FN_KIND, SERVER_PAGE_KIND, SKIP_HYDRATION, VinoRoot, applyInitApp, asHandlers, bindPageRun, createFactory, definePage, defineServerFn, defineServerPage, dispatchHandlers, hydration, initAppMiddleware, isClientPageDefinition, isPageDefinition, isServerFn, isServerPageDefinition, readBoundInitApp, readPageDefinition, readPageHydration, readPageModuleInitApp, readServerFn, resolvePageRender, setPageHydration, skipHydration, usesDefinePage, usesDefineServerFn, hydrationRenderer as vinoRenderer };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as PageConfig, c as VinoManifest, i as ManifestPage, l as VinoPayload, o as PageProps, r as LayoutProps, s as RenderMode, t as CreateVinoOptions, u as VinoViteOptions } from "./types-jfsZLl9U.mjs";
|
|
2
|
+
import { a as VinoRendererOptions, c as readBoundHydration, d as setPageHydration, f as skipHydration, i as SKIP_HYDRATION, l as readPageHydration, n as HydrationOptions, o as hydration, r as PageHydration, s as hydrationRenderer, t as VinoRoot, u as setHydrationDefaults } from "./render-Cif1RZMC.mjs";
|
|
3
|
+
export { type CreateVinoOptions, type HydrationOptions, type LayoutProps, type ManifestPage, type PageConfig, type PageHydration, type PageProps, type RenderMode, SKIP_HYDRATION, type VinoManifest, type VinoPayload, type VinoRendererOptions, VinoRoot, type VinoViteOptions, hydration, hydrationRenderer, readBoundHydration, readPageHydration, setHydrationDefaults, setPageHydration, skipHydration };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { C as VinoRoot, S as skipHydration, _ as hydrationRenderer, b as setHydrationDefaults, g as hydration, m as SKIP_HYDRATION, v as readBoundHydration, x as setPageHydration, y as readPageHydration } from "./definePage-DC6gJKwW.mjs";
|
|
2
|
+
export { SKIP_HYDRATION, VinoRoot, hydration, hydrationRenderer, readBoundHydration, readPageHydration, setHydrationDefaults, setPageHydration, skipHydration };
|