docs: add JSON-LD schemas to docs (#14007)
This commit is contained in:
@@ -41,7 +41,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
*::selection {
|
*::selection {
|
||||||
@apply bg-medusa-bg-highlight;
|
@apply bg-medusa-fg-subtle text-medusa-fg-on-inverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import { BareboneLayout, WideLayout } from "docs-ui"
|
|||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { Metadata } from "next"
|
import { Metadata } from "next"
|
||||||
import { inter, robotoMono } from "./fonts"
|
import { inter, robotoMono } from "./fonts"
|
||||||
|
import { config } from "@/config"
|
||||||
|
|
||||||
const ogImage =
|
const ogImage =
|
||||||
"https://res.cloudinary.com/dza7lstvk/image/upload/v1732200992/Medusa%20Resources/opengraph-image_daq6nx.jpg"
|
"https://res.cloudinary.com/dza7lstvk/image/upload/v1732200992/Medusa%20Resources/opengraph-image_daq6nx.jpg"
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Medusa API Reference",
|
title: `%s - ${config.titleSuffix}`,
|
||||||
description: "Check out Medusa's API reference",
|
description: config.description,
|
||||||
metadataBase: new URL(
|
metadataBase: new URL(
|
||||||
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
|||||||
|
|
||||||
export const config: DocsConfig = {
|
export const config: DocsConfig = {
|
||||||
...globalConfig,
|
...globalConfig,
|
||||||
|
titleSuffix: "Medusa API Reference",
|
||||||
|
description:
|
||||||
|
"Comprehensive reference for Medusa's API routes, request/response structures, authentication methods, and error handling.",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
||||||
// sidebar is auto generated
|
// sidebar is auto generated
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
*::selection {
|
*::selection {
|
||||||
@apply bg-medusa-bg-highlight;
|
@apply bg-medusa-fg-subtle text-medusa-fg-on-inverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
*:not(.code-block-elm) {
|
*:not(.code-block-elm) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const metadata: Metadata = {
|
|||||||
template: `%s - ${config.titleSuffix}`,
|
template: `%s - ${config.titleSuffix}`,
|
||||||
default: config.titleSuffix || "",
|
default: config.titleSuffix || "",
|
||||||
},
|
},
|
||||||
description: "Explore and learn how to use Medusa.",
|
description: config.description,
|
||||||
metadataBase: new URL(
|
metadataBase: new URL(
|
||||||
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
|||||||
export const config: DocsConfig = {
|
export const config: DocsConfig = {
|
||||||
...globalConfig,
|
...globalConfig,
|
||||||
titleSuffix: "Medusa Documentation",
|
titleSuffix: "Medusa Documentation",
|
||||||
|
description:
|
||||||
|
"Explore and learn how to use Medusa. Learn how to get started, the fundamental concepts, how to customize Medusa, and more.",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
||||||
sidebars: generatedSidebars as Sidebar.Sidebar[],
|
sidebars: generatedSidebars as Sidebar.Sidebar[],
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
*::selection {
|
*::selection {
|
||||||
@apply bg-medusa-bg-highlight;
|
@apply bg-medusa-fg-subtle text-medusa-fg-on-inverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
*:not(.code-block-elm) {
|
*:not(.code-block-elm) {
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ export const metadata: Metadata = {
|
|||||||
template: `%s - ${config.titleSuffix}`,
|
template: `%s - ${config.titleSuffix}`,
|
||||||
default: config.titleSuffix || "",
|
default: config.titleSuffix || "",
|
||||||
},
|
},
|
||||||
description:
|
description: config.description,
|
||||||
"Learn about Cloud, Medusa's PaaS offering for scalable deployments.",
|
|
||||||
metadataBase: new URL(
|
metadataBase: new URL(
|
||||||
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
|||||||
export const config: DocsConfig = {
|
export const config: DocsConfig = {
|
||||||
...globalConfig,
|
...globalConfig,
|
||||||
titleSuffix: "Medusa Cloud Documentation",
|
titleSuffix: "Medusa Cloud Documentation",
|
||||||
|
description:
|
||||||
|
"Learn about Cloud, Medusa's PaaS offering for scalable deployments. Learn how to sign up, deploy, and manage your Medusa Cloud projects.",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
||||||
sidebars: generatedSidebars as Sidebar.Sidebar[],
|
sidebars: generatedSidebars as Sidebar.Sidebar[],
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
*::selection {
|
*::selection {
|
||||||
@apply bg-medusa-bg-highlight;
|
@apply bg-medusa-fg-subtle text-medusa-fg-on-inverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ export const metadata: Metadata = {
|
|||||||
template: `%s - ${config.titleSuffix}`,
|
template: `%s - ${config.titleSuffix}`,
|
||||||
default: config.titleSuffix || "",
|
default: config.titleSuffix || "",
|
||||||
},
|
},
|
||||||
description:
|
description: config.description,
|
||||||
"Explore Medusa's recipes, API references, configurations, storefront guides, and more.",
|
|
||||||
metadataBase: new URL(
|
metadataBase: new URL(
|
||||||
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
|||||||
export const config: DocsConfig = {
|
export const config: DocsConfig = {
|
||||||
...globalConfig,
|
...globalConfig,
|
||||||
titleSuffix: "Medusa Documentation",
|
titleSuffix: "Medusa Documentation",
|
||||||
|
description:
|
||||||
|
"Explore Medusa's recipes, Commerce and Infrastructure modules, API and SDK references, storefront guides, how-to guides, tutorials, and more.",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
||||||
sidebars: [],
|
sidebars: [],
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
*::selection {
|
*::selection {
|
||||||
@apply bg-medusa-bg-highlight;
|
@apply bg-medusa-fg-subtle text-medusa-fg-on-inverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
*:not(.code-block-elm) {
|
*:not(.code-block-elm) {
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ export const metadata: Metadata = {
|
|||||||
template: `%s - ${config.titleSuffix}`,
|
template: `%s - ${config.titleSuffix}`,
|
||||||
default: config.titleSuffix || "",
|
default: config.titleSuffix || "",
|
||||||
},
|
},
|
||||||
description:
|
description: config.description,
|
||||||
"Learn about Medusa UI, A React package with primitives for building Medusa applications.",
|
|
||||||
metadataBase: new URL(
|
metadataBase: new URL(
|
||||||
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
|||||||
export const config: DocsConfig = {
|
export const config: DocsConfig = {
|
||||||
...globalConfig,
|
...globalConfig,
|
||||||
titleSuffix: "Medusa UI",
|
titleSuffix: "Medusa UI",
|
||||||
|
description:
|
||||||
|
"Learn about Medusa UI, A React package with primitives for building Medusa applications. Explore components, hooks, colors, icons, and more.",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
||||||
sidebars: generatedSidebars as Sidebar.Sidebar[],
|
sidebars: generatedSidebars as Sidebar.Sidebar[],
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
*::selection {
|
*::selection {
|
||||||
@apply bg-medusa-bg-highlight;
|
@apply bg-medusa-fg-subtle text-medusa-fg-on-inverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
*:not(.code-block-elm) {
|
*:not(.code-block-elm) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const metadata: Metadata = {
|
|||||||
template: `%s - ${config.titleSuffix}`,
|
template: `%s - ${config.titleSuffix}`,
|
||||||
default: config.titleSuffix || "",
|
default: config.titleSuffix || "",
|
||||||
},
|
},
|
||||||
description: "Explore and learn how to use the Medusa Admin.",
|
description: config.description,
|
||||||
metadataBase: new URL(
|
metadataBase: new URL(
|
||||||
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
|||||||
export const config: DocsConfig = {
|
export const config: DocsConfig = {
|
||||||
...globalConfig,
|
...globalConfig,
|
||||||
titleSuffix: "Medusa Admin User Guide",
|
titleSuffix: "Medusa Admin User Guide",
|
||||||
|
description:
|
||||||
|
"Explore and learn how to use the Medusa Admin. Learn how to manage products, orders, customers, and more within the Medusa Admin dashboard.",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
||||||
sidebars: generatedSidebars as Sidebar.Sidebar[],
|
sidebars: generatedSidebars as Sidebar.Sidebar[],
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
"eslint": "^9.13.0",
|
"eslint": "^9.13.0",
|
||||||
"next": "15.3.5",
|
"next": "15.3.5",
|
||||||
"rimraf": "^5.0.1",
|
"rimraf": "^5.0.1",
|
||||||
|
"schema-dts": "^1.1.5",
|
||||||
"tailwind": "*",
|
"tailwind": "*",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"tsc-alias": "^1.8.7",
|
"tsc-alias": "^1.8.7",
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { useSidebar, useSiteConfig } from "../../providers"
|
|||||||
import { Button } from "../Button"
|
import { Button } from "../Button"
|
||||||
import { TriangleRightMini } from "@medusajs/icons"
|
import { TriangleRightMini } from "@medusajs/icons"
|
||||||
import { Sidebar } from "types"
|
import { Sidebar } from "types"
|
||||||
|
import { getJsonLd } from "../../utils"
|
||||||
|
import type { BreadcrumbList } from "schema-dts"
|
||||||
|
|
||||||
type BreadcrumbItems = {
|
type BreadcrumbItems = {
|
||||||
title: string
|
title: string
|
||||||
@@ -16,7 +18,7 @@ type BreadcrumbItems = {
|
|||||||
export const Breadcrumbs = () => {
|
export const Breadcrumbs = () => {
|
||||||
const { sidebarHistory, getSidebarFirstLinkChild, getSidebar } = useSidebar()
|
const { sidebarHistory, getSidebarFirstLinkChild, getSidebar } = useSidebar()
|
||||||
const {
|
const {
|
||||||
config: { breadcrumbOptions },
|
config: { breadcrumbOptions, baseUrl, basePath },
|
||||||
} = useSiteConfig()
|
} = useSiteConfig()
|
||||||
|
|
||||||
const getLinkPath = (item: Sidebar.SidebarItemLink): string => {
|
const getLinkPath = (item: Sidebar.SidebarItemLink): string => {
|
||||||
@@ -51,6 +53,24 @@ export const Breadcrumbs = () => {
|
|||||||
return items
|
return items
|
||||||
}, [sidebarHistory, breadcrumbOptions])
|
}, [sidebarHistory, breadcrumbOptions])
|
||||||
|
|
||||||
|
const jsonLd = useMemo(() => {
|
||||||
|
const baseLink = `${baseUrl}${basePath}`.replace(/\/+$/, "")
|
||||||
|
return getJsonLd<BreadcrumbList>({
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
itemListElement: breadcrumbItems.map((item, index) => ({
|
||||||
|
"@type": "ListItem",
|
||||||
|
position: index + 1,
|
||||||
|
name: item.title,
|
||||||
|
item: item.link.startsWith("#")
|
||||||
|
? baseLink
|
||||||
|
: item.link.startsWith("/")
|
||||||
|
? `${baseLink}${item.link}`
|
||||||
|
: item.link,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
}, [breadcrumbItems, baseUrl, basePath])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
@@ -79,6 +99,12 @@ export const Breadcrumbs = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: jsonLd,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from "react"
|
||||||
|
import type { TechArticle } from "schema-dts"
|
||||||
|
import { useIsBrowser, useSiteConfig } from "../../providers"
|
||||||
|
import { getJsonLd } from "../../utils"
|
||||||
|
import { usePathname } from "next/navigation"
|
||||||
|
|
||||||
|
export const TechArticleJsonLd = () => {
|
||||||
|
const {
|
||||||
|
config: { baseUrl, basePath, description: configDescription, titleSuffix },
|
||||||
|
} = useSiteConfig()
|
||||||
|
const pathname = usePathname()
|
||||||
|
const { isBrowser } = useIsBrowser()
|
||||||
|
const [jsonLdData, setJsonLdData] = useState("{}")
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isBrowser) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a small delay to ensure the document has been updated after navigation
|
||||||
|
const updateJsonLd = () => {
|
||||||
|
const baseLink = `${baseUrl}${basePath}`.replace(/\/+$/, "")
|
||||||
|
const title = document.title.replace(` - ${titleSuffix}`, "")
|
||||||
|
const description =
|
||||||
|
document.querySelector("#main p")?.textContent ||
|
||||||
|
configDescription ||
|
||||||
|
""
|
||||||
|
|
||||||
|
const data = getJsonLd<TechArticle>({
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "TechArticle",
|
||||||
|
headline: title,
|
||||||
|
description,
|
||||||
|
proficiencyLevel: "Expert",
|
||||||
|
author: "Medusa",
|
||||||
|
genre: "Documentation",
|
||||||
|
keywords: "medusa, ecommerce, open-source",
|
||||||
|
url: `${baseLink}${pathname}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
setJsonLdData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update immediately
|
||||||
|
updateJsonLd()
|
||||||
|
|
||||||
|
// Also set up a MutationObserver to watch for title changes
|
||||||
|
const titleObserver = new MutationObserver(() => {
|
||||||
|
updateJsonLd()
|
||||||
|
})
|
||||||
|
|
||||||
|
const titleElement = document.querySelector("title")
|
||||||
|
if (titleElement) {
|
||||||
|
titleObserver.observe(titleElement, {
|
||||||
|
childList: true,
|
||||||
|
characterData: true,
|
||||||
|
subtree: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
titleObserver.disconnect()
|
||||||
|
}
|
||||||
|
}, [isBrowser, pathname, baseUrl, basePath, configDescription, titleSuffix])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{ __html: jsonLdData }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import clsx from "clsx"
|
|||||||
import { RootProviders, Sidebar, SidebarProps } from "@/components"
|
import { RootProviders, Sidebar, SidebarProps } from "@/components"
|
||||||
import { MainContentLayout, MainContentLayoutProps } from "./main-content"
|
import { MainContentLayout, MainContentLayoutProps } from "./main-content"
|
||||||
import { AiAssistantChatWindow } from "../components/AiAssistant/ChatWindow"
|
import { AiAssistantChatWindow } from "../components/AiAssistant/ChatWindow"
|
||||||
|
import { TechArticleJsonLd } from "../components/TechArticleJsonLd"
|
||||||
|
|
||||||
export type RootLayoutProps = {
|
export type RootLayoutProps = {
|
||||||
bodyClassName?: string
|
bodyClassName?: string
|
||||||
@@ -37,6 +38,7 @@ export const RootLayout = ({
|
|||||||
<MainContentLayout {...mainProps} />
|
<MainContentLayout {...mainProps} />
|
||||||
<AiAssistantChatWindow />
|
<AiAssistantChatWindow />
|
||||||
</div>
|
</div>
|
||||||
|
<TechArticleJsonLd />
|
||||||
</ProvidersComponent>
|
</ProvidersComponent>
|
||||||
</RootProviders>
|
</RootProviders>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
5
www/packages/docs-ui/src/utils/get-json-ld.ts
Normal file
5
www/packages/docs-ui/src/utils/get-json-ld.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import type { Thing, WithContext } from "schema-dts"
|
||||||
|
|
||||||
|
export function getJsonLd<T extends Thing>(data: WithContext<T>): string {
|
||||||
|
return JSON.stringify(data, null, 2).replace(/</g, "\\u003c")
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ export * from "./check-sidebar-item-visibility"
|
|||||||
export * from "./decode-str"
|
export * from "./decode-str"
|
||||||
export * from "./dom-utils"
|
export * from "./dom-utils"
|
||||||
export * from "./event-parser"
|
export * from "./event-parser"
|
||||||
|
export * from "./get-json-ld"
|
||||||
export * from "./get-link-with-base-path"
|
export * from "./get-link-with-base-path"
|
||||||
export * from "./get-local-search"
|
export * from "./get-local-search"
|
||||||
export * from "./get-navbar-items"
|
export * from "./get-navbar-items"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export type BreadcrumbOptions = {
|
|||||||
|
|
||||||
export declare type DocsConfig = {
|
export declare type DocsConfig = {
|
||||||
titleSuffix?: string
|
titleSuffix?: string
|
||||||
|
description?: string
|
||||||
baseUrl: string
|
baseUrl: string
|
||||||
basePath?: string
|
basePath?: string
|
||||||
sidebars: Sidebar.Sidebar[]
|
sidebars: Sidebar.Sidebar[]
|
||||||
|
|||||||
@@ -7276,6 +7276,7 @@ __metadata:
|
|||||||
react-uuid: ^2.0.0
|
react-uuid: ^2.0.0
|
||||||
reodotdev: ^1.0.0
|
reodotdev: ^1.0.0
|
||||||
rimraf: ^5.0.1
|
rimraf: ^5.0.1
|
||||||
|
schema-dts: ^1.1.5
|
||||||
slugify: ^1.6.6
|
slugify: ^1.6.6
|
||||||
tailwind: "*"
|
tailwind: "*"
|
||||||
tailwindcss: ^3.3.3
|
tailwindcss: ^3.3.3
|
||||||
@@ -13652,6 +13653,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"schema-dts@npm:^1.1.5":
|
||||||
|
version: 1.1.5
|
||||||
|
resolution: "schema-dts@npm:1.1.5"
|
||||||
|
checksum: babe23a1577c75c5df79d73acf34af3399e60928eab46f2236a0c4212061f5778d613a31c9e9ec86a2807d20b1ea460673d72d3fe1f64fb7543867460e607f76
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"search-insights@npm:^2.15.0":
|
"search-insights@npm:^2.15.0":
|
||||||
version: 2.16.3
|
version: 2.16.3
|
||||||
resolution: "search-insights@npm:2.16.3"
|
resolution: "search-insights@npm:2.16.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user