next-drupal
Version:
Helpers for Next.js + Drupal.
1 lines • 10.2 kB
Source Map (JSON)
{"version":3,"sources":["../src/navigation.ts","../src/deprecated/use-menu.ts","../src/deprecated/utils.ts","../src/deprecated/get-cache.ts","../src/deprecated/get-access-token.ts","../src/deprecated/get-menu.ts"],"sourcesContent":["export { useMenu } from \"./deprecated/use-menu\"\n","import { useRouter } from \"next/router\"\nimport { useEffect, useState } from \"react\"\nimport { getMenu } from \"./get-menu\"\nimport type { DrupalMenuItem } from \"../types\"\n\nexport function useMenu<T extends DrupalMenuItem>(\n name: string\n): {\n items: T[]\n tree: T[]\n error: unknown\n isLoading: boolean\n} {\n const router = useRouter()\n const [data, setData] = useState<{\n items: T[]\n tree: T[]\n }>(null)\n const [error, setError] = useState(null)\n const [isLoading, setIsLoading] = useState<boolean>(false)\n\n useEffect(() => {\n const fetchMenuItems = async () => {\n setIsLoading(true)\n try {\n const data = await getMenu<T>(name, {\n locale: router.locale,\n defaultLocale: router.defaultLocale,\n })\n setData(data)\n setIsLoading(false)\n } catch (error) {\n setError(error)\n setIsLoading(false)\n }\n }\n fetchMenuItems()\n }, [router.locale])\n\n return { ...data, error, isLoading }\n}\n","import { Jsona } from \"jsona\"\nimport { stringify } from \"qs\"\nimport { getAccessToken } from \"./get-access-token\"\nimport type { GetStaticPropsContext } from \"next\"\nimport type { AccessToken, Locale } from \"../types\"\n\nconst JSONAPI_PREFIX = process.env.DRUPAL_JSONAPI_PREFIX || \"/jsonapi\"\n\nconst dataFormatter = new Jsona()\n\nexport function deserialize(body, options?) {\n if (!body) return null\n\n return dataFormatter.deserialize(body, options)\n}\n\nexport async function getJsonApiPathForResourceType(\n type: string,\n locale?: Locale\n) {\n const index = await getJsonApiIndex(locale)\n\n return index?.links[type]?.href\n}\n\nexport async function getJsonApiIndex(\n locale?: Locale,\n options?: {\n accessToken?: AccessToken\n }\n): Promise<{\n links: {\n [type: string]: {\n href: string\n }\n }\n}> {\n const url = buildUrl(\n locale ? `/${locale}${JSONAPI_PREFIX}` : `${JSONAPI_PREFIX}`\n )\n\n // As per https://www.drupal.org/node/2984034 /jsonapi is public.\n // We only call buildHeaders if accessToken or locale is explicitly set.\n // This is for rare cases where /jsonapi might be protected.\n const response = await fetch(url.toString(), {\n headers:\n locale || options\n ? await buildHeaders(options)\n : {\n \"Content-Type\": \"application/json\",\n },\n })\n\n if (!response.ok) {\n throw new Error(response.statusText)\n }\n\n return await response.json()\n}\n\nexport function buildUrl(\n path: string,\n params?: string | Record<string, string> | URLSearchParams\n): URL {\n const url = new URL(\n path.charAt(0) === \"/\"\n ? `${process.env.NEXT_PUBLIC_DRUPAL_BASE_URL}${path}`\n : path\n )\n\n if (params) {\n // Use instead URLSearchParams for nested params.\n url.search = stringify(params)\n }\n\n return url\n}\n\nexport async function buildHeaders({\n accessToken,\n headers = {\n \"Content-Type\": \"application/json\",\n },\n}: {\n accessToken?: AccessToken\n headers?: RequestInit[\"headers\"]\n} = {}): Promise<RequestInit[\"headers\"]> {\n // This allows an access_token (preferrably long-lived) to be set directly on the env.\n // This reduces the number of OAuth call to the Drupal server.\n // Intentionally marked as unstable for now.\n if (process.env.UNSTABLE_DRUPAL_ACCESS_TOKEN) {\n headers[\"Authorization\"] =\n `Bearer ${process.env.UNSTABLE_DRUPAL_ACCESS_TOKEN}`\n\n return headers\n }\n\n const token = accessToken || (await getAccessToken())\n if (token) {\n headers[\"Authorization\"] = `Bearer ${token.access_token}`\n }\n\n return headers\n}\n\nexport function getPathFromContext(\n context: GetStaticPropsContext,\n prefix = \"\"\n) {\n let { slug } = context.params\n\n slug = Array.isArray(slug)\n ? slug.map((s) => encodeURIComponent(s)).join(\"/\")\n : slug\n\n // Handle locale.\n if (context.locale && context.locale !== context.defaultLocale) {\n slug = `/${context.locale}/${slug}`\n }\n\n return !slug\n ? process.env.DRUPAL_FRONT_PAGE\n : prefix\n ? `${prefix}/${slug}`\n : slug\n}\n\nexport function syncDrupalPreviewRoutes(path) {\n if (window && window.top !== window.self) {\n window.parent.postMessage(\n { type: \"NEXT_DRUPAL_ROUTE_SYNC\", path },\n process.env.NEXT_PUBLIC_DRUPAL_BASE_URL\n )\n }\n}\n","import NodeCache from \"node-cache\"\n\nexport const cache = new NodeCache()\n","import { cache } from \"./get-cache\"\nimport type { AccessToken } from \"../types\"\n\nconst CACHE_KEY = \"NEXT_DRUPAL_ACCESS_TOKEN\"\n\n/** @deprecated */\nexport async function getAccessToken(): Promise<AccessToken> {\n if (!process.env.DRUPAL_CLIENT_ID || !process.env.DRUPAL_CLIENT_SECRET) {\n return null\n }\n\n const cached = cache.get<AccessToken>(CACHE_KEY)\n if (cached?.access_token) {\n return cached\n }\n\n const basic = Buffer.from(\n `${process.env.DRUPAL_CLIENT_ID}:${process.env.DRUPAL_CLIENT_SECRET}`\n ).toString(\"base64\")\n\n const response = await fetch(\n `${process.env.NEXT_PUBLIC_DRUPAL_BASE_URL}/oauth/token`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Basic ${basic}`,\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: `grant_type=client_credentials`,\n }\n )\n\n if (!response.ok) {\n throw new Error(response.statusText)\n }\n\n const result: AccessToken = await response.json()\n\n cache.set(CACHE_KEY, result, result.expires_in)\n\n return result\n}\n","import { buildHeaders, buildUrl, deserialize } from \"./utils\"\nimport type { AccessToken, DrupalMenuItem } from \"../types\"\nimport type { JsonApiWithLocaleOptions } from \"../types/deprecated\"\n\nexport async function getMenu<T extends DrupalMenuItem>(\n name: string,\n options?: {\n deserialize?: boolean\n accessToken?: AccessToken\n } & JsonApiWithLocaleOptions\n): Promise<{\n items: T[]\n tree: T[]\n}> {\n options = {\n deserialize: true,\n ...options,\n }\n\n const localePrefix =\n options?.locale && options.locale !== options.defaultLocale\n ? `/${options.locale}`\n : \"\"\n\n const url = buildUrl(`${localePrefix}/jsonapi/menu_items/${name}`)\n\n const response = await fetch(url.toString(), {\n headers: await buildHeaders(options),\n })\n\n if (!response.ok) {\n throw new Error(response.statusText)\n }\n\n const data = await response.json()\n\n const items = options.deserialize ? deserialize(data) : data\n\n const { items: tree } = buildMenuTree(items)\n\n return {\n items,\n tree,\n }\n}\n\nfunction buildMenuTree(\n links: DrupalMenuItem[],\n parent: DrupalMenuItem[\"id\"] = \"\"\n) {\n if (!links?.length) {\n return {\n items: [],\n }\n }\n\n const children = links.filter((link) => link.parent === parent)\n\n return children.length\n ? {\n items: children.map((link) => ({\n ...link,\n ...buildMenuTree(links, link.id),\n })),\n }\n : {}\n}\n"],"mappings":"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","names":["NodeCache","data","error"]}