import memory from 'unstorage/drivers/memory'; import { prefixStorage, createStorage } from 'unstorage'; import { m as useNuxtApp, u as useRuntimeConfig } from '../server.mjs'; import { withBase } from 'ufo'; import { c as createQuery, g as get, a as assertArray, b as ensureArray, s as sortList, d as apply, w as withoutKeys, f as withKeys } from './query-e0164f92.mjs'; import { pascalCase } from 'scule'; import { u as useContentPreview } from './preview-38d6e135.mjs'; import 'vue'; import 'ofetch'; import 'hookable'; import 'unctx'; import 'h3'; import '@unhead/ssr'; import 'unhead'; import '@unhead/shared'; import 'vue-router'; import '@intlify/core-base'; import 'cookie-es'; import 'is-https'; import 'anu-vue'; import 'vue/server-renderer'; import 'defu'; import '../../nitro/node-server.mjs'; import 'node-fetch-native/polyfill'; import 'node:http'; import 'node:https'; import 'destr'; import 'unenv/runtime/fetch/index'; import 'klona'; import 'ohash'; import 'unstorage/drivers/fs'; import 'unstorage/drivers/overlay'; import 'radix3'; import 'node:fs'; import 'node:url'; import 'pathe'; import '@intlify/bundle-utils'; import 'unified'; import 'mdast-util-to-string'; import 'micromark/lib/preprocess.js'; import 'micromark/lib/postprocess.js'; import 'unist-util-stringify-position'; import 'micromark-util-character'; import 'micromark-util-chunked'; import 'micromark-util-resolve-all'; import 'remark-emoji'; import 'rehype-slug'; import 'remark-squeeze-paragraphs'; import 'rehype-external-links'; import 'remark-gfm'; import 'rehype-sort-attribute-values'; import 'rehype-sort-attributes'; import 'rehype-raw'; import 'remark-mdc'; import 'remark-parse'; import 'remark-rehype'; import 'mdast-util-to-hast'; import 'detab'; import 'unist-builder'; import 'mdurl'; import 'slugify'; import 'unist-util-position'; import 'unist-util-visit'; import 'shiki-es'; import 'unenv/runtime/npm/consola'; import './utils-6d756e03.mjs'; function createMatch(opts = {}) { const operators = createOperators(match, opts.operators); function match(item, conditions) { if (typeof conditions !== "object" || conditions instanceof RegExp) { return operators.$eq(item, conditions); } return Object.keys(conditions || {}).every((key) => { const condition = conditions[key]; if (key.startsWith("$") && operators[key]) { const fn = operators[key]; return typeof fn === "function" ? fn(item, condition) : false; } return match(get(item, key), condition); }); } return match; } function createOperators(match, operators = {}) { return { $match: (item, condition) => match(item, condition), /** * Match if item equals condition **/ $eq: (item, condition) => condition instanceof RegExp ? condition.test(item) : item === condition, /** * Match if item not equals condition **/ $ne: (item, condition) => condition instanceof RegExp ? !condition.test(item) : item !== condition, /** * Match is condition is false **/ $not: (item, condition) => !match(item, condition), /** * Match only if all of nested conditions are true **/ $and: (item, condition) => { assertArray(condition, "$and requires an array as condition"); return condition.every((cond) => match(item, cond)); }, /** * Match if any of nested conditions is true **/ $or: (item, condition) => { assertArray(condition, "$or requires an array as condition"); return condition.some((cond) => match(item, cond)); }, /** * Match if item is in condition array **/ $in: (item, condition) => ensureArray(condition).some( (cond) => Array.isArray(item) ? match(item, { $contains: cond }) : match(item, cond) ), /** * Match if item contains every condition or math every rule in condition array **/ $contains: (item, condition) => { item = Array.isArray(item) ? item : String(item); return ensureArray(condition).every((i) => item.includes(i)); }, /** * Ignore case contains **/ $icontains: (item, condition) => { if (typeof condition !== "string") { throw new TypeError("$icontains requires a string, use $contains instead"); } item = String(item).toLocaleLowerCase(); return ensureArray(condition).every((i) => item.includes(i.toLocaleLowerCase())); }, /** * Match if item contains at least one rule from condition array */ $containsAny: (item, condition) => { assertArray(condition, "$containsAny requires an array as condition"); item = Array.isArray(item) ? item : String(item); return condition.some((i) => item.includes(i)); }, /** * Check key existence */ $exists: (item, condition) => condition ? typeof item !== "undefined" : typeof item === "undefined", /** * Match if type of item equals condition */ $type: (item, condition) => typeof item === String(condition), /** * Provides regular expression capabilities for pattern matching strings. */ $regex: (item, condition) => { if (!(condition instanceof RegExp)) { const matched = String(condition).match(/\/(.*)\/([dgimsuy]*)$/); condition = matched ? new RegExp(matched[1], matched[2] || "") : new RegExp(condition); } return condition.test(String(item || "")); }, /** * Check if item is less than condition */ $lt: (item, condition) => { return item < condition; }, /** * Check if item is less than or equal to condition */ $lte: (item, condition) => { return item <= condition; }, /** * Check if item is greater than condition */ $gt: (item, condition) => { return item > condition; }, /** * Check if item is greater than or equal to condition */ $gte: (item, condition) => { return item >= condition; }, ...operators || {} }; } function createPipelineFetcher(getContentsList) { const match = createMatch(); const surround = (data, { query, before, after }) => { const matchQuery = typeof query === "string" ? { _path: query } : query; const index = data.findIndex((item) => match(item, matchQuery)); before = before ?? 1; after = after ?? 1; const slice = new Array(before + after).fill(null, 0); return index === -1 ? slice : slice.map((_, i) => data[index - before + i + Number(i >= before)] || null); }; const pipelines = [ // Conditions (data, params) => data.filter((item) => ensureArray(params.where).every((matchQuery) => match(item, matchQuery))), // Sort data (data, params) => ensureArray(params.sort).forEach((options) => sortList(data, options)), // Surround logic (data, params) => params.surround ? surround(data, params.surround) : data, // Skip first items (data, params) => params.skip ? data.slice(params.skip) : data, // Pick first items (data, params) => params.limit ? data.slice(0, params.limit) : data, // Remove unwanted fields (data, params) => apply(withoutKeys(params.without))(data), // Select only wanted fields (data, params) => apply(withKeys(params.only))(data) ]; return async (query) => { const data = await getContentsList(); const params = query.params(); const filteredData = pipelines.reduce(($data, pipe) => pipe($data, params) || $data, data); if (params.first) { return filteredData[0]; } return filteredData; }; } const generateTitle = (path) => path.split(/[\s-]/g).map(pascalCase).join(" "); function createNav(contents, configs) { const { navigation } = useRuntimeConfig().public.content; const pickNavigationFields = (content) => ({ ...pick(["title", ...navigation.fields])(content), ...isObject(content == null ? void 0 : content.navigation) ? content.navigation : {} }); const nav = contents.sort((a, b) => a._path.localeCompare(b._path)).reduce((nav2, content) => { const parts = content._path.substring(1).split("/"); const idParts = content._id.split(":").slice(1); const isIndex = !!idParts[idParts.length - 1].match(/([1-9][0-9]*\.)?index.md/g); const getNavItem = (content2) => ({ title: content2.title, _path: content2._path, _file: content2._file, children: [], ...pickNavigationFields(content2), ...content2._draft ? { _draft: true } : {} }); const navItem = getNavItem(content); if (isIndex) { const dirConfig = configs[navItem._path]; if (typeof (dirConfig == null ? void 0 : dirConfig.navigation) !== "undefined" && !(dirConfig == null ? void 0 : dirConfig.navigation)) { return nav2; } if (content._path !== "/") { const indexItem = getNavItem(content); navItem.children.push(indexItem); } Object.assign( navItem, pickNavigationFields(dirConfig) ); } if (parts.length === 1) { nav2.push(navItem); return nav2; } const siblings = parts.slice(0, -1).reduce((nodes, part, i) => { const currentPathPart = "/" + parts.slice(0, i + 1).join("/"); const conf = configs[currentPathPart]; if (typeof (conf == null ? void 0 : conf.navigation) !== "undefined" && !conf.navigation) { return []; } let parent = nodes.find((n) => n._path === currentPathPart); if (!parent) { parent = { title: generateTitle(part), _path: currentPathPart, _file: content._file, children: [], ...pickNavigationFields(conf) }; nodes.push(parent); } return parent.children; }, nav2); siblings.push(navItem); return nav2; }, []); return sortAndClear(nav); } const collator = new Intl.Collator(void 0, { numeric: true, sensitivity: "base" }); function sortAndClear(nav) { var _a; const sorted = nav.sort((a, b) => collator.compare(a._file, b._file)); for (const item of sorted) { if ((_a = item.children) == null ? void 0 : _a.length) { sortAndClear(item.children); } else { delete item.children; } delete item._file; } return nav; } function pick(keys) { return (obj) => { obj = obj || {}; if (keys && keys.length) { return keys.filter((key) => typeof obj[key] !== "undefined").reduce((newObj, key) => Object.assign(newObj, { [key]: obj[key] }), {}); } return obj; }; } function isObject(obj) { return Object.prototype.toString.call(obj) === "[object Object]"; } const withContentBase = (url) => withBase(url, useRuntimeConfig().public.content.api.baseURL); const contentStorage = prefixStorage(createStorage({ driver: memory() }), "@content"); function createDB(storage) { async function getItems() { const keys = new Set(await storage.getKeys("cache:")); const previewToken = useContentPreview().getPreviewToken(); if (previewToken) { const previewMeta = await storage.getItem(`${previewToken}$`).then((data) => data || {}); if (Array.isArray(previewMeta.ignoreSources)) { const sources = previewMeta.ignoreSources.map((s) => `cache:${s.trim()}:`); for (const key of keys) { if (sources.some((s) => key.startsWith(s))) { keys.delete(key); } } } const previewKeys = await storage.getKeys(`${previewToken}:`); const previewContents = await Promise.all(previewKeys.map((key) => storage.getItem(key))); for (const pItem of previewContents) { keys.delete(`cache:${pItem._id}`); if (!pItem.__deleted) { keys.add(`${previewToken}:${pItem._id}`); } } } const items = await Promise.all(Array.from(keys).map((key) => storage.getItem(key))); return items; } return { storage, fetch: createPipelineFetcher(getItems), query: (query) => createQuery(createPipelineFetcher(getItems), query) }; } let contentDatabase = null; let contentDatabaseInitPromise = null; async function useContentDatabase() { if (contentDatabaseInitPromise) { await contentDatabaseInitPromise; } else if (!contentDatabase) { contentDatabaseInitPromise = initContentDatabase(); contentDatabase = await contentDatabaseInitPromise; } return contentDatabase; } async function initContentDatabase() { const nuxtApp = useNuxtApp(); const { content } = useRuntimeConfig().public; const _contentDatabase = createDB(contentStorage); const integrity = await _contentDatabase.storage.getItem("integrity"); if (content.integrity !== +(integrity || 0)) { const { contents, navigation } = await $fetch(withContentBase(content.integrity ? `cache.${content.integrity}.json` : "cache.json")); await Promise.all( contents.map((content2) => _contentDatabase.storage.setItem(`cache:${content2._id}`, content2)) ); await _contentDatabase.storage.setItem("navigation", navigation); await _contentDatabase.storage.setItem("integrity", content.integrity); } await nuxtApp.callHook("content:storage", _contentDatabase.storage); return _contentDatabase; } async function generateNavigation(query) { const db = await useContentDatabase(); if (!useContentPreview().getPreviewToken() && Object.keys(query || {}).length === 0) { return db.storage.getItem("navigation"); } const contents = await db.query(query).where({ /** * Partial contents are not included in the navigation * A partial content is a content that has `_` prefix in its path */ _partial: false, /** * Exclude any pages which have opted out of navigation via frontmatter. */ navigation: { $ne: false } }).find(); const dirConfigs = await db.query().where({ _path: /\/_dir$/i, _partial: true }).find(); const configs = dirConfigs.reduce((configs2, conf) => { var _a; if (((_a = conf.title) == null ? void 0 : _a.toLowerCase()) === "dir") { conf.title = void 0; } const key = conf._path.split("/").slice(0, -1).join("/") || "/"; configs2[key] = { ...conf, // Extract meta from body. (non MD files) ...conf.body }; return configs2; }, {}); return createNav(contents, configs); } export { contentStorage, createDB, generateNavigation, useContentDatabase }; //# sourceMappingURL=client-db-d3e6e918.mjs.map