@ztl-uwu/nuxt-content 2.13.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/LICENSE +21 -0
- package/README.md +64 -0
- package/dist/module.d.mts +1176 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +696 -0
- package/dist/runtime/app.vue +3 -0
- package/dist/runtime/app.vue.d.ts +2 -0
- package/dist/runtime/components/ContentDoc.vue +108 -0
- package/dist/runtime/components/ContentDoc.vue.d.ts +118 -0
- package/dist/runtime/components/ContentList.vue +59 -0
- package/dist/runtime/components/ContentList.vue.d.ts +59 -0
- package/dist/runtime/components/ContentNavigation.vue +61 -0
- package/dist/runtime/components/ContentNavigation.vue.d.ts +35 -0
- package/dist/runtime/components/ContentQuery.vue +212 -0
- package/dist/runtime/components/ContentQuery.vue.d.ts +0 -0
- package/dist/runtime/components/ContentRenderer.vue +78 -0
- package/dist/runtime/components/ContentRenderer.vue.d.ts +56 -0
- package/dist/runtime/components/ContentRendererMarkdown.vue +69 -0
- package/dist/runtime/components/ContentRendererMarkdown.vue.d.ts +73 -0
- package/dist/runtime/components/ContentSlot.vue +25 -0
- package/dist/runtime/components/ContentSlot.vue.d.ts +37 -0
- package/dist/runtime/components/DocumentDrivenEmpty.vue +18 -0
- package/dist/runtime/components/DocumentDrivenEmpty.vue.d.ts +17 -0
- package/dist/runtime/components/DocumentDrivenNotFound.vue +9 -0
- package/dist/runtime/components/DocumentDrivenNotFound.vue.d.ts +5 -0
- package/dist/runtime/components/Markdown.vue +29 -0
- package/dist/runtime/components/Markdown.vue.d.ts +31 -0
- package/dist/runtime/components/Prose/ProseCode.vue +32 -0
- package/dist/runtime/components/Prose/ProseCode.vue.d.ts +110 -0
- package/dist/runtime/components/Prose/ProseCodeInline.vue +3 -0
- package/dist/runtime/components/Prose/ProseCodeInline.vue.d.ts +14 -0
- package/dist/runtime/components/Prose/ProsePre.vue +42 -0
- package/dist/runtime/components/Prose/ProsePre.vue.d.ts +146 -0
- package/dist/runtime/composables/client-db.d.ts +14 -0
- package/dist/runtime/composables/client-db.js +105 -0
- package/dist/runtime/composables/content.d.ts +19 -0
- package/dist/runtime/composables/content.js +41 -0
- package/dist/runtime/composables/head.d.ts +4 -0
- package/dist/runtime/composables/head.js +94 -0
- package/dist/runtime/composables/helpers.d.ts +7 -0
- package/dist/runtime/composables/helpers.js +66 -0
- package/dist/runtime/composables/navigation.d.ts +2 -0
- package/dist/runtime/composables/navigation.js +34 -0
- package/dist/runtime/composables/preview.d.ts +5 -0
- package/dist/runtime/composables/preview.js +41 -0
- package/dist/runtime/composables/query.d.ts +10 -0
- package/dist/runtime/composables/query.js +64 -0
- package/dist/runtime/composables/search.d.ts +130 -0
- package/dist/runtime/composables/search.js +59 -0
- package/dist/runtime/composables/useUnwrap.d.ts +5 -0
- package/dist/runtime/composables/useUnwrap.js +5 -0
- package/dist/runtime/composables/utils.d.ts +6 -0
- package/dist/runtime/composables/utils.js +36 -0
- package/dist/runtime/composables/web-socket.d.ts +3 -0
- package/dist/runtime/composables/web-socket.js +65 -0
- package/dist/runtime/legacy/composables/client-db.d.ts +12 -0
- package/dist/runtime/legacy/composables/client-db.js +105 -0
- package/dist/runtime/legacy/composables/navigation.d.ts +2 -0
- package/dist/runtime/legacy/composables/navigation.js +34 -0
- package/dist/runtime/legacy/composables/query.d.ts +10 -0
- package/dist/runtime/legacy/composables/query.js +61 -0
- package/dist/runtime/legacy/plugins/documentDriven.d.ts +2 -0
- package/dist/runtime/legacy/plugins/documentDriven.js +231 -0
- package/dist/runtime/legacy/server.d.ts +3 -0
- package/dist/runtime/legacy/server.js +3 -0
- package/dist/runtime/legacy/types.d.ts +5 -0
- package/dist/runtime/pages/document-driven.vue +27 -0
- package/dist/runtime/pages/document-driven.vue.d.ts +2 -0
- package/dist/runtime/plugins/documentDriven.d.ts +2 -0
- package/dist/runtime/plugins/documentDriven.js +222 -0
- package/dist/runtime/plugins/ws.d.ts +2 -0
- package/dist/runtime/plugins/ws.js +7 -0
- package/dist/runtime/query/match/index.d.ts +6 -0
- package/dist/runtime/query/match/index.js +123 -0
- package/dist/runtime/query/match/pipeline-legacy.d.ts +2 -0
- package/dist/runtime/query/match/pipeline-legacy.js +22 -0
- package/dist/runtime/query/match/pipeline.d.ts +2 -0
- package/dist/runtime/query/match/pipeline.js +104 -0
- package/dist/runtime/query/match/utils.d.ts +35 -0
- package/dist/runtime/query/match/utils.js +65 -0
- package/dist/runtime/query/query.d.ts +12 -0
- package/dist/runtime/query/query.js +61 -0
- package/dist/runtime/server/api/cache.d.ts +7 -0
- package/dist/runtime/server/api/cache.js +18 -0
- package/dist/runtime/server/api/navigation-qid-params.d.ts +1 -0
- package/dist/runtime/server/api/navigation-qid-params.js +1 -0
- package/dist/runtime/server/api/navigation-qid.d.ts +1 -0
- package/dist/runtime/server/api/navigation-qid.js +1 -0
- package/dist/runtime/server/api/navigation.d.ts +2 -0
- package/dist/runtime/server/api/navigation.js +42 -0
- package/dist/runtime/server/api/query-qid-params.d.ts +1 -0
- package/dist/runtime/server/api/query-qid-params.js +1 -0
- package/dist/runtime/server/api/query-qid.d.ts +1 -0
- package/dist/runtime/server/api/query-qid.js +1 -0
- package/dist/runtime/server/api/query.d.ts +2 -0
- package/dist/runtime/server/api/query.js +32 -0
- package/dist/runtime/server/api/search.d.ts +8 -0
- package/dist/runtime/server/api/search.js +16 -0
- package/dist/runtime/server/content-index.d.ts +4 -0
- package/dist/runtime/server/content-index.js +37 -0
- package/dist/runtime/server/index.d.ts +1 -0
- package/dist/runtime/server/index.js +1 -0
- package/dist/runtime/server/navigation.d.ts +5 -0
- package/dist/runtime/server/navigation.js +96 -0
- package/dist/runtime/server/plugins/refresh-cache.d.ts +2 -0
- package/dist/runtime/server/plugins/refresh-cache.js +15 -0
- package/dist/runtime/server/preview.d.ts +5 -0
- package/dist/runtime/server/preview.js +9 -0
- package/dist/runtime/server/search.d.ts +14 -0
- package/dist/runtime/server/search.js +70 -0
- package/dist/runtime/server/storage.d.ts +35 -0
- package/dist/runtime/server/storage.js +238 -0
- package/dist/runtime/transformers/component-resolver.d.ts +2 -0
- package/dist/runtime/transformers/component-resolver.js +44 -0
- package/dist/runtime/transformers/csv/create-tokenizer.d.ts +39 -0
- package/dist/runtime/transformers/csv/create-tokenizer.js +307 -0
- package/dist/runtime/transformers/csv/from-csv.d.ts +13 -0
- package/dist/runtime/transformers/csv/from-csv.js +203 -0
- package/dist/runtime/transformers/csv/index.d.ts +2 -0
- package/dist/runtime/transformers/csv/index.js +50 -0
- package/dist/runtime/transformers/csv/parser.d.ts +24 -0
- package/dist/runtime/transformers/csv/parser.js +154 -0
- package/dist/runtime/transformers/index.d.ts +7 -0
- package/dist/runtime/transformers/index.js +50 -0
- package/dist/runtime/transformers/json.d.ts +2 -0
- package/dist/runtime/transformers/json.js +29 -0
- package/dist/runtime/transformers/markdown.d.ts +2 -0
- package/dist/runtime/transformers/markdown.js +88 -0
- package/dist/runtime/transformers/path-meta.d.ts +27 -0
- package/dist/runtime/transformers/path-meta.js +59 -0
- package/dist/runtime/transformers/utils.d.ts +3 -0
- package/dist/runtime/transformers/utils.js +12 -0
- package/dist/runtime/transformers/yaml.d.ts +2 -0
- package/dist/runtime/transformers/yaml.js +21 -0
- package/dist/runtime/utils/config.d.ts +4 -0
- package/dist/runtime/utils/config.js +7 -0
- package/dist/runtime/utils/html-tags.d.ts +2 -0
- package/dist/runtime/utils/html-tags.js +119 -0
- package/dist/runtime/utils/json.d.ts +10 -0
- package/dist/runtime/utils/json.js +20 -0
- package/dist/runtime/utils/query.d.ts +5 -0
- package/dist/runtime/utils/query.js +77 -0
- package/dist/runtime/virtual/transformers.d.ts +2 -0
- package/dist/types.d.mts +9 -0
- package/dist/web-types.json +572 -0
- package/package.json +111 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { type Options as MiniSearchOptions } from 'minisearch';
|
|
2
|
+
import { type MaybeRefOrGetter, type Ref } from '#imports';
|
|
3
|
+
export declare const defineMiniSearchOptions: <DataItem>(options: MiniSearchOptions<DataItem>) => Ref<{
|
|
4
|
+
fields: string[];
|
|
5
|
+
idField?: string | undefined;
|
|
6
|
+
storeFields?: string[] | undefined;
|
|
7
|
+
extractField?: ((document: DataItem, fieldName: string) => string) | undefined;
|
|
8
|
+
tokenize?: ((text: string, fieldName?: string) => string[]) | undefined;
|
|
9
|
+
processTerm?: ((term: string, fieldName?: string) => string | string[] | null | undefined | false) | undefined;
|
|
10
|
+
logger?: ((level: "error" | "debug" | "info" | "warn", message: string, code?: string) => void) | undefined;
|
|
11
|
+
autoVacuum?: boolean | {
|
|
12
|
+
batchSize?: number | undefined;
|
|
13
|
+
batchWait?: number | undefined;
|
|
14
|
+
minDirtCount?: number | undefined;
|
|
15
|
+
minDirtFactor?: number | undefined;
|
|
16
|
+
} | undefined;
|
|
17
|
+
searchOptions?: {
|
|
18
|
+
fields?: string[] | undefined;
|
|
19
|
+
filter?: ((result: import("minisearch").SearchResult) => boolean) | undefined;
|
|
20
|
+
boost?: {
|
|
21
|
+
[fieldName: string]: number;
|
|
22
|
+
} | undefined;
|
|
23
|
+
boostTerm?: ((term: string, i: number, terms: string[]) => number) | undefined;
|
|
24
|
+
weights?: {
|
|
25
|
+
fuzzy: number;
|
|
26
|
+
prefix: number;
|
|
27
|
+
} | undefined;
|
|
28
|
+
boostDocument?: ((documentId: any, term: string, storedFields?: Record<string, unknown>) => number) | undefined;
|
|
29
|
+
prefix?: boolean | ((term: string, index: number, terms: string[]) => boolean) | undefined;
|
|
30
|
+
fuzzy?: boolean | number | ((term: string, index: number, terms: string[]) => boolean | number) | undefined;
|
|
31
|
+
maxFuzzy?: number | undefined;
|
|
32
|
+
combineWith?: import("minisearch").CombinationOperator | undefined;
|
|
33
|
+
tokenize?: ((text: string) => string[]) | undefined;
|
|
34
|
+
processTerm?: ((term: string) => string | string[] | null | undefined | false) | undefined;
|
|
35
|
+
bm25?: {
|
|
36
|
+
k: number;
|
|
37
|
+
b: number;
|
|
38
|
+
d: number;
|
|
39
|
+
} | undefined;
|
|
40
|
+
} | undefined;
|
|
41
|
+
autoSuggestOptions?: {
|
|
42
|
+
fields?: string[] | undefined;
|
|
43
|
+
filter?: ((result: import("minisearch").SearchResult) => boolean) | undefined;
|
|
44
|
+
boost?: {
|
|
45
|
+
[fieldName: string]: number;
|
|
46
|
+
} | undefined;
|
|
47
|
+
boostTerm?: ((term: string, i: number, terms: string[]) => number) | undefined;
|
|
48
|
+
weights?: {
|
|
49
|
+
fuzzy: number;
|
|
50
|
+
prefix: number;
|
|
51
|
+
} | undefined;
|
|
52
|
+
boostDocument?: ((documentId: any, term: string, storedFields?: Record<string, unknown>) => number) | undefined;
|
|
53
|
+
prefix?: boolean | ((term: string, index: number, terms: string[]) => boolean) | undefined;
|
|
54
|
+
fuzzy?: boolean | number | ((term: string, index: number, terms: string[]) => boolean | number) | undefined;
|
|
55
|
+
maxFuzzy?: number | undefined;
|
|
56
|
+
combineWith?: import("minisearch").CombinationOperator | undefined;
|
|
57
|
+
tokenize?: ((text: string) => string[]) | undefined;
|
|
58
|
+
processTerm?: ((term: string) => string | string[] | null | undefined | false) | undefined;
|
|
59
|
+
bm25?: {
|
|
60
|
+
k: number;
|
|
61
|
+
b: number;
|
|
62
|
+
d: number;
|
|
63
|
+
} | undefined;
|
|
64
|
+
} | undefined;
|
|
65
|
+
}, MiniSearchOptions<DataItem> | {
|
|
66
|
+
fields: string[];
|
|
67
|
+
idField?: string | undefined;
|
|
68
|
+
storeFields?: string[] | undefined;
|
|
69
|
+
extractField?: ((document: DataItem, fieldName: string) => string) | undefined;
|
|
70
|
+
tokenize?: ((text: string, fieldName?: string) => string[]) | undefined;
|
|
71
|
+
processTerm?: ((term: string, fieldName?: string) => string | string[] | null | undefined | false) | undefined;
|
|
72
|
+
logger?: ((level: "error" | "debug" | "info" | "warn", message: string, code?: string) => void) | undefined;
|
|
73
|
+
autoVacuum?: boolean | {
|
|
74
|
+
batchSize?: number | undefined;
|
|
75
|
+
batchWait?: number | undefined;
|
|
76
|
+
minDirtCount?: number | undefined;
|
|
77
|
+
minDirtFactor?: number | undefined;
|
|
78
|
+
} | undefined;
|
|
79
|
+
searchOptions?: {
|
|
80
|
+
fields?: string[] | undefined;
|
|
81
|
+
filter?: ((result: import("minisearch").SearchResult) => boolean) | undefined;
|
|
82
|
+
boost?: {
|
|
83
|
+
[fieldName: string]: number;
|
|
84
|
+
} | undefined;
|
|
85
|
+
boostTerm?: ((term: string, i: number, terms: string[]) => number) | undefined;
|
|
86
|
+
weights?: {
|
|
87
|
+
fuzzy: number;
|
|
88
|
+
prefix: number;
|
|
89
|
+
} | undefined;
|
|
90
|
+
boostDocument?: ((documentId: any, term: string, storedFields?: Record<string, unknown>) => number) | undefined;
|
|
91
|
+
prefix?: boolean | ((term: string, index: number, terms: string[]) => boolean) | undefined;
|
|
92
|
+
fuzzy?: boolean | number | ((term: string, index: number, terms: string[]) => boolean | number) | undefined;
|
|
93
|
+
maxFuzzy?: number | undefined;
|
|
94
|
+
combineWith?: import("minisearch").CombinationOperator | undefined;
|
|
95
|
+
tokenize?: ((text: string) => string[]) | undefined;
|
|
96
|
+
processTerm?: ((term: string) => string | string[] | null | undefined | false) | undefined;
|
|
97
|
+
bm25?: {
|
|
98
|
+
k: number;
|
|
99
|
+
b: number;
|
|
100
|
+
d: number;
|
|
101
|
+
} | undefined;
|
|
102
|
+
} | undefined;
|
|
103
|
+
autoSuggestOptions?: {
|
|
104
|
+
fields?: string[] | undefined;
|
|
105
|
+
filter?: ((result: import("minisearch").SearchResult) => boolean) | undefined;
|
|
106
|
+
boost?: {
|
|
107
|
+
[fieldName: string]: number;
|
|
108
|
+
} | undefined;
|
|
109
|
+
boostTerm?: ((term: string, i: number, terms: string[]) => number) | undefined;
|
|
110
|
+
weights?: {
|
|
111
|
+
fuzzy: number;
|
|
112
|
+
prefix: number;
|
|
113
|
+
} | undefined;
|
|
114
|
+
boostDocument?: ((documentId: any, term: string, storedFields?: Record<string, unknown>) => number) | undefined;
|
|
115
|
+
prefix?: boolean | ((term: string, index: number, terms: string[]) => boolean) | undefined;
|
|
116
|
+
fuzzy?: boolean | number | ((term: string, index: number, terms: string[]) => boolean | number) | undefined;
|
|
117
|
+
maxFuzzy?: number | undefined;
|
|
118
|
+
combineWith?: import("minisearch").CombinationOperator | undefined;
|
|
119
|
+
tokenize?: ((text: string) => string[]) | undefined;
|
|
120
|
+
processTerm?: ((term: string) => string | string[] | null | undefined | false) | undefined;
|
|
121
|
+
bm25?: {
|
|
122
|
+
k: number;
|
|
123
|
+
b: number;
|
|
124
|
+
d: number;
|
|
125
|
+
} | undefined;
|
|
126
|
+
} | undefined;
|
|
127
|
+
}>;
|
|
128
|
+
export declare const searchContent: <DataItem>(search: MaybeRefOrGetter<string>, options?: {
|
|
129
|
+
miniSearch?: MaybeRefOrGetter<MiniSearchOptions<DataItem>>;
|
|
130
|
+
}) => Promise<import("vue").ComputedRef<import("minisearch").SearchResult[]>>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createError } from "h3";
|
|
2
|
+
import MiniSearch from "minisearch";
|
|
3
|
+
import { useRuntimeConfig, useFetch, ref, computed, toValue } from "#imports";
|
|
4
|
+
export const defineMiniSearchOptions = (options) => {
|
|
5
|
+
return ref(options);
|
|
6
|
+
};
|
|
7
|
+
export const searchContent = async (search, options = {}) => {
|
|
8
|
+
const runtimeConfig = useRuntimeConfig();
|
|
9
|
+
const { content } = runtimeConfig.public;
|
|
10
|
+
const { integrity, api: { baseURL: baseAPI }, search: searchOptions } = content;
|
|
11
|
+
const { indexed: useIndexedSearch } = searchOptions || {};
|
|
12
|
+
const searchRoute = `${baseAPI}/search${integrity ? "-" + integrity : ""}`;
|
|
13
|
+
if (useIndexedSearch) {
|
|
14
|
+
const { options: miniSearchOptions } = searchOptions || {};
|
|
15
|
+
const { data: data2 } = await useFetch(searchRoute, { responseType: "text" });
|
|
16
|
+
if (!data2.value) {
|
|
17
|
+
throw createError({
|
|
18
|
+
statusCode: 500,
|
|
19
|
+
message: "Missing search data"
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const results2 = useIndexedMiniSearch(search, data2, miniSearchOptions);
|
|
23
|
+
return results2;
|
|
24
|
+
}
|
|
25
|
+
if (!options.miniSearch) {
|
|
26
|
+
throw createError({
|
|
27
|
+
statusCode: 500,
|
|
28
|
+
message: "Missing miniSearch options"
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const { data } = await useFetch(searchRoute);
|
|
32
|
+
if (!data.value) {
|
|
33
|
+
throw createError({
|
|
34
|
+
statusCode: 500,
|
|
35
|
+
message: "Missing search data"
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const results = useMiniSearch(search, data, options.miniSearch);
|
|
39
|
+
return results;
|
|
40
|
+
};
|
|
41
|
+
const useIndexedMiniSearch = (search, indexedData, options) => {
|
|
42
|
+
const indexedMiniSearch = computed(() => {
|
|
43
|
+
return MiniSearch.loadJSON(toValue(indexedData), toValue(options));
|
|
44
|
+
});
|
|
45
|
+
const results = computed(() => {
|
|
46
|
+
return indexedMiniSearch.value.search(toValue(search));
|
|
47
|
+
});
|
|
48
|
+
return results;
|
|
49
|
+
};
|
|
50
|
+
const useMiniSearch = function(search, data, options) {
|
|
51
|
+
const miniSearch = computed(() => {
|
|
52
|
+
return new MiniSearch(toValue(options));
|
|
53
|
+
});
|
|
54
|
+
miniSearch.value.addAll(toValue(data));
|
|
55
|
+
const results = computed(() => {
|
|
56
|
+
return miniSearch.value.search(toValue(search));
|
|
57
|
+
});
|
|
58
|
+
return results;
|
|
59
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { useContent } from './content';
|
|
2
|
+
export declare const withContentBase: (url: string) => string;
|
|
3
|
+
export declare const useContentDisabled: () => ReturnType<typeof useContent>;
|
|
4
|
+
export declare const navigationDisabled: () => never;
|
|
5
|
+
export declare const addPrerenderPath: (path: string) => void;
|
|
6
|
+
export declare const shouldUseClientDB: () => boolean;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { withBase } from "ufo";
|
|
2
|
+
import { useContentPreview } from "./preview.js";
|
|
3
|
+
import { useRuntimeConfig, useRequestEvent } from "#imports";
|
|
4
|
+
export const withContentBase = (url) => withBase(url, useRuntimeConfig().public.content.api.baseURL);
|
|
5
|
+
export const useContentDisabled = () => {
|
|
6
|
+
console.warn("useContent is only accessible when you are using `documentDriven` mode.");
|
|
7
|
+
console.warn("Learn more by visiting: https://content.nuxt.com/document-driven");
|
|
8
|
+
throw new Error("useContent is only accessible when you are using `documentDriven` mode.");
|
|
9
|
+
};
|
|
10
|
+
export const navigationDisabled = () => {
|
|
11
|
+
console.warn("Navigation is only accessible when you enable it in module options.");
|
|
12
|
+
console.warn("Learn more by visiting: https://content.nuxt.com/get-started/configuration#navigation");
|
|
13
|
+
throw new Error("Navigation is only accessible when you enable it in module options.");
|
|
14
|
+
};
|
|
15
|
+
export const addPrerenderPath = (path) => {
|
|
16
|
+
const event = useRequestEvent();
|
|
17
|
+
if (event) {
|
|
18
|
+
event.node.res.setHeader(
|
|
19
|
+
"x-nitro-prerender",
|
|
20
|
+
[
|
|
21
|
+
event.node.res.getHeader("x-nitro-prerender"),
|
|
22
|
+
path
|
|
23
|
+
].filter(Boolean).join(",")
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export const shouldUseClientDB = () => {
|
|
28
|
+
const { experimental } = useRuntimeConfig().public.content;
|
|
29
|
+
if (import.meta.server) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (experimental.clientDB) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
return useContentPreview().isEnabled();
|
|
36
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useRuntimeConfig, refreshNuxtData } from "#imports";
|
|
2
|
+
const logger = {
|
|
3
|
+
log: (...args) => console.log("[Content]", ...args),
|
|
4
|
+
warn: (...args) => console.warn("[Content]", ...args)
|
|
5
|
+
};
|
|
6
|
+
let ws;
|
|
7
|
+
export function useContentWebSocket() {
|
|
8
|
+
if (!window.WebSocket) {
|
|
9
|
+
logger.warn("Could not enable hot reload, your browser does not support WebSocket.");
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const onMessage = (message) => {
|
|
13
|
+
try {
|
|
14
|
+
const data = JSON.parse(message.data);
|
|
15
|
+
if (!data) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
refreshNuxtData();
|
|
19
|
+
} catch {
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const onOpen = () => logger.log("WS connected!");
|
|
23
|
+
const onError = (e) => {
|
|
24
|
+
switch (e.code) {
|
|
25
|
+
case "ECONNREFUSED":
|
|
26
|
+
connect(true);
|
|
27
|
+
break;
|
|
28
|
+
default:
|
|
29
|
+
logger.warn("WS Error:", e);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const onClose = (e) => {
|
|
34
|
+
if (e.code === 1e3 || e.code === 1005) {
|
|
35
|
+
logger.log("WS closed!");
|
|
36
|
+
} else {
|
|
37
|
+
connect(true);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const connect = (retry = false) => {
|
|
41
|
+
if (retry) {
|
|
42
|
+
logger.log("WS reconnecting..");
|
|
43
|
+
setTimeout(connect, 1e3);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (ws) {
|
|
47
|
+
try {
|
|
48
|
+
ws.close();
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
ws = void 0;
|
|
52
|
+
}
|
|
53
|
+
const wsURL = `${useRuntimeConfig().public.content.wsUrl}ws`;
|
|
54
|
+
logger.log(`WS connect to ${wsURL}`);
|
|
55
|
+
ws = new WebSocket(wsURL);
|
|
56
|
+
ws.onopen = onOpen;
|
|
57
|
+
ws.onmessage = onMessage;
|
|
58
|
+
ws.onerror = onError;
|
|
59
|
+
ws.onclose = onClose;
|
|
60
|
+
};
|
|
61
|
+
connect();
|
|
62
|
+
return {
|
|
63
|
+
connect
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Storage } from 'unstorage';
|
|
2
|
+
import type { NavItem, ParsedContent, QueryBuilder, QueryBuilderParams } from '@nuxt/content';
|
|
3
|
+
export declare const contentStorage: Storage;
|
|
4
|
+
interface ClientDB {
|
|
5
|
+
storage: Storage;
|
|
6
|
+
fetch: (query: QueryBuilder<ParsedContent>) => Promise<ParsedContent | ParsedContent[]>;
|
|
7
|
+
query: (query?: QueryBuilderParams) => QueryBuilder<ParsedContent>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createDB(storage: Storage): ClientDB;
|
|
10
|
+
export declare function useContentDatabase(): Promise<ClientDB>;
|
|
11
|
+
export declare function generateNavigation(query?: QueryBuilderParams): Promise<Array<NavItem>>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import memoryDriver from "unstorage/drivers/memory";
|
|
2
|
+
import { createStorage, prefixStorage } from "unstorage";
|
|
3
|
+
import { withBase } from "ufo";
|
|
4
|
+
import { createPipelineFetcherLegacy } from "../../query/match/pipeline-legacy.js";
|
|
5
|
+
import { createQuery } from "../../query/query.js";
|
|
6
|
+
import { createNav } from "../../server/navigation.js";
|
|
7
|
+
import { useContentPreview } from "../../composables/preview.js";
|
|
8
|
+
import { useRuntimeConfig, useNuxtApp } from "#imports";
|
|
9
|
+
const withContentBase = (url) => withBase(url, useRuntimeConfig().public.content.api.baseURL);
|
|
10
|
+
export const contentStorage = prefixStorage(createStorage({ driver: memoryDriver() }), "@content");
|
|
11
|
+
export function createDB(storage) {
|
|
12
|
+
async function getItems() {
|
|
13
|
+
const keys = new Set(await storage.getKeys("cache:"));
|
|
14
|
+
const previewToken = useContentPreview().getPreviewToken();
|
|
15
|
+
if (previewToken) {
|
|
16
|
+
const previewMeta = await storage.getItem(`${previewToken}$`).then((data) => data || {});
|
|
17
|
+
if (Array.isArray(previewMeta.ignoreSources)) {
|
|
18
|
+
const sources = previewMeta.ignoreSources.map((s) => `cache:${s.trim()}:`);
|
|
19
|
+
for (const key of keys) {
|
|
20
|
+
if (sources.some((s) => key.startsWith(s))) {
|
|
21
|
+
keys.delete(key);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const previewKeys = await storage.getKeys(`${previewToken}:`);
|
|
26
|
+
const previewContents = await Promise.all(previewKeys.map((key) => storage.getItem(key)));
|
|
27
|
+
for (const pItem of previewContents) {
|
|
28
|
+
keys.delete(`cache:${pItem._id}`);
|
|
29
|
+
if (!pItem.__deleted) {
|
|
30
|
+
keys.add(`${previewToken}:${pItem._id}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const items = await Promise.all(Array.from(keys).map((key) => storage.getItem(key)));
|
|
35
|
+
return items;
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
storage,
|
|
39
|
+
fetch: createPipelineFetcherLegacy(getItems),
|
|
40
|
+
query: (query) => createQuery(createPipelineFetcherLegacy(getItems), {
|
|
41
|
+
initialParams: query,
|
|
42
|
+
legacy: true
|
|
43
|
+
})
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
let contentDatabase = null;
|
|
47
|
+
let contentDatabaseInitPromise = null;
|
|
48
|
+
export async function useContentDatabase() {
|
|
49
|
+
if (contentDatabaseInitPromise) {
|
|
50
|
+
await contentDatabaseInitPromise;
|
|
51
|
+
} else if (!contentDatabase) {
|
|
52
|
+
contentDatabaseInitPromise = initContentDatabase();
|
|
53
|
+
contentDatabase = await contentDatabaseInitPromise;
|
|
54
|
+
}
|
|
55
|
+
return contentDatabase;
|
|
56
|
+
}
|
|
57
|
+
async function initContentDatabase() {
|
|
58
|
+
const nuxtApp = useNuxtApp();
|
|
59
|
+
const { content } = useRuntimeConfig().public;
|
|
60
|
+
const _contentDatabase = createDB(contentStorage);
|
|
61
|
+
const integrity = await _contentDatabase.storage.getItem("integrity");
|
|
62
|
+
if (content.integrity !== +(integrity || 0)) {
|
|
63
|
+
const { contents, navigation } = await $fetch(withContentBase(content.integrity ? `cache.${content.integrity}.json` : "cache.json"));
|
|
64
|
+
await Promise.all(
|
|
65
|
+
contents.map((content2) => _contentDatabase.storage.setItem(`cache:${content2._id}`, content2))
|
|
66
|
+
);
|
|
67
|
+
await _contentDatabase.storage.setItem("navigation", navigation);
|
|
68
|
+
await _contentDatabase.storage.setItem("integrity", content.integrity);
|
|
69
|
+
}
|
|
70
|
+
await nuxtApp.callHook("content:storage", _contentDatabase.storage);
|
|
71
|
+
return _contentDatabase;
|
|
72
|
+
}
|
|
73
|
+
export async function generateNavigation(query) {
|
|
74
|
+
const db = await useContentDatabase();
|
|
75
|
+
if (!useContentPreview().getPreviewToken() && Object.keys(query || {}).length === 0) {
|
|
76
|
+
return db.storage.getItem("navigation");
|
|
77
|
+
}
|
|
78
|
+
const contents = await db.query(query).where({
|
|
79
|
+
/**
|
|
80
|
+
* Partial contents are not included in the navigation
|
|
81
|
+
* A partial content is a content that has `_` prefix in its path
|
|
82
|
+
*/
|
|
83
|
+
_partial: false,
|
|
84
|
+
/**
|
|
85
|
+
* Exclude any pages which have opted out of navigation via frontmatter.
|
|
86
|
+
*/
|
|
87
|
+
navigation: {
|
|
88
|
+
$ne: false
|
|
89
|
+
}
|
|
90
|
+
}).find();
|
|
91
|
+
const dirConfigs = await db.query().where({ _path: /\/_dir$/i, _partial: true }).find();
|
|
92
|
+
const configs = dirConfigs.reduce((configs2, conf) => {
|
|
93
|
+
if (conf.title?.toLowerCase() === "dir") {
|
|
94
|
+
conf.title = void 0;
|
|
95
|
+
}
|
|
96
|
+
const key = conf._path.split("/").slice(0, -1).join("/") || "/";
|
|
97
|
+
configs2[key] = {
|
|
98
|
+
...conf,
|
|
99
|
+
// Extract meta from body. (non MD files)
|
|
100
|
+
...conf.body
|
|
101
|
+
};
|
|
102
|
+
return configs2;
|
|
103
|
+
}, {});
|
|
104
|
+
return createNav(contents, configs);
|
|
105
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { hash } from "ohash";
|
|
2
|
+
import { encodeQueryParams } from "../../utils/query.js";
|
|
3
|
+
import { jsonStringify } from "../../utils/json.js";
|
|
4
|
+
import { addPrerenderPath, shouldUseClientDB, withContentBase } from "../../composables/utils.js";
|
|
5
|
+
import { useContentPreview } from "../../composables/preview.js";
|
|
6
|
+
import { queryContent } from "./query.js";
|
|
7
|
+
import { useRuntimeConfig } from "#imports";
|
|
8
|
+
export const fetchContentNavigation = async (queryBuilder) => {
|
|
9
|
+
const { content } = useRuntimeConfig().public;
|
|
10
|
+
if (typeof queryBuilder?.params !== "function") {
|
|
11
|
+
queryBuilder = queryContent(queryBuilder);
|
|
12
|
+
}
|
|
13
|
+
const params = queryBuilder.params();
|
|
14
|
+
const apiPath = content.experimental.stripQueryParameters ? withContentBase(`/navigation/${import.meta.dev ? "_" : `${hash(params)}.${content.integrity}`}/${encodeQueryParams(params)}.json`) : withContentBase(import.meta.dev ? `/navigation/${hash(params)}` : `/navigation/${hash(params)}.${content.integrity}.json`);
|
|
15
|
+
if (!import.meta.dev && import.meta.server) {
|
|
16
|
+
addPrerenderPath(apiPath);
|
|
17
|
+
}
|
|
18
|
+
if (shouldUseClientDB()) {
|
|
19
|
+
const generateNavigation = await import("./client-db.js").then((m) => m.generateNavigation);
|
|
20
|
+
return generateNavigation(params);
|
|
21
|
+
}
|
|
22
|
+
const data = await $fetch(apiPath, {
|
|
23
|
+
method: "GET",
|
|
24
|
+
responseType: "json",
|
|
25
|
+
params: content.experimental.stripQueryParameters ? void 0 : {
|
|
26
|
+
_params: jsonStringify(params),
|
|
27
|
+
previewToken: useContentPreview().getPreviewToken()
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
if (typeof data === "string" && data.startsWith("<!DOCTYPE html>")) {
|
|
31
|
+
throw new Error("Not found");
|
|
32
|
+
}
|
|
33
|
+
return data;
|
|
34
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ParsedContent, QueryBuilder, QueryBuilderParams } from '@nuxt/content';
|
|
2
|
+
/**
|
|
3
|
+
* Query fetcher
|
|
4
|
+
*/
|
|
5
|
+
export declare const createQueryFetch: <T = ParsedContent>() => (query: QueryBuilder<T>) => Promise<any>;
|
|
6
|
+
/**
|
|
7
|
+
* Query contents from path
|
|
8
|
+
*/
|
|
9
|
+
export declare function queryContent<T = ParsedContent>(query?: QueryBuilderParams): QueryBuilder<T>;
|
|
10
|
+
export declare function queryContent<T = ParsedContent>(query: string, ...pathParts: string[]): QueryBuilder<T>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { joinURL, withLeadingSlash, withoutTrailingSlash } from "ufo";
|
|
2
|
+
import { hash } from "ohash";
|
|
3
|
+
import { createQuery } from "../../query/query.js";
|
|
4
|
+
import { encodeQueryParams } from "../../utils/query.js";
|
|
5
|
+
import { jsonStringify } from "../../utils/json.js";
|
|
6
|
+
import { addPrerenderPath, shouldUseClientDB, withContentBase } from "../../composables/utils.js";
|
|
7
|
+
import { useContentPreview } from "../../composables/preview.js";
|
|
8
|
+
import { useRuntimeConfig } from "#imports";
|
|
9
|
+
export const createQueryFetch = () => async (query) => {
|
|
10
|
+
const { content } = useRuntimeConfig().public;
|
|
11
|
+
const params = query.params();
|
|
12
|
+
const apiPath = content.experimental.stripQueryParameters ? withContentBase(`/query/${import.meta.dev ? "_" : `${hash(params)}.${content.integrity}`}/${encodeQueryParams(params)}.json`) : withContentBase(import.meta.dev ? "/query" : `/query/${hash(params)}.${content.integrity}.json`);
|
|
13
|
+
if (!import.meta.dev && import.meta.server) {
|
|
14
|
+
addPrerenderPath(apiPath);
|
|
15
|
+
}
|
|
16
|
+
if (shouldUseClientDB()) {
|
|
17
|
+
const db = await import("./client-db.js").then((m) => m.useContentDatabase());
|
|
18
|
+
return db.fetch(query);
|
|
19
|
+
}
|
|
20
|
+
const _query = content.experimental.stripQueryParameters ? void 0 : `_params=${encodeURIComponent(jsonStringify(params))}&previewToken=${useContentPreview().getPreviewToken()}`;
|
|
21
|
+
const data = await $fetch(apiPath + "?" + _query, { method: "GET", responseType: "json" });
|
|
22
|
+
if (typeof data === "string" && data.startsWith("<!DOCTYPE html>")) {
|
|
23
|
+
throw new Error("Not found");
|
|
24
|
+
}
|
|
25
|
+
return data;
|
|
26
|
+
};
|
|
27
|
+
export function queryContent(query, ...pathParts) {
|
|
28
|
+
const { content } = useRuntimeConfig().public;
|
|
29
|
+
const queryBuilder = createQuery(createQueryFetch(), {
|
|
30
|
+
initialParams: typeof query !== "string" ? query : {},
|
|
31
|
+
legacy: true
|
|
32
|
+
});
|
|
33
|
+
let path;
|
|
34
|
+
if (typeof query === "string") {
|
|
35
|
+
path = withLeadingSlash(joinURL(query, ...pathParts));
|
|
36
|
+
}
|
|
37
|
+
const originalParamsFn = queryBuilder.params;
|
|
38
|
+
queryBuilder.params = () => {
|
|
39
|
+
const params = originalParamsFn();
|
|
40
|
+
if (path) {
|
|
41
|
+
params.where = params.where || [];
|
|
42
|
+
if (params.first && (params.where || []).length === 0) {
|
|
43
|
+
params.where.push({ _path: withoutTrailingSlash(path) });
|
|
44
|
+
} else {
|
|
45
|
+
params.where.push({ _path: new RegExp(`^${path.replace(/[-[\]{}()*+.,^$\s/]/g, "\\$&")}`) });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (!params.sort?.length) {
|
|
49
|
+
params.sort = [{ _stem: 1, $numeric: true }];
|
|
50
|
+
}
|
|
51
|
+
if (content.locales.length) {
|
|
52
|
+
const queryLocale = params.where?.find((w) => w._locale)?._locale;
|
|
53
|
+
if (!queryLocale) {
|
|
54
|
+
params.where = params.where || [];
|
|
55
|
+
params.where.push({ _locale: content.defaultLocale });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return params;
|
|
59
|
+
};
|
|
60
|
+
return queryBuilder;
|
|
61
|
+
}
|