@extravirgin/payload-plugin-meilisearch 0.0.1 → 0.0.2
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/index.d.ts +2 -0
- package/dist/index.js.map +1 -0
- package/dist/indexCollections.d.ts +3 -0
- package/dist/indexCollections.js +395 -0
- package/dist/indexCollections.js.map +1 -0
- package/dist/mocks/mockFile.d.ts +1 -0
- package/dist/mocks/mockFile.js +3 -0
- package/dist/mocks/mockFile.js.map +1 -0
- package/dist/onInitExtension.d.ts +3 -0
- package/dist/onInitExtension.js +17 -0
- package/dist/onInitExtension.js.map +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.js +103 -0
- package/dist/plugin.js.map +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/webpack.d.ts +3 -0
- package/dist/webpack.js +32 -0
- package/dist/webpack.js.map +1 -0
- package/package.json +4 -1
- package/.editorconfig +0 -10
- package/.eslintrc.js +0 -17
- package/.github/workflows/test.yml +0 -19
- package/.prettierrc.js +0 -8
- package/dev/.env.example +0 -2
- package/dev/Dockerfile +0 -27
- package/dev/docker-compose.yml +0 -31
- package/dev/jest.config.js +0 -12
- package/dev/nodemon.json +0 -6
- package/dev/package.json +0 -35
- package/dev/plugin.spec.ts +0 -30
- package/dev/src/collections/Examples.ts +0 -17
- package/dev/src/collections/Users.ts +0 -15
- package/dev/src/mocks/fileStub.js +0 -1
- package/dev/src/payload.config.ts +0 -44
- package/dev/src/server.ts +0 -29
- package/dev/tsconfig.json +0 -34
- package/eslint-config/index.js +0 -15
- package/eslint-config/rules/import.js +0 -38
- package/eslint-config/rules/prettier.js +0 -7
- package/eslint-config/rules/style.js +0 -21
- package/eslint-config/rules/typescript.js +0 -628
- package/src/index.ts +0 -2
- package/src/indexCollections.ts +0 -155
- package/src/mocks/mockFile.js +0 -1
- package/src/onInitExtension.ts +0 -16
- package/src/plugin.ts +0 -67
- package/src/types.ts +0 -20
- package/src/webpack.ts +0 -28
- package/tsconfig.json +0 -23
package/src/indexCollections.ts
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { CollectionConfig, Field } from "payload/dist/exports/types";
|
|
2
|
-
import { PluginTypes } from "./types";
|
|
3
|
-
import { MeiliSearch } from 'meilisearch';
|
|
4
|
-
import { compile } from 'html-to-text';
|
|
5
|
-
import {
|
|
6
|
-
LexicalRichTextAdapter,
|
|
7
|
-
convertLexicalToHTML,
|
|
8
|
-
consolidateHTMLConverters,
|
|
9
|
-
} from '@payloadcms/richtext-lexical';
|
|
10
|
-
|
|
11
|
-
export const indexCollections = (collections: CollectionConfig[], config: PluginTypes) : CollectionConfig[] => {
|
|
12
|
-
|
|
13
|
-
const getIndexName = (collectionSlug: string) => `${config?.indexPrefix ?? ''}${collectionSlug}`;
|
|
14
|
-
|
|
15
|
-
const meilisearch = new MeiliSearch({
|
|
16
|
-
host: config.host,
|
|
17
|
-
apiKey: config.apiKey,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
return collections.map((collection) => {
|
|
21
|
-
|
|
22
|
-
if(config?.collections && !config?.collections.find(c => c.slug === collection.slug)) {
|
|
23
|
-
return collection;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
...collection,
|
|
28
|
-
hooks: {
|
|
29
|
-
...(collection.hooks || {}),
|
|
30
|
-
afterChange: [
|
|
31
|
-
...(collection.hooks?.afterChange || []),
|
|
32
|
-
async ({ doc, operation, req }) => {
|
|
33
|
-
await upsertIndex(meilisearch, getIndexName(collection.slug));
|
|
34
|
-
const index = meilisearch.index(getIndexName(collection.slug));
|
|
35
|
-
if (operation === 'create' || operation === 'update') {
|
|
36
|
-
const transformedDoc = { ...await transformDocumentForMeilisearch(doc, collection.fields, req), id: doc.id };
|
|
37
|
-
await index.addDocuments([transformedDoc]);
|
|
38
|
-
} else if (operation === 'delete') {
|
|
39
|
-
await index.deleteDocument(doc.id);
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function upsertIndex(client: MeiliSearch, indexUID: string) {
|
|
49
|
-
try {
|
|
50
|
-
// Attempt to retrieve the index
|
|
51
|
-
await client.getIndex(indexUID)
|
|
52
|
-
} catch (error) {
|
|
53
|
-
// Check if the error is because the index was not found
|
|
54
|
-
// @ts-ignore
|
|
55
|
-
if (error?.cause?.code === 'index_not_found') {
|
|
56
|
-
// Index doesn't exist; create it
|
|
57
|
-
await client.createIndex(indexUID, {
|
|
58
|
-
primaryKey: 'id',
|
|
59
|
-
})
|
|
60
|
-
console.log(`Index '${indexUID}' has been created.`)
|
|
61
|
-
} else {
|
|
62
|
-
// Rethrow any other errors
|
|
63
|
-
throw error
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const options = {
|
|
70
|
-
wordwrap: 130,
|
|
71
|
-
// ...
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const compiledConvert = compile(options);
|
|
75
|
-
|
|
76
|
-
// Helper function to extract text from HTML in nodejs
|
|
77
|
-
function extractTextFromHTML(html: string): string {
|
|
78
|
-
return compiledConvert(html);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Helper function to transform a document for Meilisearch indexing
|
|
82
|
-
async function transformDocumentForMeilisearch(doc: any, fields: Field[], req: Request): Promise<any> {
|
|
83
|
-
|
|
84
|
-
const transformedDoc: any = {};
|
|
85
|
-
|
|
86
|
-
await Promise.all(fields.map(async (field) => {
|
|
87
|
-
if (field.type === 'richText') {
|
|
88
|
-
// For rich text fields, convert Lexical to HTML, then extract text
|
|
89
|
-
|
|
90
|
-
const lexicalAdapter: LexicalRichTextAdapter =
|
|
91
|
-
field.editor as LexicalRichTextAdapter
|
|
92
|
-
|
|
93
|
-
const sanitizedServerEditorConfig: any = lexicalAdapter.editorConfig
|
|
94
|
-
|
|
95
|
-
const html = await convertLexicalToHTML({
|
|
96
|
-
converters: consolidateHTMLConverters({editorConfig: sanitizedServerEditorConfig}),
|
|
97
|
-
data: doc[field.name],
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
transformedDoc[field.name] = extractTextFromHTML(html);
|
|
101
|
-
|
|
102
|
-
} else if (field.type === 'array' && field.fields) {
|
|
103
|
-
// For array fields, transform each item
|
|
104
|
-
transformedDoc[field.name] = await Promise.all(
|
|
105
|
-
(doc[field.name] || []).map((item: any) =>
|
|
106
|
-
transformDocumentForMeilisearch(item, field.fields, req)
|
|
107
|
-
)
|
|
108
|
-
);
|
|
109
|
-
} else if (field.type === 'tabs') {
|
|
110
|
-
// For tab fields, transform each tab
|
|
111
|
-
(await Promise.all(
|
|
112
|
-
field.tabs.map(async (tab, index) => {
|
|
113
|
-
return await transformDocumentForMeilisearch(doc, tab.fields, req)
|
|
114
|
-
})
|
|
115
|
-
)).forEach((t) => Object.assign(transformedDoc, t));
|
|
116
|
-
} else if (field.type === 'blocks') {
|
|
117
|
-
|
|
118
|
-
// For block fields, transform each block
|
|
119
|
-
transformedDoc[field.name] = await Promise.all(
|
|
120
|
-
(doc[field.name] || []).map(async (block: any) => {
|
|
121
|
-
const fields = field.blocks.find(b => b.slug === block.blockType)?.fields
|
|
122
|
-
|
|
123
|
-
if (!fields) {
|
|
124
|
-
return {
|
|
125
|
-
type: block.blockType,
|
|
126
|
-
data: "",
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
type: block.blockType,
|
|
132
|
-
data: await transformDocumentForMeilisearch(block, fields, req),
|
|
133
|
-
};
|
|
134
|
-
})
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
} else if (field.type === 'group' && field.fields) {
|
|
138
|
-
// For group fields, transform the nested fields
|
|
139
|
-
transformedDoc[field.name] = await transformDocumentForMeilisearch(doc[field.name], field.fields, req);
|
|
140
|
-
} else if (field.type === 'relationship' || field.type === 'upload') {
|
|
141
|
-
// For relationship and upload fields, just include the ID
|
|
142
|
-
transformedDoc[field.name] = doc[field.name]?.id || doc[field.name];
|
|
143
|
-
} else {
|
|
144
|
-
// For other field types, include as-is
|
|
145
|
-
try {
|
|
146
|
-
// @ts-ignore
|
|
147
|
-
transformedDoc[field.name] = doc[field.name];
|
|
148
|
-
} catch(err) {
|
|
149
|
-
console.log(err, field, doc)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}));
|
|
153
|
-
|
|
154
|
-
return transformedDoc;
|
|
155
|
-
}
|
package/src/mocks/mockFile.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = {}
|
package/src/onInitExtension.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { Payload } from 'payload/dist/payload'
|
|
2
|
-
|
|
3
|
-
import type { PluginTypes } from './types'
|
|
4
|
-
|
|
5
|
-
export const onInitExtension = (pluginOptions: PluginTypes, payload: Payload): void => {
|
|
6
|
-
const { express: app } = payload
|
|
7
|
-
|
|
8
|
-
if (!app) return
|
|
9
|
-
|
|
10
|
-
try {
|
|
11
|
-
// You can use the existing express app here to add middleware, routes, etc.
|
|
12
|
-
// app.use(...)
|
|
13
|
-
} catch (err: unknown) {
|
|
14
|
-
payload.logger.error({ msg: 'Error in onInitExtension', err })
|
|
15
|
-
}
|
|
16
|
-
}
|
package/src/plugin.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import type { Config, Plugin } from 'payload/config'
|
|
2
|
-
|
|
3
|
-
import { onInitExtension } from './onInitExtension'
|
|
4
|
-
import type { PluginTypes } from './types'
|
|
5
|
-
import { extendWebpackConfig } from './webpack'
|
|
6
|
-
import { indexCollections } from './indexCollections'
|
|
7
|
-
|
|
8
|
-
type PluginType = (pluginOptions: PluginTypes) => Plugin
|
|
9
|
-
|
|
10
|
-
export const meilisearchPlugin =
|
|
11
|
-
(pluginOptions: PluginTypes): Plugin =>
|
|
12
|
-
(incomingConfig) => {
|
|
13
|
-
let config = { ...incomingConfig }
|
|
14
|
-
|
|
15
|
-
// If you need to add a webpack alias, use this function to extend the webpack config
|
|
16
|
-
const webpack = extendWebpackConfig(incomingConfig)
|
|
17
|
-
|
|
18
|
-
config.admin = {
|
|
19
|
-
...(config.admin || {}),
|
|
20
|
-
// If you extended the webpack config, add it back in here
|
|
21
|
-
// If you did not extend the webpack config, you can remove this line
|
|
22
|
-
webpack,
|
|
23
|
-
|
|
24
|
-
// Add additional admin config here
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// If the plugin is disabled, return the config without modifying it
|
|
28
|
-
// The order of this check is important, we still want any webpack extensions to be applied even if the plugin is disabled
|
|
29
|
-
if (pluginOptions.enabled === false) {
|
|
30
|
-
return config
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
config.collections = [
|
|
34
|
-
...(indexCollections(config.collections || [], pluginOptions)),
|
|
35
|
-
]
|
|
36
|
-
|
|
37
|
-
config.endpoints = [
|
|
38
|
-
...(config.endpoints || []),
|
|
39
|
-
// {
|
|
40
|
-
// path: '/custom-endpoint',
|
|
41
|
-
// method: 'get',
|
|
42
|
-
// root: true,
|
|
43
|
-
// handler: (req, res): void => {
|
|
44
|
-
// res.json({ message: 'Here is a custom endpoint' });
|
|
45
|
-
// },
|
|
46
|
-
// },
|
|
47
|
-
// Add additional endpoints here
|
|
48
|
-
]
|
|
49
|
-
|
|
50
|
-
config.globals = [
|
|
51
|
-
...(config.globals || []),
|
|
52
|
-
// Add additional globals here
|
|
53
|
-
]
|
|
54
|
-
|
|
55
|
-
config.hooks = {
|
|
56
|
-
...(config.hooks || {}),
|
|
57
|
-
// Add additional hooks here
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
config.onInit = async payload => {
|
|
61
|
-
if (incomingConfig.onInit) await incomingConfig.onInit(payload)
|
|
62
|
-
// Add additional onInit code by using the onInitExtension function
|
|
63
|
-
onInitExtension(pluginOptions, payload)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return config
|
|
67
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export interface PluginTypes {
|
|
2
|
-
/**
|
|
3
|
-
* Enable or disable plugin
|
|
4
|
-
* @default false
|
|
5
|
-
*/
|
|
6
|
-
enabled?: boolean
|
|
7
|
-
host: string;
|
|
8
|
-
apiKey: string;
|
|
9
|
-
indexPrefix?: string;
|
|
10
|
-
collections?: PluginCollectionConfig[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface PluginCollectionConfig {
|
|
14
|
-
slug: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export interface NewCollectionTypes {
|
|
19
|
-
title: string
|
|
20
|
-
}
|
package/src/webpack.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import type { Config } from 'payload/config'
|
|
3
|
-
import type { Configuration as WebpackConfig } from 'webpack'
|
|
4
|
-
|
|
5
|
-
export const extendWebpackConfig =
|
|
6
|
-
(config: Config): ((webpackConfig: WebpackConfig) => WebpackConfig) =>
|
|
7
|
-
webpackConfig => {
|
|
8
|
-
const existingWebpackConfig =
|
|
9
|
-
typeof config.admin?.webpack === 'function'
|
|
10
|
-
? config.admin.webpack(webpackConfig)
|
|
11
|
-
: webpackConfig
|
|
12
|
-
|
|
13
|
-
const mockModulePath = path.resolve(__dirname, './mocks/mockFile.js')
|
|
14
|
-
|
|
15
|
-
const newWebpack = {
|
|
16
|
-
...existingWebpackConfig,
|
|
17
|
-
resolve: {
|
|
18
|
-
...(existingWebpackConfig.resolve || {}),
|
|
19
|
-
alias: {
|
|
20
|
-
...(existingWebpackConfig.resolve?.alias ? existingWebpackConfig.resolve.alias : {}),
|
|
21
|
-
// Add additional aliases here like so:
|
|
22
|
-
[path.resolve(__dirname, './yourFileHere')]: mockModulePath,
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return newWebpack
|
|
28
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"lib": [
|
|
4
|
-
"dom",
|
|
5
|
-
"dom.iterable",
|
|
6
|
-
"esnext"
|
|
7
|
-
],
|
|
8
|
-
"target": "es5",
|
|
9
|
-
"outDir": "./dist",
|
|
10
|
-
"allowJs": true,
|
|
11
|
-
"module": "commonjs",
|
|
12
|
-
"sourceMap": true,
|
|
13
|
-
"jsx": "react",
|
|
14
|
-
"esModuleInterop": true,
|
|
15
|
-
"declaration": true,
|
|
16
|
-
"declarationDir": "./dist",
|
|
17
|
-
"skipLibCheck": true,
|
|
18
|
-
"strict": true,
|
|
19
|
-
},
|
|
20
|
-
"include": [
|
|
21
|
-
"src/**/*",
|
|
22
|
-
],
|
|
23
|
-
}
|