@blinkk/root-cms 3.0.2 → 3.0.4
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/dist/app.js +5 -5
- package/dist/{chunk-2BSW7SIH.js → chunk-N4K6ICFR.js} +4 -4
- package/dist/{chunk-BGTUWIV6.js → chunk-PNLLZXVY.js} +4 -4
- package/dist/{chunk-3HARN4U6.js → chunk-RLZFZT42.js} +176 -83
- package/dist/{chunk-C245C557.js → chunk-RXWDB3K4.js} +3 -3
- package/dist/{chunk-XLX37FRL.js → chunk-TEKMLYXS.js} +3 -4
- package/dist/cli/cli.d.ts +12 -0
- package/dist/cli/docs.d.ts +49 -0
- package/dist/cli/export.d.ts +11 -0
- package/dist/cli/generate-types.d.ts +6 -0
- package/dist/cli/import.d.ts +13 -0
- package/dist/cli/init-firebase.d.ts +7 -0
- package/dist/cli/utils.d.ts +27 -0
- package/dist/cli.js +10 -10
- package/dist/client.js +1 -1
- package/dist/core/ai-tools.d.ts +156 -0
- package/dist/core/ai.d.ts +330 -0
- package/dist/core/api.d.ts +21 -0
- package/dist/core/app.d.ts +16 -0
- package/dist/core/checks-translations.d.ts +13 -0
- package/dist/core/checks.d.ts +48 -0
- package/dist/core/client.d.ts +715 -0
- package/dist/core/core.d.ts +5 -0
- package/dist/core/cron.d.ts +19 -0
- package/dist/core/csv.d.ts +5 -0
- package/dist/core/functions.d.ts +9 -0
- package/dist/core/plugin.d.ts +357 -0
- package/dist/{project.d.ts → core/project.d.ts} +8 -12
- package/dist/core/richtext.d.ts +101 -0
- package/dist/{core.d.ts → core/route.d.ts} +13 -66
- package/dist/core/runtime.d.ts +46 -0
- package/dist/{schema-Db_xODoi.d.ts → core/schema.d.ts} +47 -100
- package/dist/core/search-extract.d.ts +70 -0
- package/dist/core/search-index.d.ts +182 -0
- package/dist/core/search-query.d.ts +68 -0
- package/dist/core/security.d.ts +6 -0
- package/dist/core/server-version.d.ts +5 -0
- package/dist/core/services-notifications.d.ts +57 -0
- package/dist/core/services.d.ts +44 -0
- package/dist/core/sse.d.ts +10 -0
- package/dist/core/translations-manager.d.ts +187 -0
- package/dist/core/translations.d.ts +83 -0
- package/dist/core/url-safety.d.ts +19 -0
- package/dist/core/validation.d.ts +30 -0
- package/dist/core/values.d.ts +9 -0
- package/dist/core/versions.d.ts +48 -0
- package/dist/core.js +1 -1
- package/dist/edit-M4PN4SGX.js +7 -0
- package/dist/functions.js +4 -4
- package/dist/{generate-types-SPV7I3A5.js → generate-types-JWIG4QVI.js} +1 -1
- package/dist/plugin.js +128 -133
- package/dist/shared/marshal.d.ts +68 -0
- package/dist/shared/objects.d.ts +9 -0
- package/dist/shared/richtext.d.ts +74 -0
- package/dist/shared/safe-json.d.ts +11 -0
- package/dist/shared/sanitize.d.ts +12 -0
- package/dist/shared/slug.d.ts +19 -0
- package/dist/shared/sse.d.ts +16 -0
- package/dist/shared/strings.d.ts +23 -0
- package/dist/ui/AIPage-YI3RFK5F.js +1 -0
- package/dist/ui/AssetsPage-4JNAOFYF.js +1 -0
- package/dist/ui/CollectionPage-JWHH5G55.js +1 -0
- package/dist/ui/ComparePage-YZE3EMU4.js +1 -0
- package/dist/ui/DataPage-VRCQSZZG.js +1 -0
- package/dist/ui/DataSourcePage-WMSPBZ3W.js +1 -0
- package/dist/ui/DocTranslationsPage-RY2LOZBX.js +1 -0
- package/dist/ui/DocumentPage-EEGTJMIW.js +1 -0
- package/dist/ui/EditDataSourcePage-LLCX6K4J.js +1 -0
- package/dist/ui/EditReleasePage-WQYXXMZQ.js +1 -0
- package/dist/ui/ImageEditorDialog-4H665KK2.js +81 -0
- package/dist/ui/ImageEditorDialog-4H665KK2.js.LEGAL.txt +17 -0
- package/dist/ui/LogsPage-IP2DKEYR.js +1 -0
- package/dist/ui/NewDataSourcePage-RDYJC4DH.js +1 -0
- package/dist/ui/NewReleasePage-DGMFU2JN.js +1 -0
- package/dist/ui/NotFoundPage-WDZ2K7EF.js +1 -0
- package/dist/ui/ProjectPage-HYJOQUWR.js +1 -0
- package/dist/ui/ReleasePage-2KSF23TK.js +1 -0
- package/dist/ui/ReleasesPage-NZIBBXU4.js +1 -0
- package/dist/ui/SettingsPage-36XFWV62.js +1 -0
- package/dist/ui/SidebarToolsPage-5C6YBWJ7.js +1 -0
- package/dist/ui/TaskPage-SPIFPGPP.js +1 -0
- package/dist/ui/TasksPage-ZOXRPBQV.js +1 -0
- package/dist/ui/TranslationsArbPage-UHANA7JD.js +2 -0
- package/dist/ui/TranslationsEditPage-PQY6W5YG.js +1 -0
- package/dist/ui/TranslationsPage-V2PQFCN5.js +162 -0
- package/dist/ui/ai-tools-5E5ELLZX.js +1 -0
- package/dist/ui/chunk-3IYZCUPI.js +1 -0
- package/dist/ui/chunk-4KE2SZKH.js +1 -0
- package/dist/ui/chunk-4W73RW5I.js +1 -0
- package/dist/ui/chunk-54DVDYU6.js +1 -0
- package/dist/ui/chunk-5MV6XVGA.js +1 -0
- package/dist/ui/chunk-62UWGWON.js +1 -0
- package/dist/ui/chunk-767BAQ53.js +1 -0
- package/dist/ui/chunk-AFWBSIPL.js +1 -0
- package/dist/ui/chunk-AL3TN2KI.js +1 -0
- package/dist/ui/chunk-BZIRGB4W.js +1 -0
- package/dist/ui/chunk-C5NH23G4.js +3 -0
- package/dist/ui/chunk-CGCKJFL4.js +1 -0
- package/dist/ui/chunk-DEGMKEHP.js +1 -0
- package/dist/ui/chunk-DTMZLUNY.js +15 -0
- package/dist/ui/chunk-DTMZLUNY.js.LEGAL.txt +237 -0
- package/dist/ui/chunk-DUJYIOLE.js +5 -0
- package/dist/ui/chunk-E2RCCK2T.js +1 -0
- package/dist/ui/chunk-EGEB6N4J.js +22 -0
- package/dist/ui/chunk-EGEB6N4J.js.LEGAL.txt +1059 -0
- package/dist/ui/chunk-FBJURT7Z.js +1 -0
- package/dist/ui/chunk-GXSAEPU3.js +1 -0
- package/dist/ui/chunk-HHMG665Z.js +1 -0
- package/dist/ui/chunk-HKINZLMW.js +84 -0
- package/dist/ui/chunk-HLMBCVRX.js +1 -0
- package/dist/ui/chunk-HRGYNHZ3.js +1 -0
- package/dist/ui/chunk-I6ICVKEC.js +1 -0
- package/dist/ui/chunk-JDW4UORS.js +1 -0
- package/dist/ui/chunk-JHBAMPGB.js +1 -0
- package/dist/ui/chunk-JT5L6GPZ.js +141 -0
- package/dist/ui/chunk-JT5L6GPZ.js.LEGAL.txt +106 -0
- package/dist/ui/chunk-JYFLU7DM.js +19 -0
- package/dist/ui/chunk-JZFTZ4X4.js +87 -0
- package/dist/ui/chunk-JZFTZ4X4.js.LEGAL.txt +9 -0
- package/dist/ui/chunk-KFAZBEPV.js +1 -0
- package/dist/ui/chunk-KKEWCXVV.js +1 -0
- package/dist/ui/chunk-KUCVLANF.js +1 -0
- package/dist/ui/chunk-KYDOSLTO.js +1 -0
- package/dist/ui/chunk-L4RHGQUG.js +1 -0
- package/dist/ui/chunk-MDUBCXU2.js +1 -0
- package/dist/ui/chunk-NXQVLOTK.js +1 -0
- package/dist/ui/chunk-NZHF733K.js +7 -0
- package/dist/ui/chunk-NZHF733K.js.LEGAL.txt +146 -0
- package/dist/ui/chunk-ONTGW2VA.js +1 -0
- package/dist/ui/chunk-ORXEMIQC.js +1 -0
- package/dist/ui/chunk-P3NETZZP.js +1 -0
- package/dist/ui/chunk-PHBMVORG.js +1 -0
- package/dist/ui/chunk-PJA7YP4A.js +1 -0
- package/dist/ui/chunk-PVAE643M.js +1 -0
- package/dist/ui/chunk-PWKJDYE2.js +1 -0
- package/dist/ui/chunk-RSVO46S3.js +1 -0
- package/dist/ui/chunk-SKEP5WYH.js +10 -0
- package/dist/ui/chunk-SKEP5WYH.js.LEGAL.txt +176 -0
- package/dist/ui/chunk-SQRKKWRG.js +3 -0
- package/dist/ui/chunk-TJBVMFNQ.js +1 -0
- package/dist/ui/chunk-V7S4IAGB.js +1 -0
- package/dist/ui/chunk-VMT7JFAM.js +1 -0
- package/dist/ui/chunk-W3BJ2EZX.js +1 -0
- package/dist/ui/chunk-W3HIZQ4Z.js +1 -0
- package/dist/ui/chunk-X2WHBGTP.js +1 -0
- package/dist/ui/chunk-XOQ3KDSR.js +3 -0
- package/dist/ui/chunk-YDO2EDVY.js +1 -0
- package/dist/ui/chunk-YFA6U2CV.js +1 -0
- package/dist/ui/gcs-L33FIRZU.js +1 -0
- package/dist/ui/prerender-Q4YSDCPB.js +1 -0
- package/dist/ui/signin.js +1 -1
- package/dist/ui/ui.css +1 -1
- package/dist/ui/ui.js +1 -630
- package/dist/ui/ui.js.LEGAL.txt +19 -732
- package/package.json +20 -20
- package/dist/client-1puwLgNx.d.ts +0 -1552
- package/dist/client.d.ts +0 -5
- package/dist/edit-MT4B37QK.js +0 -7
- package/dist/functions.d.ts +0 -13
- package/dist/plugin.d.ts +0 -5
- package/dist/richtext.d.ts +0 -104
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** @deprecated Use client.ts instead. */
|
|
2
|
+
import { RootConfig } from '@blinkk/root';
|
|
3
|
+
import { Query } from 'firebase-admin/firestore';
|
|
4
|
+
import { LoadTranslationsOptions, LocaleTranslations, TranslationsMap } from './client.js';
|
|
5
|
+
/**
|
|
6
|
+
* Retrieves a doc from Root.js CMS.
|
|
7
|
+
* @deprecated Use RootCMSClient.getDoc() instead.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getDoc<T>(rootConfig: RootConfig, collectionId: string, slug: string, options: {
|
|
10
|
+
mode: 'draft' | 'published';
|
|
11
|
+
}): Promise<T | null>;
|
|
12
|
+
/**
|
|
13
|
+
* Lists docs from a Root.js CMS collection.
|
|
14
|
+
* @deprecated Use RootCMSClient.listDocs() instead.
|
|
15
|
+
*/
|
|
16
|
+
export declare function listDocs<T>(rootConfig: RootConfig, collectionId: string, options: {
|
|
17
|
+
mode: 'draft' | 'published';
|
|
18
|
+
offset?: number;
|
|
19
|
+
limit?: number;
|
|
20
|
+
orderBy?: string;
|
|
21
|
+
orderByDirection?: 'asc' | 'desc';
|
|
22
|
+
query?: (query: Query) => Query;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
docs: T[];
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Returns the number of docs in a Root.js CMS collection.
|
|
28
|
+
* @deprecated Use RootCMSClient.getDocsCount() instead.
|
|
29
|
+
*/
|
|
30
|
+
export declare function numDocs(rootConfig: RootConfig, collectionId: string, options: {
|
|
31
|
+
mode: 'draft' | 'published';
|
|
32
|
+
query?: (query: Query) => Query;
|
|
33
|
+
}): Promise<number>;
|
|
34
|
+
/**
|
|
35
|
+
* Publishes scheduled docs.
|
|
36
|
+
* @deprecated Use RootCMSClient.publishScheduledDocs() instead.
|
|
37
|
+
*/
|
|
38
|
+
export declare function publishScheduledDocs(rootConfig: RootConfig): Promise<any[]>;
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated Use `RootCMSClient.loadTranslations()`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function loadTranslations(rootConfig: RootConfig, options?: LoadTranslationsOptions): Promise<TranslationsMap>;
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated Use `RootCMSClient.loadTranslationsForLocale()`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function loadTranslationsForLocale(rootConfig: RootConfig, locale: string, options?: LoadTranslationsOptions): Promise<LocaleTranslations>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
interface CommonFieldProps {
|
|
1
|
+
export interface CommonFieldProps {
|
|
2
2
|
/** The type that defines the structure of the field and its UI component. */
|
|
3
3
|
type: string;
|
|
4
4
|
/** The ID provides a key for the field in the data. */
|
|
@@ -17,7 +17,7 @@ interface CommonFieldProps {
|
|
|
17
17
|
/** Hides just the field label in the CMS UI. */
|
|
18
18
|
hideLabel?: boolean;
|
|
19
19
|
}
|
|
20
|
-
type StringField = CommonFieldProps & {
|
|
20
|
+
export type StringField = CommonFieldProps & {
|
|
21
21
|
type: 'string';
|
|
22
22
|
default?: string;
|
|
23
23
|
translate?: boolean;
|
|
@@ -37,18 +37,18 @@ type StringField = CommonFieldProps & {
|
|
|
37
37
|
*/
|
|
38
38
|
autosize?: boolean;
|
|
39
39
|
};
|
|
40
|
-
declare function string(field: Omit<StringField, 'type'>): StringField;
|
|
41
|
-
type NumberField = CommonFieldProps & {
|
|
40
|
+
export declare function string(field: Omit<StringField, 'type'>): StringField;
|
|
41
|
+
export type NumberField = CommonFieldProps & {
|
|
42
42
|
type: 'number';
|
|
43
43
|
default?: number;
|
|
44
44
|
};
|
|
45
|
-
declare function number(field: Omit<NumberField, 'type'>): NumberField;
|
|
46
|
-
type DateField = CommonFieldProps & {
|
|
45
|
+
export declare function number(field: Omit<NumberField, 'type'>): NumberField;
|
|
46
|
+
export type DateField = CommonFieldProps & {
|
|
47
47
|
type: 'date';
|
|
48
48
|
default?: string;
|
|
49
49
|
};
|
|
50
|
-
declare function date(field: Omit<DateField, 'type'>): DateField;
|
|
51
|
-
type DateTimeField = CommonFieldProps & {
|
|
50
|
+
export declare function date(field: Omit<DateField, 'type'>): DateField;
|
|
51
|
+
export type DateTimeField = CommonFieldProps & {
|
|
52
52
|
type: 'datetime';
|
|
53
53
|
default?: string;
|
|
54
54
|
/**
|
|
@@ -57,14 +57,14 @@ type DateTimeField = CommonFieldProps & {
|
|
|
57
57
|
*/
|
|
58
58
|
timezone?: string;
|
|
59
59
|
};
|
|
60
|
-
declare function datetime(field: Omit<DateTimeField, 'type'>): DateTimeField;
|
|
61
|
-
type BooleanField = CommonFieldProps & {
|
|
60
|
+
export declare function datetime(field: Omit<DateTimeField, 'type'>): DateTimeField;
|
|
61
|
+
export type BooleanField = CommonFieldProps & {
|
|
62
62
|
type: 'boolean';
|
|
63
63
|
default?: boolean;
|
|
64
64
|
checkboxLabel?: string;
|
|
65
65
|
};
|
|
66
|
-
declare function boolean(field: Omit<BooleanField, 'type'>): BooleanField;
|
|
67
|
-
type SelectField = CommonFieldProps & {
|
|
66
|
+
export declare function boolean(field: Omit<BooleanField, 'type'>): BooleanField;
|
|
67
|
+
export type SelectField = CommonFieldProps & {
|
|
68
68
|
type: 'select';
|
|
69
69
|
default?: string;
|
|
70
70
|
options?: Array<{
|
|
@@ -74,15 +74,15 @@ type SelectField = CommonFieldProps & {
|
|
|
74
74
|
translate?: boolean;
|
|
75
75
|
searchable?: boolean;
|
|
76
76
|
};
|
|
77
|
-
declare function select(field: Omit<SelectField, 'type'>): SelectField;
|
|
78
|
-
type MultiSelectField = Omit<SelectField, 'type'> & {
|
|
77
|
+
export declare function select(field: Omit<SelectField, 'type'>): SelectField;
|
|
78
|
+
export type MultiSelectField = Omit<SelectField, 'type'> & {
|
|
79
79
|
type: 'multiselect';
|
|
80
80
|
/** Set to `true` to allow users to create arbitrary values. */
|
|
81
81
|
creatable?: boolean;
|
|
82
82
|
translate?: boolean;
|
|
83
83
|
};
|
|
84
|
-
declare function multiselect(field: Omit<MultiSelectField, 'type'>): MultiSelectField;
|
|
85
|
-
type ImageField = CommonFieldProps & {
|
|
84
|
+
export declare function multiselect(field: Omit<MultiSelectField, 'type'>): MultiSelectField;
|
|
85
|
+
export type ImageField = CommonFieldProps & {
|
|
86
86
|
type: 'image';
|
|
87
87
|
translate?: boolean;
|
|
88
88
|
/** List of supported exts, e.g. `['.mp4']`. */
|
|
@@ -94,8 +94,8 @@ type ImageField = CommonFieldProps & {
|
|
|
94
94
|
/** Set to `false` to disable the alt text input. */
|
|
95
95
|
alt?: boolean;
|
|
96
96
|
};
|
|
97
|
-
declare function image(field: Omit<ImageField, 'type'>): ImageField;
|
|
98
|
-
type FileField = CommonFieldProps & {
|
|
97
|
+
export declare function image(field: Omit<ImageField, 'type'>): ImageField;
|
|
98
|
+
export type FileField = CommonFieldProps & {
|
|
99
99
|
type: 'file';
|
|
100
100
|
/** List of supported exts, e.g. `['.mp4']`. */
|
|
101
101
|
exts?: string[];
|
|
@@ -111,8 +111,8 @@ type FileField = CommonFieldProps & {
|
|
|
111
111
|
/** Set to `false` to disable the alt text input. */
|
|
112
112
|
alt?: boolean;
|
|
113
113
|
};
|
|
114
|
-
declare function file(field: Omit<FileField, 'type'>): FileField;
|
|
115
|
-
type ObjectField = CommonFieldProps & {
|
|
114
|
+
export declare function file(field: Omit<FileField, 'type'>): FileField;
|
|
115
|
+
export type ObjectField = CommonFieldProps & {
|
|
116
116
|
type: 'object';
|
|
117
117
|
fields: FieldWithId[];
|
|
118
118
|
/** Defaults to "drawer". */
|
|
@@ -128,8 +128,8 @@ type ObjectField = CommonFieldProps & {
|
|
|
128
128
|
inline?: boolean;
|
|
129
129
|
};
|
|
130
130
|
};
|
|
131
|
-
declare function object(field: Omit<ObjectField, 'type'>): ObjectField;
|
|
132
|
-
type ArrayField = CommonFieldProps & {
|
|
131
|
+
export declare function object(field: Omit<ObjectField, 'type'>): ObjectField;
|
|
132
|
+
export type ArrayField = CommonFieldProps & {
|
|
133
133
|
type: 'array';
|
|
134
134
|
default?: any[];
|
|
135
135
|
/**
|
|
@@ -161,13 +161,13 @@ type ArrayField = CommonFieldProps & {
|
|
|
161
161
|
*/
|
|
162
162
|
defaultOpen?: boolean;
|
|
163
163
|
};
|
|
164
|
-
declare function array(field: Omit<ArrayField, 'type'>): ArrayField;
|
|
164
|
+
export declare function array(field: Omit<ArrayField, 'type'>): ArrayField;
|
|
165
165
|
/**
|
|
166
166
|
* A schema pattern that is resolved at project load time. This allows schemas
|
|
167
167
|
* to reference other schemas by glob pattern without causing circular import
|
|
168
168
|
* issues, since resolution is deferred until all schemas are loaded.
|
|
169
169
|
*/
|
|
170
|
-
interface SchemaPattern {
|
|
170
|
+
export interface SchemaPattern {
|
|
171
171
|
/** Marker to identify this as a schema pattern. */
|
|
172
172
|
_schemaPattern: true;
|
|
173
173
|
/** Glob pattern to match schema files. */
|
|
@@ -177,7 +177,7 @@ interface SchemaPattern {
|
|
|
177
177
|
/** Field IDs to omit from the matched schemas. */
|
|
178
178
|
omitFields?: string[];
|
|
179
179
|
}
|
|
180
|
-
type OneOfField = CommonFieldProps & {
|
|
180
|
+
export type OneOfField = CommonFieldProps & {
|
|
181
181
|
type: 'oneof';
|
|
182
182
|
/**
|
|
183
183
|
* UI variant for the oneOf field.
|
|
@@ -195,8 +195,8 @@ type OneOfField = CommonFieldProps & {
|
|
|
195
195
|
*/
|
|
196
196
|
types: Schema[] | string[] | Array<Schema | string> | SchemaPattern;
|
|
197
197
|
};
|
|
198
|
-
declare function oneOf(field: Omit<OneOfField, 'type'>): OneOfField;
|
|
199
|
-
type RichTextField = CommonFieldProps & {
|
|
198
|
+
export declare function oneOf(field: Omit<OneOfField, 'type'>): OneOfField;
|
|
199
|
+
export type RichTextField = CommonFieldProps & {
|
|
200
200
|
type: 'richtext';
|
|
201
201
|
translate?: boolean;
|
|
202
202
|
placeholder?: string;
|
|
@@ -210,8 +210,8 @@ type RichTextField = CommonFieldProps & {
|
|
|
210
210
|
/** Custom inline component definitions to include in the rich text editor. */
|
|
211
211
|
inlineComponents?: Schema[];
|
|
212
212
|
};
|
|
213
|
-
declare function richtext(field: Omit<RichTextField, 'type'>): RichTextField;
|
|
214
|
-
type ReferenceField = CommonFieldProps & {
|
|
213
|
+
export declare function richtext(field: Omit<RichTextField, 'type'>): RichTextField;
|
|
214
|
+
export type ReferenceField = CommonFieldProps & {
|
|
215
215
|
type: 'reference';
|
|
216
216
|
/** List of collection ids the reference can be chosen from. */
|
|
217
217
|
collections?: string[];
|
|
@@ -220,8 +220,8 @@ type ReferenceField = CommonFieldProps & {
|
|
|
220
220
|
/** Label for the button. Defaults to "Select". */
|
|
221
221
|
buttonLabel?: string;
|
|
222
222
|
};
|
|
223
|
-
declare function reference(field: Omit<ReferenceField, 'type'>): ReferenceField;
|
|
224
|
-
type ReferencesField = CommonFieldProps & {
|
|
223
|
+
export declare function reference(field: Omit<ReferenceField, 'type'>): ReferenceField;
|
|
224
|
+
export type ReferencesField = CommonFieldProps & {
|
|
225
225
|
type: 'references';
|
|
226
226
|
/** List of collection ids the references can be chosen from. */
|
|
227
227
|
collections?: string[];
|
|
@@ -230,15 +230,15 @@ type ReferencesField = CommonFieldProps & {
|
|
|
230
230
|
/** Label for the button. Defaults to "Select". */
|
|
231
231
|
buttonLabel?: string;
|
|
232
232
|
};
|
|
233
|
-
declare function references(field: Omit<ReferencesField, 'type'>): ReferencesField;
|
|
234
|
-
type Field = StringField | NumberField | DateField | DateTimeField | BooleanField | SelectField | MultiSelectField | ImageField | FileField | ObjectField | ArrayField | OneOfField | RichTextField | ReferenceField | ReferencesField;
|
|
233
|
+
export declare function references(field: Omit<ReferencesField, 'type'>): ReferencesField;
|
|
234
|
+
export type Field = StringField | NumberField | DateField | DateTimeField | BooleanField | SelectField | MultiSelectField | ImageField | FileField | ObjectField | ArrayField | OneOfField | RichTextField | ReferenceField | ReferencesField;
|
|
235
235
|
/**
|
|
236
236
|
* Similar to {@link Field} but with a required `id`.
|
|
237
237
|
* TODO(stevenle): fix this.
|
|
238
238
|
*/
|
|
239
|
-
type FieldWithId = Field;
|
|
240
|
-
type ObjectLikeField = ImageField | FileField | ObjectField | OneOfField | ReferenceField;
|
|
241
|
-
interface SchemaPreset<T = Record<string, any>> {
|
|
239
|
+
export type FieldWithId = Field;
|
|
240
|
+
export type ObjectLikeField = ImageField | FileField | ObjectField | OneOfField | ReferenceField;
|
|
241
|
+
export interface SchemaPreset<T = Record<string, any>> {
|
|
242
242
|
/** Unique identifier for the preset within the schema. */
|
|
243
243
|
id: string;
|
|
244
244
|
/** Display title for the preset. Defaults to the preset id. */
|
|
@@ -257,7 +257,7 @@ interface SchemaPreset<T = Record<string, any>> {
|
|
|
257
257
|
*/
|
|
258
258
|
data?: T;
|
|
259
259
|
}
|
|
260
|
-
interface Schema {
|
|
260
|
+
export interface Schema {
|
|
261
261
|
/** The name of the content type. Used as the field key. */
|
|
262
262
|
name: string;
|
|
263
263
|
/** Label to use for UI strings. */
|
|
@@ -304,13 +304,13 @@ interface Schema {
|
|
|
304
304
|
image?: string | string[];
|
|
305
305
|
};
|
|
306
306
|
}
|
|
307
|
-
type SchemaWithTypes = Schema & {
|
|
307
|
+
export type SchemaWithTypes = Schema & {
|
|
308
308
|
/** Reusable type definitions used by the schema, e.g. for oneOf() fields. */
|
|
309
309
|
types?: Record<string, Schema>;
|
|
310
310
|
};
|
|
311
|
-
declare function defineSchema(schema: Schema): Schema;
|
|
311
|
+
export declare function defineSchema(schema: Schema): Schema;
|
|
312
312
|
/** Defines the schema for a collection or reusable component. */
|
|
313
|
-
declare const define: typeof defineSchema;
|
|
313
|
+
export declare const define: typeof defineSchema;
|
|
314
314
|
/**
|
|
315
315
|
* Defines a preset for use within `schema.define({presets: [...]})`. The
|
|
316
316
|
* optional generic parameter `T` constrains the shape of the preset's `data`
|
|
@@ -326,10 +326,10 @@ declare const define: typeof defineSchema;
|
|
|
326
326
|
* });
|
|
327
327
|
* ```
|
|
328
328
|
*/
|
|
329
|
-
declare function definePreset<T = Record<string, any>>(preset: SchemaPreset<T>): SchemaPreset<T>;
|
|
329
|
+
export declare function definePreset<T = Record<string, any>>(preset: SchemaPreset<T>): SchemaPreset<T>;
|
|
330
330
|
/** Alias for {@link definePreset}. */
|
|
331
|
-
declare const preset: typeof definePreset;
|
|
332
|
-
type Collection = SchemaWithTypes & {
|
|
331
|
+
export declare const preset: typeof definePreset;
|
|
332
|
+
export type Collection = SchemaWithTypes & {
|
|
333
333
|
/**
|
|
334
334
|
* The ID of the collection. This comes from the schema filename, e.g
|
|
335
335
|
* `<id>.schema.ts`.
|
|
@@ -397,12 +397,12 @@ type Collection = SchemaWithTypes & {
|
|
|
397
397
|
direction?: 'asc' | 'desc';
|
|
398
398
|
}>;
|
|
399
399
|
};
|
|
400
|
-
declare function defineCollection(collection: Omit<Collection, 'id'>): Omit<Collection, 'id'>;
|
|
401
|
-
declare const collection: typeof defineCollection;
|
|
400
|
+
export declare function defineCollection(collection: Omit<Collection, 'id'>): Omit<Collection, 'id'>;
|
|
401
|
+
export declare const collection: typeof defineCollection;
|
|
402
402
|
/**
|
|
403
403
|
* Options for `schema.glob()`.
|
|
404
404
|
*/
|
|
405
|
-
interface GlobOptions {
|
|
405
|
+
export interface GlobOptions {
|
|
406
406
|
/** Schema names to exclude from the matched results. */
|
|
407
407
|
exclude?: string[];
|
|
408
408
|
/** Field IDs to omit from the matched schemas. */
|
|
@@ -449,57 +449,4 @@ interface GlobOptions {
|
|
|
449
449
|
* });
|
|
450
450
|
* ```
|
|
451
451
|
*/
|
|
452
|
-
declare function glob(pattern: string, options?: GlobOptions): SchemaPattern;
|
|
453
|
-
|
|
454
|
-
type schema_ArrayField = ArrayField;
|
|
455
|
-
type schema_BooleanField = BooleanField;
|
|
456
|
-
type schema_Collection = Collection;
|
|
457
|
-
type schema_CommonFieldProps = CommonFieldProps;
|
|
458
|
-
type schema_DateField = DateField;
|
|
459
|
-
type schema_DateTimeField = DateTimeField;
|
|
460
|
-
type schema_Field = Field;
|
|
461
|
-
type schema_FieldWithId = FieldWithId;
|
|
462
|
-
type schema_FileField = FileField;
|
|
463
|
-
type schema_GlobOptions = GlobOptions;
|
|
464
|
-
type schema_ImageField = ImageField;
|
|
465
|
-
type schema_MultiSelectField = MultiSelectField;
|
|
466
|
-
type schema_NumberField = NumberField;
|
|
467
|
-
type schema_ObjectField = ObjectField;
|
|
468
|
-
type schema_ObjectLikeField = ObjectLikeField;
|
|
469
|
-
type schema_OneOfField = OneOfField;
|
|
470
|
-
type schema_ReferenceField = ReferenceField;
|
|
471
|
-
type schema_ReferencesField = ReferencesField;
|
|
472
|
-
type schema_RichTextField = RichTextField;
|
|
473
|
-
type schema_Schema = Schema;
|
|
474
|
-
type schema_SchemaPattern = SchemaPattern;
|
|
475
|
-
type schema_SchemaPreset<T = Record<string, any>> = SchemaPreset<T>;
|
|
476
|
-
type schema_SchemaWithTypes = SchemaWithTypes;
|
|
477
|
-
type schema_SelectField = SelectField;
|
|
478
|
-
type schema_StringField = StringField;
|
|
479
|
-
declare const schema_array: typeof array;
|
|
480
|
-
declare const schema_boolean: typeof boolean;
|
|
481
|
-
declare const schema_collection: typeof collection;
|
|
482
|
-
declare const schema_date: typeof date;
|
|
483
|
-
declare const schema_datetime: typeof datetime;
|
|
484
|
-
declare const schema_define: typeof define;
|
|
485
|
-
declare const schema_defineCollection: typeof defineCollection;
|
|
486
|
-
declare const schema_definePreset: typeof definePreset;
|
|
487
|
-
declare const schema_defineSchema: typeof defineSchema;
|
|
488
|
-
declare const schema_file: typeof file;
|
|
489
|
-
declare const schema_glob: typeof glob;
|
|
490
|
-
declare const schema_image: typeof image;
|
|
491
|
-
declare const schema_multiselect: typeof multiselect;
|
|
492
|
-
declare const schema_number: typeof number;
|
|
493
|
-
declare const schema_object: typeof object;
|
|
494
|
-
declare const schema_oneOf: typeof oneOf;
|
|
495
|
-
declare const schema_preset: typeof preset;
|
|
496
|
-
declare const schema_reference: typeof reference;
|
|
497
|
-
declare const schema_references: typeof references;
|
|
498
|
-
declare const schema_richtext: typeof richtext;
|
|
499
|
-
declare const schema_select: typeof select;
|
|
500
|
-
declare const schema_string: typeof string;
|
|
501
|
-
declare namespace schema {
|
|
502
|
-
export { type schema_ArrayField as ArrayField, type schema_BooleanField as BooleanField, type schema_Collection as Collection, type schema_CommonFieldProps as CommonFieldProps, type schema_DateField as DateField, type schema_DateTimeField as DateTimeField, type schema_Field as Field, type schema_FieldWithId as FieldWithId, type schema_FileField as FileField, type schema_GlobOptions as GlobOptions, type schema_ImageField as ImageField, type schema_MultiSelectField as MultiSelectField, type schema_NumberField as NumberField, type schema_ObjectField as ObjectField, type schema_ObjectLikeField as ObjectLikeField, type schema_OneOfField as OneOfField, type schema_ReferenceField as ReferenceField, type schema_ReferencesField as ReferencesField, type schema_RichTextField as RichTextField, type schema_Schema as Schema, type schema_SchemaPattern as SchemaPattern, type schema_SchemaPreset as SchemaPreset, type schema_SchemaWithTypes as SchemaWithTypes, type schema_SelectField as SelectField, type schema_StringField as StringField, schema_array as array, schema_boolean as boolean, schema_collection as collection, schema_date as date, schema_datetime as datetime, schema_define as define, schema_defineCollection as defineCollection, schema_definePreset as definePreset, schema_defineSchema as defineSchema, schema_file as file, schema_glob as glob, schema_image as image, schema_multiselect as multiselect, schema_number as number, schema_object as object, schema_oneOf as oneOf, schema_preset as preset, schema_reference as reference, schema_references as references, schema_richtext as richtext, schema_select as select, schema_string as string };
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
export { type Collection as C, type Schema as S, schema as s };
|
|
452
|
+
export declare function glob(pattern: string, options?: GlobOptions): SchemaPattern;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure (no I/O) extraction of searchable text from CMS doc data, guided by the
|
|
3
|
+
* collection's schema.
|
|
4
|
+
*
|
|
5
|
+
* Walks `fields: {...}` recursively and emits one record per leaf "text-bearing"
|
|
6
|
+
* field. The emitted `deepKey` matches the format used by the doc editor's
|
|
7
|
+
* deep-link system (see ui/hooks/useDeeplink.tsx) so that clicking a search
|
|
8
|
+
* result navigates the editor to the originating field.
|
|
9
|
+
*
|
|
10
|
+
* Reference for the deepKey format (see ui/components/DocEditor/DocEditor.tsx):
|
|
11
|
+
* - Top-level field: fields.<id>
|
|
12
|
+
* - Nested object field: fields.<id>.<sub>
|
|
13
|
+
* - Array item field: fields.<id>.<autokey>.<sub> (autokeys come from `_array`)
|
|
14
|
+
* - oneOf field: fields.<id>.<sub> (siblings of `_type`)
|
|
15
|
+
*/
|
|
16
|
+
import type { Field, Schema } from './schema.js';
|
|
17
|
+
/** Hard cap for any single extracted text value. */
|
|
18
|
+
export declare const MAX_FIELD_TEXT_CHARS = 2000;
|
|
19
|
+
export interface ExtractedRecord {
|
|
20
|
+
/** Stable record id: `<docId>#<deepKey>`. */
|
|
21
|
+
id: string;
|
|
22
|
+
/** Doc id, e.g. `Pages/foo-bar`. */
|
|
23
|
+
docId: string;
|
|
24
|
+
collection: string;
|
|
25
|
+
slug: string;
|
|
26
|
+
/** Full deep-link path, e.g. `fields.author.name` or `fields.list.<key>.title`. */
|
|
27
|
+
deepKey: string;
|
|
28
|
+
/** Field type, e.g. `string`, `richtext`, `select`. */
|
|
29
|
+
fieldType: string;
|
|
30
|
+
/** UI label for the field (falls back to `id`). */
|
|
31
|
+
fieldLabel: string;
|
|
32
|
+
/** Extracted plain text, truncated to MAX_FIELD_TEXT_CHARS. */
|
|
33
|
+
text: string;
|
|
34
|
+
}
|
|
35
|
+
interface EmitContext {
|
|
36
|
+
docId: string;
|
|
37
|
+
collection: string;
|
|
38
|
+
slug: string;
|
|
39
|
+
}
|
|
40
|
+
type EmitFn = (record: ExtractedRecord) => void;
|
|
41
|
+
/** Strip HTML tags and decode common entities from a string. */
|
|
42
|
+
export declare function stripHtml(input: string): string;
|
|
43
|
+
interface RichTextLike {
|
|
44
|
+
blocks?: Array<{
|
|
45
|
+
type?: string;
|
|
46
|
+
data?: any;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Extracts plain text from a richtext value (EditorJS-shaped).
|
|
51
|
+
*
|
|
52
|
+
* Supported block types mirror those rendered in `core/richtext.tsx`:
|
|
53
|
+
* paragraph, heading, quote, ordered/unordered list, table, html. Unknown or
|
|
54
|
+
* non-textual blocks (e.g. delimiter, image) contribute nothing.
|
|
55
|
+
*/
|
|
56
|
+
export declare function extractRichText(data: RichTextLike | unknown): string;
|
|
57
|
+
/**
|
|
58
|
+
* Walks a doc's `fields` against its collection schema and emits one record per
|
|
59
|
+
* text-bearing leaf field.
|
|
60
|
+
*/
|
|
61
|
+
export declare function walkSchemaFields(fields: Field[], data: any, parentDeepKey: string, ctx: EmitContext, emit: EmitFn): void;
|
|
62
|
+
export interface ExtractDocOptions {
|
|
63
|
+
collection: string;
|
|
64
|
+
slug: string;
|
|
65
|
+
/** Top-level fields object as stored on the doc. */
|
|
66
|
+
fields: any;
|
|
67
|
+
}
|
|
68
|
+
/** Extracts every searchable record from a single doc. */
|
|
69
|
+
export declare function extractDocRecords(schema: Schema, options: ExtractDocOptions): ExtractedRecord[];
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted full-text search index for the CMS.
|
|
3
|
+
*
|
|
4
|
+
* The index is built from the `Drafts` collection of every doc in the project,
|
|
5
|
+
* serialized via MiniSearch's `toJSON()`, sharded across Firestore docs (to
|
|
6
|
+
* stay under the 1 MB per-doc limit), and queried server-side by the
|
|
7
|
+
* `/cms/api/search.query` endpoint.
|
|
8
|
+
*
|
|
9
|
+
* Persistence layout:
|
|
10
|
+
* Projects/{projectId}/SearchIndex/_meta — {lastRun, shardCount, docCount, fieldCount}
|
|
11
|
+
* Projects/{projectId}/SearchIndex/_docMap — {records: {[docId]: recordIds[]}}
|
|
12
|
+
* Projects/{projectId}/SearchIndex/shard-0..N — {shardId, data} (chunks of toJSON())
|
|
13
|
+
*
|
|
14
|
+
* Build modes:
|
|
15
|
+
* - `force: false` (cron path) — incremental: discard records for docs whose
|
|
16
|
+
* `sys.modifiedAt >= lastRun`, re-extract them, addAll. Reconcile deletions
|
|
17
|
+
* by diffing _docMap against the live doc-id set per collection.
|
|
18
|
+
* - `force: true` — drop everything and re-index every doc.
|
|
19
|
+
*/
|
|
20
|
+
import { RootConfig } from '@blinkk/root';
|
|
21
|
+
import { Timestamp } from 'firebase-admin/firestore';
|
|
22
|
+
import MiniSearch from 'minisearch';
|
|
23
|
+
import type { CMSSearchIndexConfig } from './plugin.js';
|
|
24
|
+
import type { Schema } from './schema.js';
|
|
25
|
+
import { ExtractedRecord } from './search-extract.js';
|
|
26
|
+
interface IndexableRecord extends ExtractedRecord {
|
|
27
|
+
/** Per-record boost: 2 for title-like fields, 1 otherwise. */
|
|
28
|
+
weight: number;
|
|
29
|
+
}
|
|
30
|
+
interface SearchIndexMeta {
|
|
31
|
+
lastRun: Timestamp;
|
|
32
|
+
shardCount: number;
|
|
33
|
+
docCount: number;
|
|
34
|
+
fieldCount: number;
|
|
35
|
+
/** How many incremental rebuilds have run since the last vacuum. */
|
|
36
|
+
runsSinceVacuum?: number;
|
|
37
|
+
}
|
|
38
|
+
export interface SearchHit {
|
|
39
|
+
id: string;
|
|
40
|
+
docId: string;
|
|
41
|
+
collection: string;
|
|
42
|
+
slug: string;
|
|
43
|
+
deepKey: string;
|
|
44
|
+
fieldLabel: string;
|
|
45
|
+
fieldType: string;
|
|
46
|
+
text: string;
|
|
47
|
+
score: number;
|
|
48
|
+
terms: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface RebuildResult {
|
|
51
|
+
/** True if a full (force) rebuild was performed. */
|
|
52
|
+
forced: boolean;
|
|
53
|
+
/** True if the rebuild short-circuited (no work needed). */
|
|
54
|
+
skipped: boolean;
|
|
55
|
+
docCount: number;
|
|
56
|
+
fieldCount: number;
|
|
57
|
+
shardCount: number;
|
|
58
|
+
durationMs: number;
|
|
59
|
+
}
|
|
60
|
+
export interface SearchIndexStatus {
|
|
61
|
+
lastRun: number | null;
|
|
62
|
+
docCount: number;
|
|
63
|
+
fieldCount: number;
|
|
64
|
+
shardCount: number;
|
|
65
|
+
}
|
|
66
|
+
type DocMap = Record<string, string[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Normalized form of `CMSSearchIndexConfig`. Empty arrays are treated as
|
|
69
|
+
* "unset" so the user can defensively pass an empty list without accidentally
|
|
70
|
+
* excluding everything via `includeCollections: []`.
|
|
71
|
+
*/
|
|
72
|
+
interface ResolvedFilters {
|
|
73
|
+
includeCollections: Set<string> | null;
|
|
74
|
+
excludeCollections: Set<string> | null;
|
|
75
|
+
includeDocIds: Set<string> | null;
|
|
76
|
+
excludeDocIds: Set<string> | null;
|
|
77
|
+
}
|
|
78
|
+
export declare function resolveSearchIndexFilters(config?: CMSSearchIndexConfig): ResolvedFilters;
|
|
79
|
+
export declare function isCollectionIndexable(filters: ResolvedFilters, collectionId: string): boolean;
|
|
80
|
+
export declare function isDocIndexable(filters: ResolvedFilters, docId: string): boolean;
|
|
81
|
+
interface CachedIndex {
|
|
82
|
+
index: MiniSearch;
|
|
83
|
+
meta: SearchIndexMeta;
|
|
84
|
+
docMap: DocMap;
|
|
85
|
+
}
|
|
86
|
+
export declare function isTitleyDeepKey(deepKey: string): boolean;
|
|
87
|
+
export declare function withWeight(rec: ExtractedRecord): IndexableRecord;
|
|
88
|
+
/**
|
|
89
|
+
* Loader for a collection's schema. Pluggable so callers can provide a
|
|
90
|
+
* dev-mode loader (Vite SSR) and prod uses the default (`dist/...json`).
|
|
91
|
+
*/
|
|
92
|
+
export type LoadSchemaFn = (collectionId: string) => Promise<Schema | null>;
|
|
93
|
+
export declare class SearchIndexService {
|
|
94
|
+
private readonly rootConfig;
|
|
95
|
+
private readonly projectId;
|
|
96
|
+
private readonly db;
|
|
97
|
+
private readonly loadSchema;
|
|
98
|
+
private readonly filters;
|
|
99
|
+
private cached;
|
|
100
|
+
constructor(rootConfig: RootConfig, loadSchema?: LoadSchemaFn, filtersOverride?: CMSSearchIndexConfig);
|
|
101
|
+
/** Returns true if the given collection passes the include/exclude filter. */
|
|
102
|
+
isCollectionIndexable(collectionId: string): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Returns true if the given doc id passes the include/exclude filter (and
|
|
105
|
+
* its collection is itself indexable). Doc ids are `<collectionId>/<slug>`.
|
|
106
|
+
*/
|
|
107
|
+
isDocIndexable(docId: string): boolean;
|
|
108
|
+
/** Returns the MiniSearch options used by both writers and readers. */
|
|
109
|
+
static getMiniSearchOptions(): {
|
|
110
|
+
fields: string[];
|
|
111
|
+
storeFields: string[];
|
|
112
|
+
searchOptions: {
|
|
113
|
+
boost: {
|
|
114
|
+
fieldLabel: number;
|
|
115
|
+
};
|
|
116
|
+
prefix: boolean;
|
|
117
|
+
fuzzy: number;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
private indexDocPath;
|
|
121
|
+
private indexCollectionPath;
|
|
122
|
+
/**
|
|
123
|
+
* Lists collection ids by globbing `<rootDir>/collections/*.schema.ts`,
|
|
124
|
+
* filtered by the include/exclude config.
|
|
125
|
+
*/
|
|
126
|
+
listCollectionIds(): Promise<string[]>;
|
|
127
|
+
/**
|
|
128
|
+
* Default schema loader: reads `dist/collections/<id>.schema.json`. These
|
|
129
|
+
* files are produced by the CMS plugin's `preBuild` hook during a real
|
|
130
|
+
* `root build`. In dev there is no JSON file on disk, so callers should
|
|
131
|
+
* pass a dev-aware `loadSchema` callback to the constructor (the API
|
|
132
|
+
* endpoints do this — they delegate to the same Vite SSR path used by
|
|
133
|
+
* `/cms/api/collection.get`).
|
|
134
|
+
*/
|
|
135
|
+
private loadCollectionSchemaFromDist;
|
|
136
|
+
private readMeta;
|
|
137
|
+
private readDocMap;
|
|
138
|
+
/** Reads all shard docs and returns the concatenated MiniSearch JSON string. */
|
|
139
|
+
private readShards;
|
|
140
|
+
/** Writes shards, _docMap, _meta in one batched commit. */
|
|
141
|
+
private writeIndex;
|
|
142
|
+
/** Drops every doc under the SearchIndex subcollection. */
|
|
143
|
+
private wipeIndex;
|
|
144
|
+
/**
|
|
145
|
+
* Lists the full set of live (collection, slug, doc) tuples for `Drafts`,
|
|
146
|
+
* filtered by the include/exclude config.
|
|
147
|
+
*/
|
|
148
|
+
private listAllDocs;
|
|
149
|
+
/**
|
|
150
|
+
* Lists docs modified since `lastRun` across every collection, filtered by
|
|
151
|
+
* the include/exclude config.
|
|
152
|
+
*/
|
|
153
|
+
private listChangedDocs;
|
|
154
|
+
/**
|
|
155
|
+
* Returns true when no docs have been modified since `lastRun` AND no
|
|
156
|
+
* deletions are pending (i.e. the doc-id set in `_docMap` matches the live
|
|
157
|
+
* doc-id set across all collections).
|
|
158
|
+
*/
|
|
159
|
+
hasChangesSince(lastRun: Timestamp, docMap?: DocMap | null): Promise<boolean>;
|
|
160
|
+
/** Orchestrates a rebuild (incremental by default; full when `force: true`). */
|
|
161
|
+
rebuildIndex(opts?: {
|
|
162
|
+
force?: boolean;
|
|
163
|
+
}): Promise<RebuildResult>;
|
|
164
|
+
private fullRebuild;
|
|
165
|
+
private incrementalRebuild;
|
|
166
|
+
/**
|
|
167
|
+
* Returns the cached MiniSearch index, loading it from Firestore if
|
|
168
|
+
* necessary. The cache is keyed off `meta.lastRun` and survives across
|
|
169
|
+
* requests in the same process.
|
|
170
|
+
*/
|
|
171
|
+
getIndex(): Promise<CachedIndex | null>;
|
|
172
|
+
/** Runs a query against the loaded index. */
|
|
173
|
+
search(q: string, options?: {
|
|
174
|
+
limit?: number;
|
|
175
|
+
}): Promise<{
|
|
176
|
+
hits: SearchHit[];
|
|
177
|
+
meta: SearchIndexStatus;
|
|
178
|
+
}>;
|
|
179
|
+
/** Lightweight metadata read for status endpoints / settings UI. */
|
|
180
|
+
getStatus(): Promise<SearchIndexStatus>;
|
|
181
|
+
}
|
|
182
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google-style query parsing and execution for the CMS search index.
|
|
3
|
+
*
|
|
4
|
+
* The CMS spotlight passes raw user input straight through to MiniSearch, which
|
|
5
|
+
* means quotes, leading dashes, and multiple words all get tokenized the same
|
|
6
|
+
* way (fuzzy + prefix on every term, OR-combined). That produces noisy results
|
|
7
|
+
* — typing `homepage hero` returns every doc containing `homepage` *or* a
|
|
8
|
+
* fuzzy/prefix match for `hero`.
|
|
9
|
+
*
|
|
10
|
+
* This module preprocesses the query string into structured parts and runs
|
|
11
|
+
* each part with the appropriate MiniSearch options:
|
|
12
|
+
*
|
|
13
|
+
* - `"exact phrase"` — must appear verbatim (token-aligned) in the doc;
|
|
14
|
+
* fuzzy + prefix disabled.
|
|
15
|
+
* - `bare term` — fuzzy + prefix allowed (existing behavior).
|
|
16
|
+
* - `-foo` / `-"x y"` — must NOT appear in matching docs.
|
|
17
|
+
*
|
|
18
|
+
* Multiple parts are AND-combined so adding more terms narrows results, just
|
|
19
|
+
* like Google.
|
|
20
|
+
*/
|
|
21
|
+
import MiniSearch, { SearchResult } from 'minisearch';
|
|
22
|
+
/** Structured form of a user query string. */
|
|
23
|
+
export interface ParsedQuery {
|
|
24
|
+
/** Quoted phrases that must appear verbatim (token-aligned). */
|
|
25
|
+
phrases: string[];
|
|
26
|
+
/** Free-form terms; fuzzy + prefix matching applies. */
|
|
27
|
+
terms: string[];
|
|
28
|
+
/** Bare terms that must NOT appear in matching docs. */
|
|
29
|
+
excluded: string[];
|
|
30
|
+
/** Quoted phrases that must NOT appear in matching docs. */
|
|
31
|
+
excludedPhrases: string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Splits a Google-style query string into phrases / terms / exclusions.
|
|
35
|
+
*
|
|
36
|
+
* Examples:
|
|
37
|
+
* `foo "bar baz" -qux` -> terms=[foo], phrases=[bar baz], excluded=[qux]
|
|
38
|
+
* `"exact phrase only"` -> phrases=[exact phrase only]
|
|
39
|
+
* `-"forbidden phrase"` -> excludedPhrases=[forbidden phrase]
|
|
40
|
+
*
|
|
41
|
+
* Notes:
|
|
42
|
+
* - Smart quotes (U+201C / U+201D / etc.) are normalized to straight `"`.
|
|
43
|
+
* - An unclosed quote is treated as if closed at end-of-input (matches
|
|
44
|
+
* Google's behavior — the rest of the query becomes a single phrase).
|
|
45
|
+
* - Empty or whitespace-only quotes (`""`, `" "`) are skipped.
|
|
46
|
+
* - A leading `-` only marks exclusion when followed by a non-whitespace
|
|
47
|
+
* character; standalone `-` is dropped.
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseQuery(input: string): ParsedQuery;
|
|
50
|
+
/**
|
|
51
|
+
* Returns true if `phrase` appears in `text` as a contiguous run of word
|
|
52
|
+
* tokens. Punctuation between tokens is ignored, but token boundaries are
|
|
53
|
+
* required (so `foo bar` does NOT match `foobar`).
|
|
54
|
+
*/
|
|
55
|
+
export declare function containsPhrase(text: string, phrase: string): boolean;
|
|
56
|
+
/** True if this parsed query carries no positive constraints. */
|
|
57
|
+
export declare function isEmptyQuery(parsed: ParsedQuery): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Runs a parsed query against a MiniSearch index using Google-style semantics:
|
|
60
|
+
* - phrases match as exact contiguous word runs (no fuzzy / no prefix);
|
|
61
|
+
* - free terms keep the index's default fuzzy + prefix behavior;
|
|
62
|
+
* - all positive parts are AND-combined (a doc must satisfy each one);
|
|
63
|
+
* - excluded terms / phrases remove docs from the result.
|
|
64
|
+
*
|
|
65
|
+
* Per-record scores from each part are summed, so a doc that matches more
|
|
66
|
+
* constraints ranks above one that matches fewer.
|
|
67
|
+
*/
|
|
68
|
+
export declare function executeQuery(index: MiniSearch, parsed: ParsedQuery): SearchResult[];
|