fumapress 0.5.4 → 0.5.5

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/css/generated.css CHANGED
@@ -6,6 +6,7 @@
6
6
  @source inline("@orama/orama");
7
7
  @source inline("a");
8
8
  @source inline("above");
9
+ @source inline("absolute");
9
10
  @source inline("absolutePath");
10
11
  @source inline("accepts");
11
12
  @source inline("active:scale-95");
@@ -374,6 +375,7 @@
374
375
  @source inline("requests");
375
376
  @source inline("resolution");
376
377
  @source inline("resolve");
378
+ @source inline("resolveBaseUrl");
377
379
  @source inline("resolved");
378
380
  @source inline("rest");
379
381
  @source inline("result");
@@ -512,6 +514,7 @@
512
514
  @source inline("width");
513
515
  @source inline("widths");
514
516
  @source inline("will");
517
+ @source inline("with");
515
518
  @source inline("without");
516
519
  @source inline("would");
517
520
  @source inline("wrapper");
@@ -1,8 +1,8 @@
1
1
  import { Link } from "./link.js";
2
+ import { joinPathname } from "../lib/pathname.js";
2
3
  import { getCreationDate, getPressContext } from "../lib/shared.js";
3
4
  import { cn } from "../lib/cn.js";
4
5
  import { I18nLabel } from "./i18n.js";
5
- import { joinPathname } from "../lib/pathname.js";
6
6
  import { getBlogContext } from "../plugins/blog.js";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { CornerLeftUpIcon } from "lucide-react";
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { resolveBaseUrl } from "../lib/pathname.js";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
4
  import { useI18n } from "fumadocs-ui/contexts/i18n";
4
5
  import { SearchDialog, SearchDialogClose, SearchDialogContent, SearchDialogHeader, SearchDialogIcon, SearchDialogInput, SearchDialogList, SearchDialogOverlay } from "fumadocs-ui/components/dialog/search";
@@ -7,7 +8,10 @@ import { flexsearchStaticClient } from "fumadocs-core/search/client/flexsearch-s
7
8
  //#region src/components/flexsearch-static.tsx
