import type { MatchedRoute, Server, WebSocketHandler } from "bun"; import type { DetailedHTMLProps, FC, HtmlHTMLAttributes, PropsWithChildren } from "react"; export type ServerProps = { params: Record; searchParams: Record; headers: Headers; cookies: Record; body: any; method: string; url: string; pathname: string; query: Record; search: string; hash: string; }; export type StaticProps = { params: Record; searchParams: Record; headers: Headers; cookies: Record; body: any; method: string; url: string; pathname: string; query: Record; search: string; hash: string; }; export type StaticPaths = string[]; export type StaticParams = Record; export type PageModule = { component: React.ComponentType; serverProps: ServerProps; staticProps: StaticProps; staticPaths: StaticPaths; staticParams: StaticParams; }; export type BunextConfig = { dist_dir?: string; assets_prefix?: string; origin?: string; global_vars?: { [k: string]: any; }; port?: number; development?: boolean; middleware?: (params: BunextConfigMiddlewareParams) => Promise | Response | Request | undefined; default_cache_expiry?: number; /** * Maximum number of cached pages kept on disk. New pages are not * cached once this is reached. Defaults to 1000. */ max_cache_entries?: number; /** * By default, pages are not written to the cache when the request * carries a `Cookie` or `Authorization` header, so one user's page is * never served to everyone. Set this to `true` only if your cached * pages never render per-user content. */ cache_credentialed_requests?: boolean; /** * Trust the `X-Forwarded-Proto` header (set this when running behind a * reverse proxy that sets it). Defaults to `false`. */ trust_proxy?: boolean; websocket?: WebSocketHandler; server_options?: Omit, "fetch" | "routes">; /** * These are patterns in the pages to exclude * from the router */ pages_exclude_patterns?: RegExp[]; max_logs?: number; /** * Patterns to exclude from the SSR bundler. This is * required for modules that aren't compatible with esbuild * bundler. Eg. `sqlite-vec` */ ssr_compiler_excludes?: string[]; /** * Patterns to exclude from the Main page bundler. This is * required for modules that aren't compatible with esbuild * bundler for the browser. Eg. `react/jsx-dev-runtime` */ page_compiler_excludes?: string[]; /** * Patterns to exclude from the watcher. Eg. `./src/server.ts` * or `\*.test.ts\`. It should either be a file path (relative or * absolute), or a RegEx pattern. */ exclude_watch_patterns?: (string | RegExp)[]; /** * Public environment variables to be passed to the client */ public_envs?: Record; /** * Options for the `bunext sitemap` command */ sitemap?: BunextSitemapConfig; /** * Options for the robots.txt written by `bunext sitemap`. Set to * `false` to skip generating it. */ robots?: BunextRobotsConfig | false; /** * Keep the whole site out of search engines, e.g. for preview * deployments. Every response gets `X-Robots-Tag: noindex, nofollow`, * pages get a matching robots meta tag (overriding `meta.robots`), and * `/robots.txt` disallows all crawlers regardless of `public/robots.txt`. */ disable_seo?: boolean; /** * Maximum time (ms) a page's server render may take before it is * aborted and answered with a 500. Defaults to 30000. */ ssr_render_timeout_ms?: number; }; export type BunextConfigMiddlewareParams = { req: Request; url: URL; }; export type GetRouteReturn = { match: MatchedRoute; module: PageModule; component: React.ComponentType; serverProps: ServerProps; staticProps: StaticProps; staticPaths: StaticPaths; staticParams: StaticParams; }; export type BunxRouteParams = { req: Request; url: URL; body?: any; query?: any; /** * Intercept and Transform the response object */ res_transform?: (res: Response) => Promise | Response; server?: Server; }; export interface PostInsertReturn { fieldCount?: number; affectedRows?: number; insertId?: number; serverStatus?: number; warningCount?: number; message?: string; protocol41?: boolean; changedRows?: number; } export type APIResponseObject = { success: boolean; payload?: T[] | null; singleRes?: T | null; stringRes?: string | null; numberRes?: number | null; postInsertReturn?: PostInsertReturn | null; payloadBase64?: string; payloadThumbnailBase64?: string; payloadURL?: string; payloadThumbnailURL?: string; error?: any; msg?: string; queryObject?: any; countQueryObject?: any; status?: number; count?: number; errors?: any[]; debug?: any; batchPayload?: any[][] | null; errorData?: any; token?: string; csrf?: string; cookieNames?: any; key?: string; userId?: string | number; code?: string; createdAt?: number; email?: string; requestOptions?: any; logoutUser?: boolean; redirect?: string; }; export type BunextServerRouteConfig = { max_request_body_mb?: number; }; export type LivePageDistGenParams = { component?: FC; pageProps?: any; module?: BunextPageModule; root_module?: BunextRootModule; bundledMap?: BundlerCTXMap; routeParams?: BunxRouteParams; debug?: boolean; }; export type BunextPageHeadFCProps = { serverRes: BunextPageModuleServerReturn; ctx?: BunxRouteParams; }; export type BunextPageModule = { default: FC; meta?: BunextPageModuleMeta | BunextPageModuleMetaFn; Head?: FC; config?: BunextRouteConfig; html_props?: BunextHTMLProps; }; export type BunextPageServerModule = { default?: BunextPageServerFn; server?: BunextPageServerFn; sitemap?: BunextPageSitemapFn; }; /** * Returns the sitemap entries for a page. Required for dynamic routes * (`[slug]`) to appear in the sitemap. On a static page, the returned * entries replace the page's default entry. */ export type BunextPageSitemapFn = (params: { /** * The page's route pattern, e.g. `/blog/[slug]` */ route: string; }) => BunextSitemapAdditionalPaths | Promise; export type BunextHTMLProps = DetailedHTMLProps, HTMLHtmlElement>; export type BunextPageModuleMetaFn = (params: { ctx: BunxRouteParams; serverRes?: BunextPageModuleServerReturn; }) => Promise; export type BunextPageModuleMeta = { title?: string; description?: string; keywords?: string | string[]; author?: string; robots?: string; canonical?: string; themeColor?: string; og?: BunextPageModuleMetaOG; twitter?: BunextPageModuleMetaTwitter; }; export type BunextPageModuleMetaOG = { title?: string; description?: string; image?: string; url?: string; type?: string; siteName?: string; locale?: string; }; export type BunextPageModuleMetaTwitter = { card?: "summary" | "summary_large_image" | "app" | "player"; title?: string; description?: string; image?: string; site?: string; creator?: string; }; export type BunextPageServerFn = (ctx: Omit & { props?: T; }) => Promise>; export type BunextRouteConfig = { /** * Whether to cache the current page */ cachePage?: BunextCachePageType; /** * Expiry time of the cache in seconds */ cacheExpiry?: number; }; export type BunextPageModuleServerReturn = { props?: T; query?: Q; redirect?: BunextPageModuleServerRedirect; response_options?: ResponseInit; /** * Whether to cache the current page */ cache_page?: BunextCachePageType; /** * Expiry time of the cache in seconds */ cache_expiry?: number; url?: BunextPageModuleServerReturnURLObject; error?: string; res_transform?: (res: Response) => Promise | Response; }; export type BunextCachePageType = boolean | ((params: { ctx: Omit; serverRes?: BunextPageModuleServerReturn; }) => Promise | boolean); export type BunextPageProps = BunextPageModuleServerReturn; export type BunextPageModuleServerReturnURLObject = { hash: string; host: string; hostname: string; href: string; origin: string; password: string; pathname: string; port: string; protocol: string; search: string; searchParams: Record; username: string; }; export type BunextPageModuleServerRedirect = { destination: string; permanent?: boolean; status_code?: number; }; export type BunextPageModuleMetadata = { title?: string; description?: string; }; export type GrabPageComponentRes = { component?: FC; serverRes?: BunextPageModuleServerReturn; routeParams?: BunxRouteParams; bundledMap?: BundlerCTXMap; module?: BunextPageModule; root_module?: BunextRootModule; debug?: boolean; success?: boolean; }; export type BunextRootModule = BunextPageModule; export type GrabPageReactBundledComponentRes = { component?: FC; server_res?: BunextPageModuleServerReturn; tsx?: string; /** * The page's own exports (`meta`, `Head`, `config`, ...), re-exported * from the SSR bundle so they share its fresh module graph. */ page_module?: BunextPageModule; root_module?: BunextPageModule; }; export type PageFiles = { local_path: string; url_path: string; file_name: string; }; export type BundlerCTXMap = { path: string; hash: string; type: string; entrypoint: string; local_path: string; url_path: string; file_name: string; css_path?: string; }; export type GlobalHMRControllerObject = { controller: ReadableStreamDefaultController; page_url: string; target_map?: BundlerCTXMap; page_props?: any; page_reloaded?: boolean; page_cookie?: string | null; }; export type BunextCacheFileMeta = { date_created: number; paradigm: "html" | "json"; expiry_seconds?: number; }; export type BunextRootComponentProps = PropsWithChildren & BunextPageProps; export type GrabTSXModuleSingleParams = { tsx: string; page_file_path: string; }; export type GrabTSXModuleBatchParams = { tsx_map: GrabTSXModuleBatchMap[]; }; export type GrabTSXModuleBatchMap = { tsx: string; page_file_path: string; }; export type BunextAPIRouteJSONRes = { bunext_api_route_res_options?: ResponseInit; bunext_api_route_res_transform_fn?: (res: Response) => Promise | Response; } & { [k: string]: any; }; export type BunextAPIRouteHandlerObjectReturn = Response | (T & Pick); export type BunextAPIRouteHandler = (params: BunxRouteParams) => Promise> | Response | BunextAPIRouteHandlerObjectReturn; export type BunSpawnOptions = Bun.SpawnOptions.SpawnOptions<"inherit", "inherit", "inherit"> & { cmd: string[]; }; export type BuildDataType = { build_id: string; build_date_unix: number; build_date: string; }; export type BunextSitemapChangeFreq = "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never"; export type BunextSitemapEntry = { /** * URL path (e.g. `/blog/my-post`) or absolute URL. */ path: string; lastmod?: Date | string; changefreq?: BunextSitemapChangeFreq; /** * Between `0.0` and `1.0`. */ priority?: number; }; export type BunextSitemapAdditionalPaths = (string | BunextSitemapEntry)[]; export type BunextGenerateSitemapParams = { /** * Base URL prepended to every path. Defaults to `config.origin`, * falling back to `http://localhost:`. */ origin?: string; /** * Paths to leave out. A string matches a path exactly, or a whole * subtree when it ends with `/*` (e.g. `/admin/*`). A RegExp is * tested against the path. */ exclude?: (string | RegExp)[]; /** * Extra entries, typically concrete URLs for dynamic routes * (`[slug]`), which cannot be discovered from the file system. Can * also be a function (sync or async) returning them, e.g. to load * them from a database. */ additional_paths?: BunextSitemapAdditionalPaths | (() => BunextSitemapAdditionalPaths | Promise); /** * Fall back to each page file's modification time as `lastmod` when * the build record has no date for it. Defaults to `false`: checkouts * reset modification times, so they are rarely meaningful. */ use_file_lastmod?: boolean; /** * `lastmod` for entries that have no other date */ default_lastmod?: Date | string; /** * Page last-modified record written by `bunext build`, relative to the * project root. Defaults to `.bunext/page-lastmod.json`. Point it at a * cached or committed location when builds start from a fresh checkout. */ lastmod_file?: string; /** * Append a trailing slash to every non-root path. Defaults to `false`. */ trailing_slash?: boolean; default_changefreq?: BunextSitemapChangeFreq; default_priority?: number; }; export type BunextSitemapConfig = BunextGenerateSitemapParams & { /** * Maximum URLs per sitemap file. Above this, `bunext sitemap` writes * chunk files to `chunks_dir` and makes sitemap.xml a sitemap index * referencing them. Defaults to 10,000; capped at 50,000, the protocol * limit. Chunks are also split at 50MB. */ chunk_size?: number; /** * Directory for sitemap chunk files, relative to the project root. * Must be inside `public/` so the files are served. Defaults to * `public/sitemap-chunks`. */ chunks_dir?: string; /** * Output file, relative to the project root. Defaults to * `public/sitemap.xml`, which is served at `/sitemap.xml`. */ output?: string; }; export type BunextRobotsRule = { /** * One or more crawler names, e.g. `*` or `["GPTBot", "CCBot"]` */ user_agent: string | string[]; allow?: string[]; disallow?: string[]; /** * Seconds between requests. Not supported by every crawler. */ crawl_delay?: number; }; export type BunextGenerateRobotsTxtParams = { /** * Base URL used to turn relative `sitemaps` paths into absolute URLs. * Defaults to `config.origin`, falling back to `http://localhost:`. */ origin?: string; /** * Defaults to allowing every crawler everywhere. */ rules?: BunextRobotsRule[]; /** * Sitemap URLs or paths, each written as a `Sitemap:` line. */ sitemaps?: string[]; /** * Block every crawler from the whole site, ignoring `rules` and * `sitemaps`. Useful for staging deployments. */ disallow_all?: boolean; }; export type BunextRobotsConfig = BunextGenerateRobotsTxtParams & { /** * Output file, relative to the project root. Defaults to * `public/robots.txt`, which is served at `/robots.txt`. */ output?: string; }; /** * Written by `bunext build`. Keyed by page path relative to the project * root. `lastmod` is the build date at which `fingerprint` last changed. */ export type BunextPageLastmodRecord = { pages: { [local_path: string]: { fingerprint: string; lastmod: string; }; }; };