@extravirgin/payload-plugin-meilisearch 0.0.13 → 0.0.15
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/README.md +91 -1
- package/dist/index.d.ts +70 -1
- package/dist/index.js.map +1 -1
- package/dist/indexCollections.d.ts +9 -2
- package/dist/indexCollections.js +214 -25
- package/dist/indexCollections.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1 +1,91 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Payload Meilisearch plugin
|
|
2
|
+
|
|
3
|
+
## Indexing fields from relationships
|
|
4
|
+
|
|
5
|
+
Relationship fields are indexed as IDs by default. To make selected values from
|
|
6
|
+
the related documents searchable, configure `indexRelationshipFields`. The
|
|
7
|
+
relationship ID is retained alongside the selected fields.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
meilisearch({
|
|
11
|
+
apiKey: process.env.MEILISEARCH_API_KEY,
|
|
12
|
+
host: process.env.MEILISEARCH_HOST,
|
|
13
|
+
collections: [
|
|
14
|
+
{
|
|
15
|
+
slug: 'posts',
|
|
16
|
+
indexRelationshipFields: {
|
|
17
|
+
category: ['name'],
|
|
18
|
+
tags: ['name', 'slug'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
})
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
For example, a populated `category` relationship is indexed as:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
{
|
|
29
|
+
category: {
|
|
30
|
+
id: 'category-id',
|
|
31
|
+
name: 'Engineering',
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`hasMany` relationships produce an array of these objects. Polymorphic
|
|
37
|
+
relationships also retain `relationTo`. Both the relationship field key and
|
|
38
|
+
selected related field names support dot notation:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
indexRelationshipFields: {
|
|
42
|
+
'meta.category': ['name', 'seo.title'],
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The option can be set globally and overridden per collection. When it is
|
|
47
|
+
enabled, the plugin reads the source document at a depth of at least 1 so direct
|
|
48
|
+
relationship values are populated. Changes to a related document do not by
|
|
49
|
+
themselves run the source collection's hooks; reindex the source collection
|
|
50
|
+
when those values change.
|
|
51
|
+
|
|
52
|
+
## Indexing localized select labels
|
|
53
|
+
|
|
54
|
+
Select values remain unchanged and can still be used for filtering. To also make
|
|
55
|
+
their option labels searchable, enable `indexSelectLabels`. The label is added
|
|
56
|
+
to a sibling field with the `_label` suffix.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
meilisearch({
|
|
60
|
+
apiKey: process.env.MEILISEARCH_API_KEY,
|
|
61
|
+
host: process.env.MEILISEARCH_HOST,
|
|
62
|
+
collections: [{ slug: 'products' }],
|
|
63
|
+
indexSelectLabels: true,
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
For a document locale such as `en-US`, labels are tried in this order:
|
|
68
|
+
`en-US`, `en`, then Payload's i18n fallback language. The behavior can be
|
|
69
|
+
configured globally or overridden per collection:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
meilisearch({
|
|
73
|
+
// ...
|
|
74
|
+
collections: [
|
|
75
|
+
{
|
|
76
|
+
slug: 'products',
|
|
77
|
+
indexSelectLabels: {
|
|
78
|
+
defaultLocale: 'de',
|
|
79
|
+
fieldSuffix: '_optionLabel',
|
|
80
|
+
resolveLabel: ({ defaultLabel, option, localeFallbacks }) => {
|
|
81
|
+
// Useful for function labels or application-specific translations.
|
|
82
|
+
return defaultLabel
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Returning `undefined` from `resolveLabel` keeps the built-in result. Returning
|
|
91
|
+
`null` omits the label.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
|
-
import type { Config, PayloadRequest } from 'payload';
|
|
1
|
+
import type { Config, Option, PayloadRequest, SelectField } from 'payload';
|
|
2
|
+
export type ResolveSelectLabelArgs = {
|
|
3
|
+
/**
|
|
4
|
+
* Label resolved by the plugin. This is undefined for label functions and
|
|
5
|
+
* when none of the configured locale fallbacks matched.
|
|
6
|
+
*/
|
|
7
|
+
defaultLabel?: string;
|
|
8
|
+
field: SelectField;
|
|
9
|
+
locale?: string;
|
|
10
|
+
localeFallbacks: string[];
|
|
11
|
+
option: Option;
|
|
12
|
+
req: PayloadRequest;
|
|
13
|
+
value: string;
|
|
14
|
+
};
|
|
15
|
+
export type IndexSelectLabelsConfig = {
|
|
16
|
+
/**
|
|
17
|
+
* Locale used after progressively less-specific variants of the document
|
|
18
|
+
* locale have been tried. Defaults to Payload's i18n fallback language.
|
|
19
|
+
*/
|
|
20
|
+
defaultLocale?: string;
|
|
21
|
+
/**
|
|
22
|
+
* The indexed label is stored in a sibling field named
|
|
23
|
+
* `${field.name}${fieldSuffix}`.
|
|
24
|
+
*
|
|
25
|
+
* @default '_label'
|
|
26
|
+
*/
|
|
27
|
+
fieldSuffix?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Override or provide a label. Returning undefined uses defaultLabel;
|
|
30
|
+
* returning null omits the label from the index.
|
|
31
|
+
*/
|
|
32
|
+
resolveLabel?: (args: ResolveSelectLabelArgs) => null | Promise<null | string | undefined> | string | undefined;
|
|
33
|
+
};
|
|
34
|
+
export type IndexSelectLabels = boolean | IndexSelectLabelsConfig;
|
|
35
|
+
/**
|
|
36
|
+
* Relationship field paths mapped to the fields that should be copied from
|
|
37
|
+
* populated related documents.
|
|
38
|
+
*
|
|
39
|
+
* Both relationship field paths and related document field paths support dot
|
|
40
|
+
* notation.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* {
|
|
44
|
+
* category: ['name'],
|
|
45
|
+
* 'meta.tags': ['name', 'slug'],
|
|
46
|
+
* }
|
|
47
|
+
*/
|
|
48
|
+
export type IndexRelationshipFields = Record<string, readonly string[]>;
|
|
2
49
|
export interface PluginCollectionConfig {
|
|
50
|
+
/**
|
|
51
|
+
* Overrides the plugin-level relationship field indexing setting for this
|
|
52
|
+
* collection.
|
|
53
|
+
*/
|
|
54
|
+
indexRelationshipFields?: IndexRelationshipFields;
|
|
55
|
+
/**
|
|
56
|
+
* Overrides the plugin-level select label indexing setting for this
|
|
57
|
+
* collection.
|
|
58
|
+
*/
|
|
59
|
+
indexSelectLabels?: IndexSelectLabels;
|
|
3
60
|
shouldIndex?: (doc: object, previousDoc: object, locale?: string) => 'delete' | 'ignore' | 'index';
|
|
4
61
|
slug: string;
|
|
5
62
|
}
|
|
@@ -12,6 +69,18 @@ export type MeilisearchConfig = {
|
|
|
12
69
|
disabled?: boolean;
|
|
13
70
|
host: string;
|
|
14
71
|
indexPrefix?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Copy selected fields from populated relationship documents into the
|
|
74
|
+
* indexed relationship value. Unconfigured relationships remain ID-only.
|
|
75
|
+
*/
|
|
76
|
+
indexRelationshipFields?: IndexRelationshipFields;
|
|
77
|
+
/**
|
|
78
|
+
* Index select option labels in addition to their stored values.
|
|
79
|
+
*
|
|
80
|
+
* Set to true to use the defaults, or pass an object to configure locale
|
|
81
|
+
* fallback, the label field suffix, or a custom label resolver.
|
|
82
|
+
*/
|
|
83
|
+
indexSelectLabels?: IndexSelectLabels;
|
|
15
84
|
reindexPermissionCallback?: (req: PayloadRequest) => boolean;
|
|
16
85
|
};
|
|
17
86
|
export declare const meilisearch: (pluginOptions: MeilisearchConfig) => (config: Config) => Config;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Config, PayloadRequest } from 'payload'\n\nimport { indexCollection, reindexCollection } from './indexCollections.js'\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Config, Option, PayloadRequest, SelectField } from 'payload'\n\nimport { indexCollection, reindexCollection } from './indexCollections.js'\n\nexport type ResolveSelectLabelArgs = {\n /**\n * Label resolved by the plugin. This is undefined for label functions and\n * when none of the configured locale fallbacks matched.\n */\n defaultLabel?: string\n field: SelectField\n locale?: string\n localeFallbacks: string[]\n option: Option\n req: PayloadRequest\n value: string\n}\n\nexport type IndexSelectLabelsConfig = {\n /**\n * Locale used after progressively less-specific variants of the document\n * locale have been tried. Defaults to Payload's i18n fallback language.\n */\n defaultLocale?: string\n /**\n * The indexed label is stored in a sibling field named\n * `${field.name}${fieldSuffix}`.\n *\n * @default '_label'\n */\n fieldSuffix?: string\n /**\n * Override or provide a label. Returning undefined uses defaultLabel;\n * returning null omits the label from the index.\n */\n resolveLabel?: (\n args: ResolveSelectLabelArgs,\n ) => null | Promise<null | string | undefined> | string | undefined\n}\n\nexport type IndexSelectLabels = boolean | IndexSelectLabelsConfig\n\n/**\n * Relationship field paths mapped to the fields that should be copied from\n * populated related documents.\n *\n * Both relationship field paths and related document field paths support dot\n * notation.\n *\n * @example\n * {\n * category: ['name'],\n * 'meta.tags': ['name', 'slug'],\n * }\n */\nexport type IndexRelationshipFields = Record<string, readonly string[]>\n\nexport interface PluginCollectionConfig {\n /**\n * Overrides the plugin-level relationship field indexing setting for this\n * collection.\n */\n indexRelationshipFields?: IndexRelationshipFields\n /**\n * Overrides the plugin-level select label indexing setting for this\n * collection.\n */\n indexSelectLabels?: IndexSelectLabels\n shouldIndex?: (\n doc: object,\n previousDoc: object,\n locale?: string,\n ) => 'delete' | 'ignore' | 'index'\n slug: string\n}\n\nexport type MeilisearchConfig = {\n apiKey: string\n /**\n * List of collections to add a custom field\n */\n collections?: PluginCollectionConfig[]\n disabled?: boolean\n host: string\n indexPrefix?: string\n /**\n * Copy selected fields from populated relationship documents into the\n * indexed relationship value. Unconfigured relationships remain ID-only.\n */\n indexRelationshipFields?: IndexRelationshipFields\n /**\n * Index select option labels in addition to their stored values.\n *\n * Set to true to use the defaults, or pass an object to configure locale\n * fallback, the label field suffix, or a custom label resolver.\n */\n indexSelectLabels?: IndexSelectLabels\n reindexPermissionCallback?: (req: PayloadRequest) => boolean\n}\n\nexport const meilisearch =\n (pluginOptions: MeilisearchConfig) =>\n (config: Config): Config => {\n if (!config.collections) {\n config.collections = []\n }\n\n\n if (pluginOptions.disabled) {\n return config\n }\n\n if (pluginOptions.collections) {\n\n for (const { slug } of pluginOptions.collections) {\n const collection = config.collections.find(\n (collection) => collection.slug === slug,\n )\n\n if (collection) {\n indexCollection(collection, pluginOptions)\n }\n }\n }\n\n if (!config.endpoints) {\n config.endpoints = []\n }\n\n config.endpoints.push({\n handler: async (req) => {\n\n if (!pluginOptions.reindexPermissionCallback || pluginOptions.reindexPermissionCallback(req)) {\n for (const c of pluginOptions.collections ?? []) {\n const collection = req.payload.config.collections.find(\n (collection) => collection.slug === c.slug,\n )\n if (collection) {\n await reindexCollection(collection, pluginOptions, req)\n }\n }\n return Response.json({ message: 'sucessfully started indexing' })\n } else {\n return Response.json({ message: 'not allowed' }, {\n status: 403\n })\n\n }\n\n },\n method: 'get',\n path: '/reindex-meilisearch',\n })\n\n\n return config\n }\n"],"names":["indexCollection","reindexCollection","meilisearch","pluginOptions","config","collections","disabled","slug","collection","find","endpoints","push","handler","req","reindexPermissionCallback","c","payload","Response","json","message","status","method","path"],"mappings":"AAEA,SAASA,eAAe,EAAEC,iBAAiB,QAAQ,wBAAuB;AAkG1E,OAAO,MAAMC,cACX,CAACC,gBACC,CAACC;QACC,IAAI,CAACA,OAAOC,WAAW,EAAE;YACvBD,OAAOC,WAAW,GAAG,EAAE;QACzB;QAGA,IAAIF,cAAcG,QAAQ,EAAE;YAC1B,OAAOF;QACT;QAEA,IAAID,cAAcE,WAAW,EAAE;YAE7B,KAAK,MAAM,EAAEE,IAAI,EAAE,IAAIJ,cAAcE,WAAW,CAAE;gBAChD,MAAMG,aAAaJ,OAAOC,WAAW,CAACI,IAAI,CACxC,CAACD,aAAeA,WAAWD,IAAI,KAAKA;gBAGtC,IAAIC,YAAY;oBACdR,gBAAgBQ,YAAYL;gBAC9B;YACF;QACF;QAEA,IAAI,CAACC,OAAOM,SAAS,EAAE;YACrBN,OAAOM,SAAS,GAAG,EAAE;QACvB;QAEAN,OAAOM,SAAS,CAACC,IAAI,CAAC;YACpBC,SAAS,OAAOC;gBAEd,IAAI,CAACV,cAAcW,yBAAyB,IAAIX,cAAcW,yBAAyB,CAACD,MAAM;oBAC5F,KAAK,MAAME,KAAKZ,cAAcE,WAAW,IAAI,EAAE,CAAE;wBAC/C,MAAMG,aAAaK,IAAIG,OAAO,CAACZ,MAAM,CAACC,WAAW,CAACI,IAAI,CACpD,CAACD,aAAeA,WAAWD,IAAI,KAAKQ,EAAER,IAAI;wBAE5C,IAAIC,YAAY;4BACd,MAAMP,kBAAkBO,YAAYL,eAAeU;wBACrD;oBACF;oBACA,OAAOI,SAASC,IAAI,CAAC;wBAAEC,SAAS;oBAA+B;gBACjE,OAAO;oBACL,OAAOF,SAASC,IAAI,CAAC;wBAAEC,SAAS;oBAAc,GAAG;wBAC/CC,QAAQ;oBACV;gBAEF;YAEF;YACAC,QAAQ;YACRC,MAAM;QACR;QAGA,OAAOlB;IACT,EAAC"}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import type { CollectionConfig, PayloadRequest, SanitizedCollectionConfig } from "payload";
|
|
2
|
-
import type { MeilisearchConfig } from "./index.js";
|
|
1
|
+
import type { CollectionConfig, Field, PayloadRequest, SanitizedCollectionConfig } from "payload";
|
|
2
|
+
import type { IndexRelationshipFields, IndexSelectLabels, MeilisearchConfig } from "./index.js";
|
|
3
3
|
export declare const reindexCollection: (collection: SanitizedCollectionConfig, config: MeilisearchConfig, req: PayloadRequest) => Promise<void>;
|
|
4
4
|
export declare const indexCollection: (collection: CollectionConfig, config: MeilisearchConfig) => void;
|
|
5
|
+
export type TransformOptions = {
|
|
6
|
+
indexRelationshipFields?: IndexRelationshipFields;
|
|
7
|
+
indexSelectLabels?: IndexSelectLabels;
|
|
8
|
+
locale?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const getSelectLabelLocaleFallbacks: (locale: string | undefined, defaultLocale: string | undefined) => string[];
|
|
11
|
+
export declare function transformDocumentForMeilisearch(doc: any, fields: Field[], req: PayloadRequest, options?: TransformOptions, parentPath?: string): Promise<any>;
|
package/dist/indexCollections.js
CHANGED
|
@@ -47,6 +47,7 @@ const processDocument = async (doc, previousDoc, collection, config, req)=>{
|
|
|
47
47
|
}
|
|
48
48
|
const baseDoc = doc;
|
|
49
49
|
const collectionConfig = config.collections && config?.collections.find((c)=>c.slug === collection.slug);
|
|
50
|
+
const indexRelationshipFields = collectionConfig?.indexRelationshipFields ?? config.indexRelationshipFields;
|
|
50
51
|
const payload = req.payload;
|
|
51
52
|
const client = getMeilisearchClient(config);
|
|
52
53
|
await upsertIndex(client, getIndexName(config, collection.slug));
|
|
@@ -58,6 +59,7 @@ const processDocument = async (doc, previousDoc, collection, config, req)=>{
|
|
|
58
59
|
const localizedDoc = await req.payload.findByID({
|
|
59
60
|
id: doc.id,
|
|
60
61
|
collection: collection.slug,
|
|
62
|
+
depth: indexRelationshipFields ? Math.max(payload.config.defaultDepth ?? 2, 1) : undefined,
|
|
61
63
|
draft: false,
|
|
62
64
|
fallbackLocale: locale.fallbackLocale || defaultLocale,
|
|
63
65
|
locale: locale.code,
|
|
@@ -71,7 +73,11 @@ const processDocument = async (doc, previousDoc, collection, config, req)=>{
|
|
|
71
73
|
const shouldIndex = collectionConfig?.shouldIndex?.(localizedDoc, previousDoc, locale.code) ?? 'index';
|
|
72
74
|
if (shouldIndex === 'index') {
|
|
73
75
|
const transformedDoc = {
|
|
74
|
-
...await transformDocumentForMeilisearch(localizedDoc, collection.fields, req
|
|
76
|
+
...await transformDocumentForMeilisearch(localizedDoc, collection.fields, req, {
|
|
77
|
+
indexRelationshipFields,
|
|
78
|
+
indexSelectLabels: collectionConfig?.indexSelectLabels ?? config.indexSelectLabels,
|
|
79
|
+
locale: locale.code
|
|
80
|
+
}),
|
|
75
81
|
id: documentId,
|
|
76
82
|
documentId: doc.id,
|
|
77
83
|
locale: locale.code
|
|
@@ -86,10 +92,20 @@ const processDocument = async (doc, previousDoc, collection, config, req)=>{
|
|
|
86
92
|
}
|
|
87
93
|
} else {
|
|
88
94
|
const documentId = doc.id;
|
|
89
|
-
const
|
|
95
|
+
const document = indexRelationshipFields ? await req.payload.findByID({
|
|
96
|
+
id: doc.id,
|
|
97
|
+
collection: collection.slug,
|
|
98
|
+
depth: Math.max(payload.config.defaultDepth ?? 2, 1),
|
|
99
|
+
draft: false,
|
|
100
|
+
overrideAccess: true
|
|
101
|
+
}) : doc;
|
|
102
|
+
const shouldIndex = collectionConfig?.shouldIndex?.(document, previousDoc) ?? 'index';
|
|
90
103
|
if (shouldIndex === 'index') {
|
|
91
104
|
const transformedDoc = {
|
|
92
|
-
...await transformDocumentForMeilisearch(
|
|
105
|
+
...await transformDocumentForMeilisearch(document, collection.fields, req, {
|
|
106
|
+
indexRelationshipFields,
|
|
107
|
+
indexSelectLabels: collectionConfig?.indexSelectLabels ?? config.indexSelectLabels
|
|
108
|
+
}),
|
|
93
109
|
id: documentId,
|
|
94
110
|
documentId: doc.id
|
|
95
111
|
};
|
|
@@ -179,11 +195,175 @@ const compiledConvert = compile(options);
|
|
|
179
195
|
function extractTextFromHTML(html) {
|
|
180
196
|
return compiledConvert(html);
|
|
181
197
|
}
|
|
198
|
+
const normalizeLocale = (locale)=>locale.replaceAll('_', '-').toLowerCase();
|
|
199
|
+
export const getSelectLabelLocaleFallbacks = (locale, defaultLocale)=>{
|
|
200
|
+
const fallbacks = [];
|
|
201
|
+
const addLocaleAndParents = (value)=>{
|
|
202
|
+
if (!value) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const parts = value.replaceAll('_', '-').split('-').filter(Boolean);
|
|
206
|
+
while(parts.length > 0){
|
|
207
|
+
const candidate = parts.join('-');
|
|
208
|
+
if (!fallbacks.some((item)=>normalizeLocale(item) === normalizeLocale(candidate))) {
|
|
209
|
+
fallbacks.push(candidate);
|
|
210
|
+
}
|
|
211
|
+
parts.pop();
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
addLocaleAndParents(locale);
|
|
215
|
+
addLocaleAndParents(defaultLocale);
|
|
216
|
+
return fallbacks;
|
|
217
|
+
};
|
|
218
|
+
const getDefaultSelectLabel = (option, localeFallbacks)=>{
|
|
219
|
+
if (typeof option === 'string') {
|
|
220
|
+
return option;
|
|
221
|
+
}
|
|
222
|
+
if (typeof option.label === 'string') {
|
|
223
|
+
return option.label;
|
|
224
|
+
}
|
|
225
|
+
if (typeof option.label === 'function') {
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
for (const locale of localeFallbacks){
|
|
229
|
+
const matchingKey = Object.keys(option.label).find((key)=>normalizeLocale(key) === normalizeLocale(locale));
|
|
230
|
+
if (matchingKey && option.label[matchingKey]) {
|
|
231
|
+
return option.label[matchingKey];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return undefined;
|
|
235
|
+
};
|
|
236
|
+
const getSelectedOption = (field, value)=>field.options.find((option)=>typeof option === 'string' ? option === value : option.value === value);
|
|
237
|
+
const transformSelectLabels = async ({ field, locale, options, req, value })=>{
|
|
238
|
+
const defaultLocale = options.defaultLocale ?? req.payload.config.i18n.fallbackLanguage;
|
|
239
|
+
const localeFallbacks = getSelectLabelLocaleFallbacks(locale, defaultLocale);
|
|
240
|
+
const resolveValue = async (selectedValue)=>{
|
|
241
|
+
if (typeof selectedValue !== 'string') {
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
const option = getSelectedOption(field, selectedValue);
|
|
245
|
+
if (!option) {
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
248
|
+
const defaultLabel = getDefaultSelectLabel(option, localeFallbacks);
|
|
249
|
+
if (!options.resolveLabel) {
|
|
250
|
+
return defaultLabel;
|
|
251
|
+
}
|
|
252
|
+
const resolvedLabel = await options.resolveLabel({
|
|
253
|
+
defaultLabel,
|
|
254
|
+
field,
|
|
255
|
+
locale,
|
|
256
|
+
localeFallbacks,
|
|
257
|
+
option,
|
|
258
|
+
req,
|
|
259
|
+
value: selectedValue
|
|
260
|
+
});
|
|
261
|
+
return resolvedLabel === undefined ? defaultLabel : resolvedLabel ?? undefined;
|
|
262
|
+
};
|
|
263
|
+
if (Array.isArray(value)) {
|
|
264
|
+
const labels = (await Promise.all(value.map(resolveValue))).filter((label)=>typeof label === 'string');
|
|
265
|
+
return labels.length > 0 ? labels : undefined;
|
|
266
|
+
}
|
|
267
|
+
return resolveValue(value);
|
|
268
|
+
};
|
|
269
|
+
const joinFieldPath = (parentPath, fieldName)=>parentPath ? `${parentPath}.${fieldName}` : fieldName;
|
|
270
|
+
const isRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
271
|
+
const unsafePathSegments = new Set([
|
|
272
|
+
'__proto__',
|
|
273
|
+
'constructor',
|
|
274
|
+
'prototype'
|
|
275
|
+
]);
|
|
276
|
+
const getValueAtPath = (value, path)=>{
|
|
277
|
+
const segments = path.split('.').filter(Boolean);
|
|
278
|
+
let current = value;
|
|
279
|
+
for (const segment of segments){
|
|
280
|
+
if (unsafePathSegments.has(segment) || !isRecord(current)) {
|
|
281
|
+
return undefined;
|
|
282
|
+
}
|
|
283
|
+
current = current[segment];
|
|
284
|
+
}
|
|
285
|
+
return current;
|
|
286
|
+
};
|
|
287
|
+
const setValueAtPath = (target, path, value)=>{
|
|
288
|
+
const segments = path.split('.').filter(Boolean);
|
|
289
|
+
if (segments.length === 0 || segments.some((segment)=>unsafePathSegments.has(segment))) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
let current = target;
|
|
293
|
+
for (const [index, segment] of segments.entries()){
|
|
294
|
+
if (index === segments.length - 1) {
|
|
295
|
+
current[segment] = value;
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const nestedValue = current[segment];
|
|
299
|
+
if (isRecord(nestedValue)) {
|
|
300
|
+
current = nestedValue;
|
|
301
|
+
} else {
|
|
302
|
+
const nestedTarget = {};
|
|
303
|
+
current[segment] = nestedTarget;
|
|
304
|
+
current = nestedTarget;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
const selectRelatedDocumentFields = (relatedDocument, fieldPaths)=>{
|
|
309
|
+
if (!isRecord(relatedDocument)) {
|
|
310
|
+
return {};
|
|
311
|
+
}
|
|
312
|
+
const selected = {};
|
|
313
|
+
for (const fieldPath of fieldPaths){
|
|
314
|
+
const value = getValueAtPath(relatedDocument, fieldPath);
|
|
315
|
+
if (value !== undefined) {
|
|
316
|
+
setValueAtPath(selected, fieldPath, value);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return selected;
|
|
320
|
+
};
|
|
321
|
+
const getRelationshipID = (value, fallbackToValue)=>{
|
|
322
|
+
if (!isRecord(value)) {
|
|
323
|
+
return fallbackToValue ? value ?? '' : '';
|
|
324
|
+
}
|
|
325
|
+
if (value.id !== undefined) {
|
|
326
|
+
return value.id;
|
|
327
|
+
}
|
|
328
|
+
return fallbackToValue ? value : value.value ?? '';
|
|
329
|
+
};
|
|
330
|
+
const getPolymorphicRelationshipID = (value)=>{
|
|
331
|
+
if (!isRecord(value)) {
|
|
332
|
+
return '';
|
|
333
|
+
}
|
|
334
|
+
return isRecord(value.value) ? value.value.id ?? '' : value.value ?? '';
|
|
335
|
+
};
|
|
336
|
+
const getRelatedDocument = (value)=>{
|
|
337
|
+
if (!isRecord(value)) {
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
return isRecord(value.value) ? value.value : value;
|
|
341
|
+
};
|
|
342
|
+
const transformRelationshipValue = (value, selectedFieldPaths, fallbackToValue = false)=>{
|
|
343
|
+
const id = getRelationshipID(value, fallbackToValue);
|
|
344
|
+
if (!selectedFieldPaths) {
|
|
345
|
+
return id;
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
...selectRelatedDocumentFields(getRelatedDocument(value), selectedFieldPaths),
|
|
349
|
+
id
|
|
350
|
+
};
|
|
351
|
+
};
|
|
352
|
+
const transformPolymorphicRelationshipValue = (value, selectedFieldPaths)=>{
|
|
353
|
+
const relationship = isRecord(value) ? value : {};
|
|
354
|
+
const transformed = selectedFieldPaths ? selectRelatedDocumentFields(getRelatedDocument(value), selectedFieldPaths) : {};
|
|
355
|
+
return {
|
|
356
|
+
...transformed,
|
|
357
|
+
id: getPolymorphicRelationshipID(value),
|
|
358
|
+
relationTo: relationship.relationTo ?? ''
|
|
359
|
+
};
|
|
360
|
+
};
|
|
182
361
|
// Helper function to transform a document for Meilisearch indexing
|
|
183
|
-
async function transformDocumentForMeilisearch(doc, fields, req) {
|
|
362
|
+
export async function transformDocumentForMeilisearch(doc, fields, req, options = {}, parentPath = '') {
|
|
184
363
|
const transformedDoc = {};
|
|
185
364
|
await Promise.all(fields.map(async (field)=>{
|
|
186
365
|
try {
|
|
366
|
+
const fieldPath = 'name' in field && field.name ? joinFieldPath(parentPath, field.name) : parentPath;
|
|
187
367
|
if (field.type === 'richText') {
|
|
188
368
|
// For rich text fields, convert Lexical to HTML, then extract text
|
|
189
369
|
const lexicalAdapter = field.editor;
|
|
@@ -197,16 +377,16 @@ async function transformDocumentForMeilisearch(doc, fields, req) {
|
|
|
197
377
|
transformedDoc[field.name] = extractTextFromHTML(html);
|
|
198
378
|
} else if (field.type === 'array' && field.fields) {
|
|
199
379
|
// For array fields, transform each item
|
|
200
|
-
transformedDoc[field.name] = await Promise.all((doc[field.name] || []).map((item)=>transformDocumentForMeilisearch(item, field.fields, req)));
|
|
380
|
+
transformedDoc[field.name] = await Promise.all((doc[field.name] || []).map((item)=>transformDocumentForMeilisearch(item, field.fields, req, options, fieldPath)));
|
|
201
381
|
} else if (field.type === 'tabs') {
|
|
202
382
|
// For tab fields, transform each tab
|
|
203
383
|
(await Promise.all(field.tabs.map(async (tab)=>{
|
|
204
384
|
if ('name' in tab && tab.name) {
|
|
205
385
|
return {
|
|
206
|
-
[tab.name]: await transformDocumentForMeilisearch(doc?.[tab.name] ?? {}, tab.fields, req)
|
|
386
|
+
[tab.name]: await transformDocumentForMeilisearch(doc?.[tab.name] ?? {}, tab.fields, req, options, joinFieldPath(parentPath, tab.name))
|
|
207
387
|
};
|
|
208
388
|
}
|
|
209
|
-
return await transformDocumentForMeilisearch(doc, tab.fields, req);
|
|
389
|
+
return await transformDocumentForMeilisearch(doc, tab.fields, req, options, parentPath);
|
|
210
390
|
}))).forEach((t)=>Object.assign(transformedDoc, t));
|
|
211
391
|
} else if (field.type === 'blocks') {
|
|
212
392
|
// For block fields, transform each block
|
|
@@ -220,36 +400,45 @@ async function transformDocumentForMeilisearch(doc, fields, req) {
|
|
|
220
400
|
}
|
|
221
401
|
return {
|
|
222
402
|
type: block.blockType,
|
|
223
|
-
data: await transformDocumentForMeilisearch(block, fields, req)
|
|
403
|
+
data: await transformDocumentForMeilisearch(block, fields, req, options, fieldPath)
|
|
224
404
|
};
|
|
225
405
|
}));
|
|
406
|
+
} else if (field.type === 'select') {
|
|
407
|
+
transformedDoc[field.name] = doc[field.name];
|
|
408
|
+
if (options.indexSelectLabels) {
|
|
409
|
+
const selectLabelOptions = options.indexSelectLabels === true ? {} : options.indexSelectLabels;
|
|
410
|
+
const label = await transformSelectLabels({
|
|
411
|
+
field,
|
|
412
|
+
locale: options.locale,
|
|
413
|
+
options: selectLabelOptions,
|
|
414
|
+
req,
|
|
415
|
+
value: doc[field.name]
|
|
416
|
+
});
|
|
417
|
+
if (label !== undefined) {
|
|
418
|
+
transformedDoc[`${field.name}${selectLabelOptions.fieldSuffix ?? '_label'}`] = label;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
226
421
|
} else if (field.type === 'radio') {
|
|
227
422
|
transformedDoc[field.name] = doc[field.name];
|
|
228
423
|
} else if (field.type === 'group' && field.name && field.fields) {
|
|
229
424
|
// For group fields, transform the nested fields
|
|
230
|
-
transformedDoc[field.name] = await transformDocumentForMeilisearch(doc[field.name], field.fields, req);
|
|
425
|
+
transformedDoc[field.name] = await transformDocumentForMeilisearch(doc[field.name], field.fields, req, options, fieldPath);
|
|
231
426
|
} else if (field.type === 'group' && !field.name && field.fields) {
|
|
232
|
-
Object.assign(transformedDoc, await transformDocumentForMeilisearch(doc, field.fields, req));
|
|
427
|
+
Object.assign(transformedDoc, await transformDocumentForMeilisearch(doc, field.fields, req, options, parentPath));
|
|
233
428
|
} else if ((field.type === 'row' || field.type === 'collapsible') && field.fields) {
|
|
234
|
-
Object.assign(transformedDoc, await transformDocumentForMeilisearch(doc, field.fields, req));
|
|
429
|
+
Object.assign(transformedDoc, await transformDocumentForMeilisearch(doc, field.fields, req, options, parentPath));
|
|
235
430
|
} else if (field.type === 'relationship' && Array.isArray(field.relationTo) && field.hasMany) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
id: relatedDoc?.value?.id ?? relatedDoc?.value ?? '',
|
|
239
|
-
relationTo: relatedDoc?.relationTo ?? ''
|
|
240
|
-
};
|
|
241
|
-
}) ?? [];
|
|
431
|
+
const selectedFieldPaths = options.indexRelationshipFields?.[fieldPath];
|
|
432
|
+
transformedDoc[field.name] = doc[field.name]?.map((relatedDoc)=>transformPolymorphicRelationshipValue(relatedDoc, selectedFieldPaths)) ?? [];
|
|
242
433
|
} else if (field.type === 'relationship' && Array.isArray(field.relationTo) && !field.hasMany) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
relationTo: doc?.[field.name]?.relationTo ?? ''
|
|
246
|
-
};
|
|
434
|
+
const selectedFieldPaths = options.indexRelationshipFields?.[fieldPath];
|
|
435
|
+
transformedDoc[field.name] = transformPolymorphicRelationshipValue(doc?.[field.name], selectedFieldPaths);
|
|
247
436
|
} else if (field.type === 'relationship' && !Array.isArray(field.relationTo) && field.hasMany) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}) ?? [];
|
|
437
|
+
const selectedFieldPaths = options.indexRelationshipFields?.[fieldPath];
|
|
438
|
+
transformedDoc[field.name] = doc[field.name]?.map((relatedDoc)=>transformRelationshipValue(relatedDoc, selectedFieldPaths)) ?? [];
|
|
251
439
|
} else if (field.type === 'relationship' && !Array.isArray(field.relationTo) && !field.hasMany) {
|
|
252
|
-
|
|
440
|
+
const selectedFieldPaths = options.indexRelationshipFields?.[fieldPath];
|
|
441
|
+
transformedDoc[field.name] = transformRelationshipValue(doc?.[field.name], selectedFieldPaths, true);
|
|
253
442
|
} else if (field.type === 'relationship' || field.type === 'upload') {
|
|
254
443
|
// For relationship and upload fields, just include the ID
|
|
255
444
|
transformedDoc[field.name] = doc[field.name]?.id || doc[field.name];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/indexCollections.ts"],"sourcesContent":["import type {\n LexicalRichTextAdapter,\n SanitizedServerEditorConfig\n} from '@payloadcms/richtext-lexical';\nimport type { Block, CollectionAfterChangeHook, CollectionAfterDeleteHook, CollectionConfig, Field, Payload, PayloadRequest, SanitizedCollectionConfig, Tab } from \"payload\";\n\nimport {\n consolidateHTMLConverters,\n convertLexicalToHTML,\n} from '@payloadcms/richtext-lexical';\nimport { compile } from 'html-to-text';\nimport { MeiliSearch } from 'meilisearch';\n\nimport type { MeilisearchConfig } from \"./index.js\";\n\n\nconst getIndexName = (config: MeilisearchConfig, collectionSlug: string) => `${config?.indexPrefix ?? ''}${collectionSlug}`;\n\nexport const reindexCollection = async (collection: SanitizedCollectionConfig, config: MeilisearchConfig, req: PayloadRequest) => {\n\n req.context.meiliSkipDelay = true;\n\n const entries = await req.payload.find({\n collection: collection.slug,\n draft: false,\n pagination: false,\n select: {\n id: true,\n },\n });\n\n const client = getMeilisearchClient(config);\n await upsertIndex(client, getIndexName(config, collection.slug));\n const index = client.index(getIndexName(config, collection.slug));\n\n await index.deleteAllDocuments();\n\n\n for (const entry of entries.docs) {\n await handleAfterChange(config)({\n collection,\n context: req.context,\n doc: entry,\n operation: \"update\",\n previousDoc: null,\n req,\n })\n }\n}\n\nexport const indexCollection = (collection: CollectionConfig, config: MeilisearchConfig) => {\n\n if (!collection.hooks) {\n collection.hooks = {};\n }\n\n if (!collection.hooks.afterChange) {\n collection.hooks.afterChange = [];\n }\n\n collection.hooks.afterChange.push(handleAfterChange(config));\n\n if (!collection.hooks.afterDelete) {\n collection.hooks.afterDelete = [];\n }\n\n collection.hooks.afterDelete.push(afterDeleteHook(config));\n}\n\nconst processDocument = async (doc: any, previousDoc: any, collection: CollectionConfig, config: MeilisearchConfig, req: PayloadRequest) => {\n\n // wait for 50ms to allow for the document to be saved to the database to make things more reliable\n if (!req.context?.meiliSkipDelay) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n\n const baseDoc = doc;\n const collectionConfig = config.collections && config?.collections.find(c => c.slug === collection.slug);\n\n const payload: Payload = req.payload;\n\n const client = getMeilisearchClient(config);\n await upsertIndex(client, getIndexName(config, collection.slug));\n const index = client.index(getIndexName(config, collection.slug));\n\n const documents = [];\n\n if (payload.config?.localization && payload.config.localization.locales?.length > 0) {\n\n const {\n defaultLocale,\n fallback,\n locales,\n } = payload.config.localization;\n\n for (const locale of locales) {\n\n const localizedDoc = await req.payload.findByID({\n id: doc.id,\n collection: collection.slug,\n draft: false,\n fallbackLocale: locale.fallbackLocale || defaultLocale,\n locale: locale.code,\n overrideAccess: true,\n });\n\n const documentId = doc.id + `_${locale.code}`;\n\n if (!localizedDoc) {\n await index.deleteDocument(documentId);\n continue;\n }\n const shouldIndex = collectionConfig?.shouldIndex?.(localizedDoc, previousDoc, locale.code) ?? 'index'\n if (shouldIndex === 'index') {\n const transformedDoc = {\n ...await transformDocumentForMeilisearch(localizedDoc, collection.fields, req),\n id: documentId,\n documentId: doc.id,\n locale: locale.code,\n };\n documents.push(transformedDoc);\n } else if (shouldIndex === 'delete') {\n await index.deleteDocument(documentId);\n }\n\n }\n\n if (documents.length > 0) {\n await index.addDocuments(documents);\n }\n } else {\n const documentId = doc.id;\n const shouldIndex = collectionConfig?.shouldIndex?.(doc, previousDoc) ?? 'index'\n if (shouldIndex === 'index') {\n const transformedDoc = {\n ...await transformDocumentForMeilisearch(doc, collection.fields, req),\n id: documentId,\n documentId: doc.id,\n };\n await index.addDocuments([transformedDoc]);\n } else if (shouldIndex === 'delete') {\n await index.deleteDocument(documentId);\n }\n }\n}\n\nconst handleAfterChange: (config: MeilisearchConfig) => CollectionAfterChangeHook = (config) => {\n return async function ({ collection, doc, previousDoc, req }) {\n\n req.payload.logger.info(`Meilisearch [handleAfterChange] ${collection.slug} document ${doc.id}`);\n\n if (doc?._status === 'draft' && previousDoc?._status === 'draft') {\n req.payload.logger.info(`Meilisearch [handleAfterChange] ${collection.slug} document ${doc.id} - skipping consecutive draft change`);\n return;\n }\n try {\n\n await Promise.any([\n processDocument(doc, previousDoc, collection, config, req).catch((error) => {\n console.error('Meilisearch indexing error:', error);\n }),\n new Promise((resolve) => setTimeout(resolve, 500)),\n ]);\n\n } catch (error) {\n console.error('Meilisearch indexing error:', error);\n }\n }\n}\n\nconst afterDeleteHook: (config: MeilisearchConfig) => CollectionAfterDeleteHook = (config) => {\n return async ({ collection, doc, req }) => {\n try {\n\n const payload: Payload = req.payload;\n\n const localization = payload.config?.localization;\n\n const client = getMeilisearchClient(config);\n await upsertIndex(client, getIndexName(config, collection.slug));\n const index = client.index(getIndexName(config, collection.slug));\n\n if (localization && localization.locales?.length > 0) {\n\n const {\n locales,\n } = localization;\n\n for (const locale of locales) {\n\n const documentId = doc.id + `_${locale.code}`;\n await index.deleteDocument(documentId);\n\n }\n } else {\n await index.deleteDocument(doc.id);\n }\n\n } catch (error) {\n console.error('Meilisearch indexing error:', error);\n }\n }\n}\n\nlet meilisearch: MeiliSearch;\n\nfunction getMeilisearchClient(config: MeilisearchConfig) {\n if (!meilisearch) {\n meilisearch = new MeiliSearch({\n apiKey: config.apiKey,\n host: config.host,\n });\n\n }\n return meilisearch;\n}\n\nasync function upsertIndex(client: MeiliSearch, indexUID: string) {\n try {\n // Attempt to retrieve the index\n await client.getIndex(indexUID)\n } catch (error) {\n // Check if the error is because the index was not found\n // @ts-ignore\n if (error?.cause?.code === 'index_not_found') {\n // Index doesn't exist; create it\n await client.createIndex(indexUID, {\n primaryKey: 'id',\n })\n console.log(`Index '${indexUID}' has been created.`)\n } else {\n // Rethrow any other errors\n throw error\n }\n }\n}\n\n\nconst options = {\n wordwrap: 130,\n // ...\n};\n\nconst compiledConvert = compile(options);\n\n// Helper function to extract text from HTML in nodejs\nfunction extractTextFromHTML(html: string): string {\n return compiledConvert(html);\n}\n\n// Helper function to transform a document for Meilisearch indexing\nasync function transformDocumentForMeilisearch(doc: any, fields: Field[], req: PayloadRequest): Promise<any> {\n\n const transformedDoc: any = {};\n\n await Promise.all(fields.map(async (field) => {\n try {\n\n if (field.type === 'richText') {\n // For rich text fields, convert Lexical to HTML, then extract text\n\n const lexicalAdapter: LexicalRichTextAdapter =\n field.editor as LexicalRichTextAdapter\n\n const sanitizedServerEditorConfig: SanitizedServerEditorConfig = lexicalAdapter.editorConfig\n\n const html = await convertLexicalToHTML({\n converters: consolidateHTMLConverters({ editorConfig: sanitizedServerEditorConfig }),\n data: doc[field.name],\n });\n\n transformedDoc[field.name] = extractTextFromHTML(html);\n\n } else if (field.type === 'array' && field.fields) {\n // For array fields, transform each item\n transformedDoc[field.name] = await Promise.all(\n (doc[field.name] || []).map((item: any) =>\n transformDocumentForMeilisearch(item, field.fields, req)\n )\n );\n } else if (field.type === 'tabs') {\n // For tab fields, transform each tab\n (await Promise.all(\n field.tabs.map(async (tab: Tab) => {\n if ('name' in tab && tab.name) {\n return {\n [tab.name]: await transformDocumentForMeilisearch(doc?.[tab.name] ?? {}, tab.fields, req),\n }\n }\n return await transformDocumentForMeilisearch(doc, tab.fields, req)\n })\n )).forEach((t: any) => Object.assign(transformedDoc, t));\n } else if (field.type === 'blocks') {\n\n // For block fields, transform each block\n transformedDoc[field.name] = await Promise.all(\n (doc[field.name] || []).map(async (block: any) => {\n const fields = field.blocks.find((b: Block) => b.slug === block.blockType)?.fields\n\n if (!fields) {\n return {\n type: block.blockType,\n data: \"\",\n }\n }\n\n return {\n type: block.blockType,\n data: await transformDocumentForMeilisearch(block, fields, req),\n };\n })\n );\n } else if (field.type === 'radio') {\n transformedDoc[field.name] = doc[field.name]\n\n } else if (field.type === 'group' && field.name && field.fields) {\n // For group fields, transform the nested fields\n transformedDoc[field.name] = await transformDocumentForMeilisearch(doc[field.name], field.fields, req);\n } else if (field.type === 'group' && !field.name && field.fields) {\n Object.assign(\n transformedDoc,\n await transformDocumentForMeilisearch(doc, field.fields, req)\n );\n } else if ((field.type === 'row' || field.type === 'collapsible') && field.fields) {\n Object.assign(\n transformedDoc,\n await transformDocumentForMeilisearch(doc, field.fields, req)\n );\n } else if (field.type === 'relationship' && Array.isArray(field.relationTo) && field.hasMany) {\n transformedDoc[field.name] = doc[field.name]?.map((relatedDoc: any) => {\n return {\n id: relatedDoc?.value?.id ?? relatedDoc?.value ?? '',\n relationTo: relatedDoc?.relationTo ?? '',\n }\n }) ?? [];\n } else if (field.type === 'relationship' && Array.isArray(field.relationTo) && !field.hasMany) {\n transformedDoc[field.name] = {\n id: doc?.[field.name]?.value?.id ?? doc?.[field.name]?.value ?? '',\n relationTo: doc?.[field.name]?.relationTo ?? '',\n }\n } else if (field.type === 'relationship' && !Array.isArray(field.relationTo) && field.hasMany) {\n transformedDoc[field.name] = doc[field.name]?.map((relatedDoc: any) => {\n return relatedDoc?.id ?? relatedDoc?.value ?? '';\n }) ?? [];\n } else if (field.type === 'relationship' && !Array.isArray(field.relationTo) && !field.hasMany) {\n transformedDoc[field.name] = doc?.[field.name]?.id ?? doc?.[field.name] ?? '';\n } else if (field.type === 'relationship' || field.type === 'upload') {\n // For relationship and upload fields, just include the ID\n\n transformedDoc[field.name] = doc[field.name]?.id || doc[field.name];\n } else {\n // For other field types, include as-is\n // @ts-ignore\n transformedDoc[field.name] = doc[field.name];\n }\n } catch (err) {\n console.log(err, field, doc)\n }\n }));\n\n return transformedDoc;\n}"],"names":["consolidateHTMLConverters","convertLexicalToHTML","compile","MeiliSearch","getIndexName","config","collectionSlug","indexPrefix","reindexCollection","collection","req","context","meiliSkipDelay","entries","payload","find","slug","draft","pagination","select","id","client","getMeilisearchClient","upsertIndex","index","deleteAllDocuments","entry","docs","handleAfterChange","doc","operation","previousDoc","indexCollection","hooks","afterChange","push","afterDelete","afterDeleteHook","processDocument","Promise","resolve","setTimeout","baseDoc","collectionConfig","collections","c","documents","localization","locales","length","defaultLocale","fallback","locale","localizedDoc","findByID","fallbackLocale","code","overrideAccess","documentId","deleteDocument","shouldIndex","transformedDoc","transformDocumentForMeilisearch","fields","addDocuments","logger","info","_status","any","catch","error","console","meilisearch","apiKey","host","indexUID","getIndex","cause","createIndex","primaryKey","log","options","wordwrap","compiledConvert","extractTextFromHTML","html","all","map","field","type","lexicalAdapter","editor","sanitizedServerEditorConfig","editorConfig","converters","data","name","item","tabs","tab","forEach","t","Object","assign","block","blocks","b","blockType","Array","isArray","relationTo","hasMany","relatedDoc","value","err"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/indexCollections.ts"],"sourcesContent":["import type {\n LexicalRichTextAdapter,\n SanitizedServerEditorConfig\n} from '@payloadcms/richtext-lexical';\nimport type { Block, CollectionAfterChangeHook, CollectionAfterDeleteHook, CollectionConfig, Field, Option, Payload, PayloadRequest, SanitizedCollectionConfig, SelectField, Tab } from \"payload\";\n\nimport {\n consolidateHTMLConverters,\n convertLexicalToHTML,\n} from '@payloadcms/richtext-lexical';\nimport { compile } from 'html-to-text';\nimport { MeiliSearch } from 'meilisearch';\n\nimport type { IndexRelationshipFields, IndexSelectLabels, IndexSelectLabelsConfig, MeilisearchConfig } from \"./index.js\";\n\n\nconst getIndexName = (config: MeilisearchConfig, collectionSlug: string) => `${config?.indexPrefix ?? ''}${collectionSlug}`;\n\nexport const reindexCollection = async (collection: SanitizedCollectionConfig, config: MeilisearchConfig, req: PayloadRequest) => {\n\n req.context.meiliSkipDelay = true;\n\n const entries = await req.payload.find({\n collection: collection.slug,\n draft: false,\n pagination: false,\n select: {\n id: true,\n },\n });\n\n const client = getMeilisearchClient(config);\n await upsertIndex(client, getIndexName(config, collection.slug));\n const index = client.index(getIndexName(config, collection.slug));\n\n await index.deleteAllDocuments();\n\n\n for (const entry of entries.docs) {\n await handleAfterChange(config)({\n collection,\n context: req.context,\n doc: entry,\n operation: \"update\",\n previousDoc: null,\n req,\n })\n }\n}\n\nexport const indexCollection = (collection: CollectionConfig, config: MeilisearchConfig) => {\n\n if (!collection.hooks) {\n collection.hooks = {};\n }\n\n if (!collection.hooks.afterChange) {\n collection.hooks.afterChange = [];\n }\n\n collection.hooks.afterChange.push(handleAfterChange(config));\n\n if (!collection.hooks.afterDelete) {\n collection.hooks.afterDelete = [];\n }\n\n collection.hooks.afterDelete.push(afterDeleteHook(config));\n}\n\nconst processDocument = async (doc: any, previousDoc: any, collection: CollectionConfig, config: MeilisearchConfig, req: PayloadRequest) => {\n\n // wait for 50ms to allow for the document to be saved to the database to make things more reliable\n if (!req.context?.meiliSkipDelay) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n\n const baseDoc = doc;\n const collectionConfig = config.collections && config?.collections.find(c => c.slug === collection.slug);\n const indexRelationshipFields =\n collectionConfig?.indexRelationshipFields ?? config.indexRelationshipFields\n\n const payload: Payload = req.payload;\n\n const client = getMeilisearchClient(config);\n await upsertIndex(client, getIndexName(config, collection.slug));\n const index = client.index(getIndexName(config, collection.slug));\n\n const documents = [];\n\n if (payload.config?.localization && payload.config.localization.locales?.length > 0) {\n\n const {\n defaultLocale,\n fallback,\n locales,\n } = payload.config.localization;\n\n for (const locale of locales) {\n\n const localizedDoc = await req.payload.findByID({\n id: doc.id,\n collection: collection.slug,\n depth: indexRelationshipFields\n ? Math.max(payload.config.defaultDepth ?? 2, 1)\n : undefined,\n draft: false,\n fallbackLocale: locale.fallbackLocale || defaultLocale,\n locale: locale.code,\n overrideAccess: true,\n });\n\n const documentId = doc.id + `_${locale.code}`;\n\n if (!localizedDoc) {\n await index.deleteDocument(documentId);\n continue;\n }\n const shouldIndex = collectionConfig?.shouldIndex?.(localizedDoc, previousDoc, locale.code) ?? 'index'\n if (shouldIndex === 'index') {\n const transformedDoc = {\n ...await transformDocumentForMeilisearch(localizedDoc, collection.fields, req, {\n indexRelationshipFields,\n indexSelectLabels: collectionConfig?.indexSelectLabels ?? config.indexSelectLabels,\n locale: locale.code,\n }),\n id: documentId,\n documentId: doc.id,\n locale: locale.code,\n };\n documents.push(transformedDoc);\n } else if (shouldIndex === 'delete') {\n await index.deleteDocument(documentId);\n }\n\n }\n\n if (documents.length > 0) {\n await index.addDocuments(documents);\n }\n } else {\n const documentId = doc.id;\n const document = indexRelationshipFields\n ? await req.payload.findByID({\n id: doc.id,\n collection: collection.slug,\n depth: Math.max(payload.config.defaultDepth ?? 2, 1),\n draft: false,\n overrideAccess: true,\n })\n : doc\n const shouldIndex = collectionConfig?.shouldIndex?.(document, previousDoc) ?? 'index'\n if (shouldIndex === 'index') {\n const transformedDoc = {\n ...await transformDocumentForMeilisearch(document, collection.fields, req, {\n indexRelationshipFields,\n indexSelectLabels: collectionConfig?.indexSelectLabels ?? config.indexSelectLabels,\n }),\n id: documentId,\n documentId: doc.id,\n };\n await index.addDocuments([transformedDoc]);\n } else if (shouldIndex === 'delete') {\n await index.deleteDocument(documentId);\n }\n }\n}\n\nconst handleAfterChange: (config: MeilisearchConfig) => CollectionAfterChangeHook = (config) => {\n return async function ({ collection, doc, previousDoc, req }) {\n\n req.payload.logger.info(`Meilisearch [handleAfterChange] ${collection.slug} document ${doc.id}`);\n\n if (doc?._status === 'draft' && previousDoc?._status === 'draft') {\n req.payload.logger.info(`Meilisearch [handleAfterChange] ${collection.slug} document ${doc.id} - skipping consecutive draft change`);\n return;\n }\n try {\n\n await Promise.any([\n processDocument(doc, previousDoc, collection, config, req).catch((error) => {\n console.error('Meilisearch indexing error:', error);\n }),\n new Promise((resolve) => setTimeout(resolve, 500)),\n ]);\n\n } catch (error) {\n console.error('Meilisearch indexing error:', error);\n }\n }\n}\n\nconst afterDeleteHook: (config: MeilisearchConfig) => CollectionAfterDeleteHook = (config) => {\n return async ({ collection, doc, req }) => {\n try {\n\n const payload: Payload = req.payload;\n\n const localization = payload.config?.localization;\n\n const client = getMeilisearchClient(config);\n await upsertIndex(client, getIndexName(config, collection.slug));\n const index = client.index(getIndexName(config, collection.slug));\n\n if (localization && localization.locales?.length > 0) {\n\n const {\n locales,\n } = localization;\n\n for (const locale of locales) {\n\n const documentId = doc.id + `_${locale.code}`;\n await index.deleteDocument(documentId);\n\n }\n } else {\n await index.deleteDocument(doc.id);\n }\n\n } catch (error) {\n console.error('Meilisearch indexing error:', error);\n }\n }\n}\n\nlet meilisearch: MeiliSearch;\n\nfunction getMeilisearchClient(config: MeilisearchConfig) {\n if (!meilisearch) {\n meilisearch = new MeiliSearch({\n apiKey: config.apiKey,\n host: config.host,\n });\n\n }\n return meilisearch;\n}\n\nasync function upsertIndex(client: MeiliSearch, indexUID: string) {\n try {\n // Attempt to retrieve the index\n await client.getIndex(indexUID)\n } catch (error) {\n // Check if the error is because the index was not found\n // @ts-ignore\n if (error?.cause?.code === 'index_not_found') {\n // Index doesn't exist; create it\n await client.createIndex(indexUID, {\n primaryKey: 'id',\n })\n console.log(`Index '${indexUID}' has been created.`)\n } else {\n // Rethrow any other errors\n throw error\n }\n }\n}\n\n\nconst options = {\n wordwrap: 130,\n // ...\n};\n\nconst compiledConvert = compile(options);\n\n// Helper function to extract text from HTML in nodejs\nfunction extractTextFromHTML(html: string): string {\n return compiledConvert(html);\n}\n\nexport type TransformOptions = {\n indexRelationshipFields?: IndexRelationshipFields\n indexSelectLabels?: IndexSelectLabels\n locale?: string\n}\n\nconst normalizeLocale = (locale: string) => locale.replaceAll('_', '-').toLowerCase()\n\nexport const getSelectLabelLocaleFallbacks = (\n locale: string | undefined,\n defaultLocale: string | undefined,\n): string[] => {\n const fallbacks: string[] = []\n\n const addLocaleAndParents = (value: string | undefined) => {\n if (!value) {\n return\n }\n\n const parts = value.replaceAll('_', '-').split('-').filter(Boolean)\n while (parts.length > 0) {\n const candidate = parts.join('-')\n if (!fallbacks.some((item) => normalizeLocale(item) === normalizeLocale(candidate))) {\n fallbacks.push(candidate)\n }\n parts.pop()\n }\n }\n\n addLocaleAndParents(locale)\n addLocaleAndParents(defaultLocale)\n\n return fallbacks\n}\n\nconst getDefaultSelectLabel = (\n option: Option,\n localeFallbacks: string[],\n): string | undefined => {\n if (typeof option === 'string') {\n return option\n }\n\n if (typeof option.label === 'string') {\n return option.label\n }\n\n if (typeof option.label === 'function') {\n return undefined\n }\n\n for (const locale of localeFallbacks) {\n const matchingKey = Object.keys(option.label).find(\n (key) => normalizeLocale(key) === normalizeLocale(locale),\n )\n if (matchingKey && option.label[matchingKey]) {\n return option.label[matchingKey]\n }\n }\n\n return undefined\n}\n\nconst getSelectedOption = (field: SelectField, value: string): Option | undefined =>\n field.options.find((option) => (\n typeof option === 'string' ? option === value : option.value === value\n ))\n\nconst transformSelectLabels = async ({\n field,\n locale,\n options,\n req,\n value,\n}: {\n field: SelectField\n locale?: string\n options: IndexSelectLabelsConfig\n req: PayloadRequest\n value: unknown\n}): Promise<string | string[] | undefined> => {\n const defaultLocale = options.defaultLocale ?? req.payload.config.i18n.fallbackLanguage\n const localeFallbacks = getSelectLabelLocaleFallbacks(locale, defaultLocale)\n\n const resolveValue = async (selectedValue: unknown): Promise<string | undefined> => {\n if (typeof selectedValue !== 'string') {\n return undefined\n }\n\n const option = getSelectedOption(field, selectedValue)\n if (!option) {\n return undefined\n }\n\n const defaultLabel = getDefaultSelectLabel(option, localeFallbacks)\n if (!options.resolveLabel) {\n return defaultLabel\n }\n\n const resolvedLabel = await options.resolveLabel({\n defaultLabel,\n field,\n locale,\n localeFallbacks,\n option,\n req,\n value: selectedValue,\n })\n\n return resolvedLabel === undefined ? defaultLabel : resolvedLabel ?? undefined\n }\n\n if (Array.isArray(value)) {\n const labels = (await Promise.all(value.map(resolveValue))).filter(\n (label): label is string => typeof label === 'string',\n )\n return labels.length > 0 ? labels : undefined\n }\n\n return resolveValue(value)\n}\n\nconst joinFieldPath = (parentPath: string, fieldName: string): string =>\n parentPath ? `${parentPath}.${fieldName}` : fieldName\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst unsafePathSegments = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst getValueAtPath = (\n value: Record<string, unknown>,\n path: string,\n): unknown => {\n const segments = path.split('.').filter(Boolean)\n let current: unknown = value\n\n for (const segment of segments) {\n if (unsafePathSegments.has(segment) || !isRecord(current)) {\n return undefined\n }\n current = current[segment]\n }\n\n return current\n}\n\nconst setValueAtPath = (\n target: Record<string, unknown>,\n path: string,\n value: unknown,\n): void => {\n const segments = path.split('.').filter(Boolean)\n if (segments.length === 0 || segments.some((segment) => unsafePathSegments.has(segment))) {\n return\n }\n\n let current = target\n for (const [index, segment] of segments.entries()) {\n if (index === segments.length - 1) {\n current[segment] = value\n return\n }\n\n const nestedValue = current[segment]\n if (isRecord(nestedValue)) {\n current = nestedValue\n } else {\n const nestedTarget: Record<string, unknown> = {}\n current[segment] = nestedTarget\n current = nestedTarget\n }\n }\n}\n\nconst selectRelatedDocumentFields = (\n relatedDocument: unknown,\n fieldPaths: readonly string[],\n): Record<string, unknown> => {\n if (!isRecord(relatedDocument)) {\n return {}\n }\n\n const selected: Record<string, unknown> = {}\n for (const fieldPath of fieldPaths) {\n const value = getValueAtPath(relatedDocument, fieldPath)\n if (value !== undefined) {\n setValueAtPath(selected, fieldPath, value)\n }\n }\n return selected\n}\n\nconst getRelationshipID = (\n value: unknown,\n fallbackToValue: boolean,\n): unknown => {\n if (!isRecord(value)) {\n return fallbackToValue ? value ?? '' : ''\n }\n\n if (value.id !== undefined) {\n return value.id\n }\n\n return fallbackToValue ? value : value.value ?? ''\n}\n\nconst getPolymorphicRelationshipID = (value: unknown): unknown => {\n if (!isRecord(value)) {\n return ''\n }\n\n return isRecord(value.value) ? value.value.id ?? '' : value.value ?? ''\n}\n\nconst getRelatedDocument = (value: unknown): Record<string, unknown> | undefined => {\n if (!isRecord(value)) {\n return undefined\n }\n\n return isRecord(value.value) ? value.value : value\n}\n\nconst transformRelationshipValue = (\n value: unknown,\n selectedFieldPaths?: readonly string[],\n fallbackToValue = false,\n): unknown => {\n const id = getRelationshipID(value, fallbackToValue)\n if (!selectedFieldPaths) {\n return id\n }\n\n return {\n ...selectRelatedDocumentFields(getRelatedDocument(value), selectedFieldPaths),\n id,\n }\n}\n\nconst transformPolymorphicRelationshipValue = (\n value: unknown,\n selectedFieldPaths?: readonly string[],\n): Record<string, unknown> => {\n const relationship = isRecord(value) ? value : {}\n const transformed = selectedFieldPaths\n ? selectRelatedDocumentFields(getRelatedDocument(value), selectedFieldPaths)\n : {}\n\n return {\n ...transformed,\n id: getPolymorphicRelationshipID(value),\n relationTo: relationship.relationTo ?? '',\n }\n}\n\n// Helper function to transform a document for Meilisearch indexing\nexport async function transformDocumentForMeilisearch(\n doc: any,\n fields: Field[],\n req: PayloadRequest,\n options: TransformOptions = {},\n parentPath = '',\n): Promise<any> {\n\n const transformedDoc: any = {};\n\n await Promise.all(fields.map(async (field) => {\n try {\n const fieldPath = 'name' in field && field.name\n ? joinFieldPath(parentPath, field.name)\n : parentPath\n\n if (field.type === 'richText') {\n // For rich text fields, convert Lexical to HTML, then extract text\n\n const lexicalAdapter: LexicalRichTextAdapter =\n field.editor as LexicalRichTextAdapter\n\n const sanitizedServerEditorConfig: SanitizedServerEditorConfig = lexicalAdapter.editorConfig\n\n const html = await convertLexicalToHTML({\n converters: consolidateHTMLConverters({ editorConfig: sanitizedServerEditorConfig }),\n data: doc[field.name],\n });\n\n transformedDoc[field.name] = extractTextFromHTML(html);\n\n } else if (field.type === 'array' && field.fields) {\n // For array fields, transform each item\n transformedDoc[field.name] = await Promise.all(\n (doc[field.name] || []).map((item: any) =>\n transformDocumentForMeilisearch(item, field.fields, req, options, fieldPath)\n )\n );\n } else if (field.type === 'tabs') {\n // For tab fields, transform each tab\n (await Promise.all(\n field.tabs.map(async (tab: Tab) => {\n if ('name' in tab && tab.name) {\n return {\n [tab.name]: await transformDocumentForMeilisearch(\n doc?.[tab.name] ?? {},\n tab.fields,\n req,\n options,\n joinFieldPath(parentPath, tab.name),\n ),\n }\n }\n return await transformDocumentForMeilisearch(doc, tab.fields, req, options, parentPath)\n })\n )).forEach((t: any) => Object.assign(transformedDoc, t));\n } else if (field.type === 'blocks') {\n\n // For block fields, transform each block\n transformedDoc[field.name] = await Promise.all(\n (doc[field.name] || []).map(async (block: any) => {\n const fields = field.blocks.find((b: Block) => b.slug === block.blockType)?.fields\n\n if (!fields) {\n return {\n type: block.blockType,\n data: \"\",\n }\n }\n\n return {\n type: block.blockType,\n data: await transformDocumentForMeilisearch(block, fields, req, options, fieldPath),\n };\n })\n );\n } else if (field.type === 'select') {\n transformedDoc[field.name] = doc[field.name]\n\n if (options.indexSelectLabels) {\n const selectLabelOptions = options.indexSelectLabels === true\n ? {}\n : options.indexSelectLabels\n const label = await transformSelectLabels({\n field,\n locale: options.locale,\n options: selectLabelOptions,\n req,\n value: doc[field.name],\n })\n\n if (label !== undefined) {\n transformedDoc[`${field.name}${selectLabelOptions.fieldSuffix ?? '_label'}`] = label\n }\n }\n } else if (field.type === 'radio') {\n transformedDoc[field.name] = doc[field.name]\n\n } else if (field.type === 'group' && field.name && field.fields) {\n // For group fields, transform the nested fields\n transformedDoc[field.name] = await transformDocumentForMeilisearch(\n doc[field.name],\n field.fields,\n req,\n options,\n fieldPath,\n );\n } else if (field.type === 'group' && !field.name && field.fields) {\n Object.assign(\n transformedDoc,\n await transformDocumentForMeilisearch(doc, field.fields, req, options, parentPath)\n );\n } else if ((field.type === 'row' || field.type === 'collapsible') && field.fields) {\n Object.assign(\n transformedDoc,\n await transformDocumentForMeilisearch(doc, field.fields, req, options, parentPath)\n );\n } else if (field.type === 'relationship' && Array.isArray(field.relationTo) && field.hasMany) {\n const selectedFieldPaths = options.indexRelationshipFields?.[fieldPath]\n transformedDoc[field.name] = doc[field.name]?.map((relatedDoc: any) =>\n transformPolymorphicRelationshipValue(relatedDoc, selectedFieldPaths)\n ) ?? [];\n } else if (field.type === 'relationship' && Array.isArray(field.relationTo) && !field.hasMany) {\n const selectedFieldPaths = options.indexRelationshipFields?.[fieldPath]\n transformedDoc[field.name] = transformPolymorphicRelationshipValue(\n doc?.[field.name],\n selectedFieldPaths,\n )\n } else if (field.type === 'relationship' && !Array.isArray(field.relationTo) && field.hasMany) {\n const selectedFieldPaths = options.indexRelationshipFields?.[fieldPath]\n transformedDoc[field.name] = doc[field.name]?.map((relatedDoc: any) =>\n transformRelationshipValue(relatedDoc, selectedFieldPaths)\n ) ?? [];\n } else if (field.type === 'relationship' && !Array.isArray(field.relationTo) && !field.hasMany) {\n const selectedFieldPaths = options.indexRelationshipFields?.[fieldPath]\n transformedDoc[field.name] = transformRelationshipValue(\n doc?.[field.name],\n selectedFieldPaths,\n true,\n )\n } else if (field.type === 'relationship' || field.type === 'upload') {\n // For relationship and upload fields, just include the ID\n\n transformedDoc[field.name] = doc[field.name]?.id || doc[field.name];\n } else {\n // For other field types, include as-is\n // @ts-ignore\n transformedDoc[field.name] = doc[field.name];\n }\n } catch (err) {\n console.log(err, field, doc)\n }\n }));\n\n return transformedDoc;\n}\n"],"names":["consolidateHTMLConverters","convertLexicalToHTML","compile","MeiliSearch","getIndexName","config","collectionSlug","indexPrefix","reindexCollection","collection","req","context","meiliSkipDelay","entries","payload","find","slug","draft","pagination","select","id","client","getMeilisearchClient","upsertIndex","index","deleteAllDocuments","entry","docs","handleAfterChange","doc","operation","previousDoc","indexCollection","hooks","afterChange","push","afterDelete","afterDeleteHook","processDocument","Promise","resolve","setTimeout","baseDoc","collectionConfig","collections","c","indexRelationshipFields","documents","localization","locales","length","defaultLocale","fallback","locale","localizedDoc","findByID","depth","Math","max","defaultDepth","undefined","fallbackLocale","code","overrideAccess","documentId","deleteDocument","shouldIndex","transformedDoc","transformDocumentForMeilisearch","fields","indexSelectLabels","addDocuments","document","logger","info","_status","any","catch","error","console","meilisearch","apiKey","host","indexUID","getIndex","cause","createIndex","primaryKey","log","options","wordwrap","compiledConvert","extractTextFromHTML","html","normalizeLocale","replaceAll","toLowerCase","getSelectLabelLocaleFallbacks","fallbacks","addLocaleAndParents","value","parts","split","filter","Boolean","candidate","join","some","item","pop","getDefaultSelectLabel","option","localeFallbacks","label","matchingKey","Object","keys","key","getSelectedOption","field","transformSelectLabels","i18n","fallbackLanguage","resolveValue","selectedValue","defaultLabel","resolveLabel","resolvedLabel","Array","isArray","labels","all","map","joinFieldPath","parentPath","fieldName","isRecord","unsafePathSegments","Set","getValueAtPath","path","segments","current","segment","has","setValueAtPath","target","nestedValue","nestedTarget","selectRelatedDocumentFields","relatedDocument","fieldPaths","selected","fieldPath","getRelationshipID","fallbackToValue","getPolymorphicRelationshipID","getRelatedDocument","transformRelationshipValue","selectedFieldPaths","transformPolymorphicRelationshipValue","relationship","transformed","relationTo","name","type","lexicalAdapter","editor","sanitizedServerEditorConfig","editorConfig","converters","data","tabs","tab","forEach","t","assign","block","blocks","b","blockType","selectLabelOptions","fieldSuffix","hasMany","relatedDoc","err"],"mappings":"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"}
|