8
9
  function DefaultSearchDialog(props) {
9
10
  const { locale } = useI18n();
10
- const { search, setSearch, query } = useDocsSearch({ client: flexsearchStaticClient({ locale }) });
11
+ const { search, setSearch, query } = useDocsSearch({ client: flexsearchStaticClient({
12
+ locale,
13
+ from: resolveBaseUrl(import.meta.env.BASE_URL, "/api/search")
14
+ }) });
11
15
  return /* @__PURE__ */ jsxs(SearchDialog, {
12
16
  search,
13
17
  onSearchChange: setSearch,
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { resolveBaseUrl } from "../lib/pathname.js";
2
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
4
  import { createContext, use, useMemo } from "react";
4
5
  import ReactDOM from "react-dom";
@@ -11,14 +12,14 @@ function parseLength(v) {
11
12
  return parsed;
12
13
  }
13
14
  /**
14
- * resolve src to a full pathname if relative
15
+ * resolve src to a full pathname with base URL included (or keep absolute URLs as-is)
15
16
  */
16
17
  function normalizeSrc(src, basePathname) {
17
- if (src.startsWith("http://") || src.startsWith("https://")) return src;
18
+ if (src.startsWith("http://") || src.startsWith("https://") || src.startsWith("data:")) return src;
18
19
  const base = new URL(basePathname, "http://localhost");
19
20
  const resolved = new URL(src, base);
20
21
  if (resolved.hostname !== base.hostname) throw new Error(`The src attribute "${src}" is not a valid relative path`);
21
- return resolved.pathname;
22
+ return resolveBaseUrl(import.meta.env.BASE_URL, resolved.pathname);
22
23
  }
23
24
  const ImageContext = createContext(null);
24
25
  function ImageProvider({ provider, children }) {
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { resolveBaseUrl } from "../lib/pathname.js";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
4
  import { useI18n } from "fumadocs-ui/contexts/i18n";
4
5
  import { SearchDialog, SearchDialogClose, SearchDialogContent, SearchDialogHeader, SearchDialogIcon, SearchDialogInput, SearchDialogList, SearchDialogOverlay } from "fumadocs-ui/components/dialog/search";
@@ -16,7 +17,8 @@ function DefaultSearchDialog(props) {
16
17
  const { search, setSearch, query } = useDocsSearch({
17
18
  type: "static",
18
19
  initOrama,
19
- locale
20
+ locale,
21
+ from: resolveBaseUrl(import.meta.env.BASE_URL, "/api/search")
20
22
  });
21
23
  return /* @__PURE__ */ jsxs(SearchDialog, {
22
24
  search,
@@ -1,8 +1,8 @@
1
1
  import { Link } from "../components/link.js";
2
+ import { joinPathname } from "../lib/pathname.js";
2
3
  import { getPressContext } from "../lib/shared.js";
3
4
  import { cn } from "../lib/cn.js";
4
5
  import { I18nLabel } from "../components/i18n.js";
5
- import { joinPathname } from "../lib/pathname.js";
6
6
  import { getBlogContext } from "../plugins/blog.js";
7
7
  import { OrderedBlogGrid } from "../components/blog.js";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -1,8 +1,8 @@
1
1
  import { Link } from "../components/link.js";
2
+ import { joinPathname } from "../lib/pathname.js";
2
3
  import { getCreationDate, getPressContext, renderBody, renderPageMeta, renderToc } from "../lib/shared.js";
3
4
  import { BlogPanel, BlogProvider } from "../components/blog-panel.js";
4
5
  import { getTags } from "../lib/shared/blog.js";
5
- import { joinPathname } from "../lib/pathname.js";
6
6
  import { createHomeLayout } from "./home.js";
7
7
  import { getBlogContext } from "../plugins/blog.js";
8
8
  import { LinkToHome } from "../components/blog.js";
@@ -1,4 +1,5 @@
1
1
  //#region src/lib/pathname.ts
2
+ /** Join multiple (full) pathnames */
2
3
  function joinPathname(...paths) {
3
4
  const segs = [];
4
5
  for (let p of paths) {
@@ -10,8 +11,14 @@ function joinPathname(...paths) {
10
11
  }
11
12
  const PATHNAME_SEGMENT_REGEX = /^[A-Za-z0-9\-._~!$&'()*+,;=:@]+$/;
12
13
  /** Check if the string is a full pathname (one that does not include `.` or `..`) */
13
- function isPlainPathname(s) {
14
+ function isFullPathname(s) {
14
15
  return s.startsWith("/") && s.slice(1).split("/").every((seg) => seg !== "." && seg !== ".." && PATHNAME_SEGMENT_REGEX.test(seg));
15
16
  }
17
+ /** add base URL to pathname */
18
+ function resolveBaseUrl(base, pathname) {
19
+ if (base.endsWith("/")) base = base.slice(0, -1);
20
+ if (pathname.startsWith("/")) pathname = pathname.slice(1);
21
+ return `${base}/${pathname}`;
22
+ }
16
23
  //#endregion
17
- export { isPlainPathname, joinPathname };
24
+ export { isFullPathname, joinPathname, resolveBaseUrl };
@@ -1,5 +1,5 @@
1
- import { groupTags, groupTagsI18n } from "../lib/shared/blog.js";
2
1
  import { joinPathname } from "../lib/pathname.js";
2
+ import { groupTags, groupTagsI18n } from "../lib/shared/blog.js";
3
3
  import { createBlogLayout, createBlogLayoutPage } from "../layouts/blog.js";
4
4
  import { createBlogTagPage, createBlogTagsPage } from "../layouts/blog.tags.js";
5
5
  import { createBlogIndexPage } from "../layouts/blog.index.js";
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { ImageProvider } from "../../components/image.js";
3
2
  import { joinPathname } from "../../lib/pathname.js";
3
+ import { ImageProvider } from "../../components/image.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { useMemo } from "react";
6
6
  //#region src/plugins/image/cloudflare.client.tsx
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { resolveBaseUrl } from "../../lib/pathname.js";
2
3
  import { ImageProvider } from "../../components/image.js";
3
4
  import { validateImageSrc } from "./self-hosted.utils.js";
4
5
  import { jsx } from "react/jsx-runtime";
@@ -16,7 +17,7 @@ function createProvider(config) {
16
17
  width: String(width),
17
18
  quality: String(quality)
18
19
  });
19
- return `${config.path}?${params.toString()}`;
20
+ return `${resolveBaseUrl(import.meta.env.BASE_URL, config.path)}?${params.toString()}`;
20
21
  },
21
22
  validate(src) {
22
23
  if (import.meta.env.DEV) {
@@ -1,5 +1,5 @@
1
1
  import { __toESM } from "../../_virtual/_rolldown/runtime.js";
2
- import { isPlainPathname } from "../../lib/pathname.js";
2
+ import { isFullPathname } from "../../lib/pathname.js";
3
3
  import { require_http_cache_semantics } from "../../node_modules/.pnpm/http-cache-semantics@4.2.0/node_modules/http-cache-semantics/index.js";
4
4
  //#region src/plugins/image/self-hosted.utils.ts
5
5
  var import_http_cache_semantics = /* @__PURE__ */ __toESM(require_http_cache_semantics(), 1);
@@ -253,7 +253,7 @@ function validateImageSrc(config, src) {
253
253
  };
254
254
  return { allowed: true };
255
255
  }
256
- if (isPlainPathname(src)) return { allowed: true };
256
+ if (isFullPathname(src)) return { allowed: true };
257
257
  return {
258
258
  allowed: false,
259
259
  reason: `Image URL "${src}" is not normalized`
@@ -1,4 +1,4 @@
1
- import { isPlainPathname } from "../lib/pathname.js";
1
+ import { isFullPathname, resolveBaseUrl } from "../lib/pathname.js";
2
2
  import { PayloadProvider, WithPayload } from "../components/openapi.payload.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { openapiTranslations } from "fumadocs-openapi/i18n";
@@ -16,9 +16,14 @@ function openapiPlugin(options) {
16
16
  }
17
17
  async function ServerPayloadProvider({ children }) {
18
18
  const payload = {};
19
+ let clientProxyUrl;
20
+ if (typeof server.options.proxyUrl === "string") {
21
+ const proxyUrl = server.options.proxyUrl;
22
+ clientProxyUrl = isFullPathname(proxyUrl) ? resolveBaseUrl(import.meta.env.BASE_URL, proxyUrl) : proxyUrl;
23
+ }
19
24
  for (const [schemaId, schema] of Object.entries(await server.getSchemas())) payload[schemaId] = {
20
25
  bundled: schema.bundled,
21
- proxyUrl: server.options.proxyUrl
26
+ proxyUrl: clientProxyUrl
22
27
  };
23
28
  return /* @__PURE__ */ jsx(PayloadProvider, {
24
29
  payload: JSON.stringify(payload),
@@ -46,7 +51,7 @@ function openapiPlugin(options) {
46
51
  },
47
52
  async createPages({ createApi }) {
48
53
  const proxyUrl = server.options.proxyUrl;
49
- const { createProxy = typeof proxyUrl === "string" && isPlainPathname(proxyUrl) } = options;
54
+ const { createProxy = typeof proxyUrl === "string" && isFullPathname(proxyUrl) } = options;
50
55
  if (createProxy) {
51
56
  if (!proxyUrl) throw new Error(`[Fumapress] The "proxyUrl" option in createOpenAPI() is required to create proxy server`);
52
57
  if (this.mode === "static") throw new Error(`[Fumapress] static mode is not compatible with proxy server`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumapress",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "An opinionated docs framework powered by Fumadocs",
5
5
  "keywords": [
6
6
  "Docs",