strapi-plugin-meilisearch 0.13.1 → 0.13.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021-2024 Meili SAS
3
+ Copyright (c) 2021-2025 Meili SAS
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -31,9 +31,8 @@ Add your Strapi content-types into a Meilisearch instance. The plugin listens to
31
31
  ## Table of Contents <!-- omit in TOC -->
32
32
 
33
33
  - [📖 Documentation](#-documentation)
34
- - [⚡ Supercharge your Meilisearch experience](#-supercharge-your-meilisearch-experience)
35
34
  - [🔧 Installation](#-installation)
36
- - [🎬 Getting Started](#-getting-started)
35
+ - [🚀 Getting started](#-getting-started)
37
36
  - [💅 Customization](#-customization)
38
37
  - [💡 Run the Playground](#-run-the-playground)
39
38
  - [🤖 Compatibility with Meilisearch and Strapi](#-compatibility-with-meilisearch-and-strapi)
@@ -47,10 +46,6 @@ To understand Meilisearch and how it works, see the [Meilisearch's documentation
47
46
 
48
47
  To understand Strapi and how to create an app, see [Strapi's documentation](https://strapi.io/documentation/developer-docs/latest/getting-started/introduction.html).
49
48
 
50
- ## ⚡ Supercharge your Meilisearch experience
51
-
52
- Say goodbye to server deployment and manual updates with [Meilisearch Cloud](https://www.meilisearch.com/cloud?utm_campaign=oss&utm_source=github&utm_medium=strapi-plugin-meilisearch). Get started with a 14-day free trial! No credit card required.
53
-
54
49
  ## 🔧 Installation
55
50
 
56
51
  This package version works with the [v5 of Strapi](https://docs.strapi.io/dev-docs/intro). If you are using [Strapi v4](https://docs-v4.strapi.io/), refer to versions under [`v0.12`](https://github.com/meilisearch/strapi-plugin-meilisearch/tree/v0.12.0), if you are using [Strapi v3](https://docs-v3.strapi.io/), consider [this README](https://github.com/meilisearch/strapi-plugin-meilisearch/tree/v3_main).
@@ -77,16 +72,11 @@ strapi build
77
72
 
78
73
  You will need both a running Strapi app and a running Meilisearch instance. For [specific version compatibility, see this section](#-compatibility-with-meilisearch-and-strapi).
79
74
 
80
- ### 🏃‍♀️ Run Meilisearch <!-- omit in toc -->
81
-
82
- There are many easy ways to [download and run a Meilisearch instance](https://www.meilisearch.com/docs/reference/features/installation.html#download-and-launch).
75
+ ### Run Meilisearch <!-- omit in toc -->
83
76
 
84
- For example, if you use Docker:
77
+ ⚡️ **Launch, scale, and streamline in minutes with Meilisearch Cloud**—no maintenance, no commitment, cancel anytime. [Try it free now](https://cloud.meilisearch.com/login?utm_campaign=oss&utm_source=github&utm_medium=strapi-plugin-meilisearch).
85
78
 
86
- ```bash
87
- docker pull getmeili/meilisearch:latest # Fetch the latest version of Meilisearch image from Docker Hub
88
- docker run -it --rm -p 7700:7700 getmeili/meilisearch:latest meilisearch --master-key=masterKey
89
- ```
79
+ 🪨 Prefer to self-host? [Download and deploy](https://www.meilisearch.com/docs/learn/self_hosted/getting_started_with_self_hosted_meilisearch?utm_campaign=oss&utm_source=github&utm_medium=strapi-plugin-meilisearch) our fast, open-source search engine on your own infrastructure.
90
80
 
91
81
  ### 🏃‍♂️ Run Strapi <!-- omit in toc -->
92
82
 
@@ -116,7 +106,7 @@ You can use Docker to run Meilisearch and Strapi on the same server. A Docker co
116
106
 
117
107
  To run the Docker script add both files `Dockerfile` and `docker-compose.yaml` at the root of your Strapi project and run it with the following command: `docker-compose up`.
118
108
 
119
- ## 🎬 Getting Started
109
+ ## 🚀 Getting started
120
110
 
121
111
  Now that you have installed the plugin, a running Meilisearch instance and, a running Strapi app, let's go to the plugin page on your admin dashboard.
122
112
 
@@ -318,7 +308,7 @@ For example, given two content-types:
318
308
 
319
309
  The index `product` has both the entries of shoes and shirts. If the index `product` has `350` documents in Meilisearch, it is not possible to know how many of them are from `shoes` or `shirts`.
320
310
 
321
- When removing `shoes` or `shirts` from Meilisearch, both are removed as it would require to much processing to only remove one. You can still re-index only one after that.
311
+ When removing `shoes` or `shirts` from Meilisearch, both are removed as it would require too much processing to only remove one. You can still re-index only one after that.
322
312
 
323
313
  <p align="center">Example with two single types:</p>
324
314
  <p align="center">
@@ -437,9 +427,9 @@ The options you can set are described in the [`findMany` documentation](https://
437
427
 
438
428
  **Common use cases**
439
429
 
440
- If you are using the [🌍 Internationalization (i18n)](https://docs.strapi.io/developer-docs/latest/plugins/i18n.html) plugin, an additional field `locale` should also be added in `entriesQuery`.
430
+ If you are localizing your Strapi content, an additional field `locale` should also be added in `entriesQuery`.
441
431
 
442
- ⚠️ Warning: if you do not specify `locale: "all"` in `entriesQuery`, you may not index all available entries, potentially leading to missing products in your search results. To ensure all entries in every language are indexed in Meilisearch, include the `locale` field with the value 'all'.
432
+ ⚠️ Warning: if you do not specify `locale: "*"` in `entriesQuery`, you may not index all available entries, potentially leading to missing products in your search results. To ensure all entries in every language are indexed in Meilisearch, include the `locale` field with the value 'all'.
443
433
 
444
434
  ```js
445
435
  module.exports = {
@@ -447,7 +437,7 @@ module.exports = {
447
437
  config: {
448
438
  restaurant: {
449
439
  entriesQuery: {
450
- locale: 'all',
440
+ locale: '*',
451
441
  },
452
442
  },
453
443
  },
@@ -455,6 +445,8 @@ module.exports = {
455
445
  }
456
446
  ```
457
447
 
448
+ If you are using Strapi 4 with the [🌍 Internationalization (i18n)](https://docs.strapi.io/developer-docs/latest/plugins/i18n.html) plugin, the `locale` field should be set to `all`.
449
+
458
450
  If you want to add a collection with a relation to the collection being included, you have to configure the `populate` parameter in `entriesQuery`. See [the docs](https://docs.strapi.io/dev-docs/api/entity-service/populate) on how it works, and [an example](./resources/entries-query/populate.js) in our resources.
459
451
 
460
452
  **Example**
@@ -662,5 +654,5 @@ If you want to know more about the development workflow or want to contribute, p
662
654
  Using the [foodadvisor](https://github.com/strapi/foodadvisor) restaurant demo Strapi provided. We added a searchbar to it using [instant-meilisearch](https://github.com/meilisearch/meilisearch-js-plugins/tree/main/packages/instant-meilisearch).
663
655
 
664
656
  <p align="center">
665
- <img src="./assets/restaurant.gif" alt="Fooradvisor demo" width="600"/>
657
+ <img src="./assets/restaurant.gif" alt="Foodadvisor demo" width="600"/>
666
658
  </p>
@@ -4,7 +4,7 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const React = require("react");
5
5
  const reactRouterDom = require("react-router-dom");
6
6
  const admin = require("@strapi/strapi/admin");
7
- const index = require("./index-DpsiLUFK.js");
7
+ const index = require("./index-OgM-GMGo.js");
8
8
  const designSystem = require("@strapi/design-system");
9
9
  function _interopNamespace(e) {
10
10
  if (e && e.__esModule) return e;
@@ -450,7 +450,7 @@ function useAlert() {
450
450
  type = "info",
451
451
  message = i18n(
452
452
  "plugin.message.something",
453
- "Something occured in Meilisearch"
453
+ "Something occurred in Meilisearch"
454
454
  ),
455
455
  link,
456
456
  blockTransition = true,
@@ -3,7 +3,7 @@ import * as React from "react";
3
3
  import { useState, useEffect, memo } from "react";
4
4
  import { Routes, Route } from "react-router-dom";
5
5
  import { useNotification, useFetchClient, useRBAC, private_useAutoReloadOverlayBlocker, private_AutoReloadOverlayBlockerProvider, Page, Layouts, BackButton } from "@strapi/strapi/admin";
6
- import { p as pluginId, P as PERMISSIONS } from "./index-LIHGx_pt.mjs";
6
+ import { p as pluginId, P as PERMISSIONS } from "./index-CnETd4ds.mjs";
7
7
  import { Tr, Td, Checkbox, Typography, Flex, Box, Button, Thead, Th, VisuallyHidden, Table, Tbody, Field, Link, Tabs } from "@strapi/design-system";
8
8
  var __assign = function() {
9
9
  __assign = Object.assign || function __assign2(t) {
@@ -431,7 +431,7 @@ function useAlert() {
431
431
  type = "info",
432
432
  message = i18n(
433
433
  "plugin.message.something",
434
- "Something occured in Meilisearch"
434
+ "Something occurred in Meilisearch"
435
435
  ),
436
436
  link,
437
437
  blockTransition = true,
@@ -31,7 +31,7 @@ const en = {
31
31
  "plugin.message.success.add": "Request to add a content-type is successful",
32
32
  "plugin.message.success.update": "Request to update content-type is successful",
33
33
  "plugin.message.success.credentials": "Credentials successfully updated!",
34
- "plugin.message.something": "Something occured in Meilisearch",
34
+ "plugin.message.something": "Something occurred in Meilisearch",
35
35
  "plugin.message.forbidden.title": "Forbidden",
36
36
  "plugin.message.forbidden.description": "You do not have permission to do this action"
37
37
  };
@@ -29,7 +29,7 @@ const en = {
29
29
  "plugin.message.success.add": "Request to add a content-type is successful",
30
30
  "plugin.message.success.update": "Request to update content-type is successful",
31
31
  "plugin.message.success.credentials": "Credentials successfully updated!",
32
- "plugin.message.something": "Something occured in Meilisearch",
32
+ "plugin.message.something": "Something occurred in Meilisearch",
33
33
  "plugin.message.forbidden.title": "Forbidden",
34
34
  "plugin.message.forbidden.description": "You do not have permission to do this action"
35
35
  };
@@ -18,7 +18,7 @@ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
18
18
  });
19
19
  };
20
20
  const name$1 = "strapi-plugin-meilisearch";
21
- const version = "0.13.1";
21
+ const version = "0.13.2";
22
22
  const description = "Synchronise and search in your Strapi content-types with Meilisearch";
23
23
  const scripts = {
24
24
  build: "strapi-plugin build",
@@ -62,25 +62,25 @@ const files = [
62
62
  const dependencies = {
63
63
  "@strapi/design-system": "^2.0.0-rc.14",
64
64
  "@strapi/icons": "^2.0.0-rc.14",
65
- meilisearch: "^0.45.0"
65
+ meilisearch: "0.48.2"
66
66
  };
67
67
  const peerDependencies = {
68
- "@strapi/sdk-plugin": "^5.2.7",
69
- "@strapi/strapi": "^5.4.1",
68
+ "@strapi/sdk-plugin": "^5.2.8",
69
+ "@strapi/strapi": "^5.6.0",
70
70
  react: "^18.3.1",
71
71
  "react-dom": "^18.3.1",
72
- "react-router-dom": "^6.26.2",
73
- "styled-components": "^6.1.13"
72
+ "react-router-dom": "^6.29.0",
73
+ "styled-components": "^6.1.14"
74
74
  };
75
75
  const devDependencies = {
76
- "@babel/core": "^7.25.2",
77
- "@babel/preset-env": "^7.25.4",
78
- "@strapi/sdk-plugin": "^5.2.7",
79
- "@strapi/strapi": "^5.4.1",
76
+ "@babel/core": "^7.26.7",
77
+ "@babel/preset-env": "^7.26.7",
78
+ "@strapi/sdk-plugin": "^5.2.8",
79
+ "@strapi/strapi": "^5.6.0",
80
80
  "@types/jest": "^29.5.12",
81
81
  "babel-jest": "^29.7.0",
82
82
  concurrently: "^8.2.2",
83
- cypress: "^13.16.0",
83
+ cypress: "^14.0.1",
84
84
  eslint: "^8.2.0",
85
85
  "eslint-config-prettier": "^9.1.0",
86
86
  "eslint-plugin-cypress": "^2.12.1",
@@ -93,8 +93,8 @@ const devDependencies = {
93
93
  prettier: "3.2.5",
94
94
  react: "^18.3.1",
95
95
  "react-dom": "^18.3.1",
96
- "react-router-dom": "^6.26.2",
97
- "styled-components": "^6.1.13"
96
+ "react-router-dom": "^6.29.0",
97
+ "styled-components": "^6.1.14"
98
98
  };
99
99
  const author = {
100
100
  name: "Charlotte Vermandel <charlotte@meilisearch.com>"
@@ -210,7 +210,7 @@ const index = {
210
210
  defaultMessage: name
211
211
  },
212
212
  Component: async () => {
213
- const { App } = await import("./App-DJswI2N8.mjs");
213
+ const { App } = await import("./App-C_AT8Sze.mjs");
214
214
  return App;
215
215
  },
216
216
  permissions: PERMISSIONS.main
@@ -219,7 +219,7 @@ const index = {
219
219
  async registerTrads({ locales }) {
220
220
  const importedTranslations = await Promise.all(
221
221
  locales.map((locale) => {
222
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-BUZC2Pm5.mjs"), "./translations/es.json": () => import("./es-B-4TrEJr.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
222
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-D4dIehJl.mjs"), "./translations/es.json": () => import("./es-B-4TrEJr.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
223
223
  return {
224
224
  data: getTranslation(data),
225
225
  locale
@@ -19,7 +19,7 @@ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
19
19
  });
20
20
  };
21
21
  const name$1 = "strapi-plugin-meilisearch";
22
- const version = "0.13.1";
22
+ const version = "0.13.2";
23
23
  const description = "Synchronise and search in your Strapi content-types with Meilisearch";
24
24
  const scripts = {
25
25
  build: "strapi-plugin build",
@@ -63,25 +63,25 @@ const files = [
63
63
  const dependencies = {
64
64
  "@strapi/design-system": "^2.0.0-rc.14",
65
65
  "@strapi/icons": "^2.0.0-rc.14",
66
- meilisearch: "^0.45.0"
66
+ meilisearch: "0.48.2"
67
67
  };
68
68
  const peerDependencies = {
69
- "@strapi/sdk-plugin": "^5.2.7",
70
- "@strapi/strapi": "^5.4.1",
69
+ "@strapi/sdk-plugin": "^5.2.8",
70
+ "@strapi/strapi": "^5.6.0",
71
71
  react: "^18.3.1",
72
72
  "react-dom": "^18.3.1",
73
- "react-router-dom": "^6.26.2",
74
- "styled-components": "^6.1.13"
73
+ "react-router-dom": "^6.29.0",
74
+ "styled-components": "^6.1.14"
75
75
  };
76
76
  const devDependencies = {
77
- "@babel/core": "^7.25.2",
78
- "@babel/preset-env": "^7.25.4",
79
- "@strapi/sdk-plugin": "^5.2.7",
80
- "@strapi/strapi": "^5.4.1",
77
+ "@babel/core": "^7.26.7",
78
+ "@babel/preset-env": "^7.26.7",
79
+ "@strapi/sdk-plugin": "^5.2.8",
80
+ "@strapi/strapi": "^5.6.0",
81
81
  "@types/jest": "^29.5.12",
82
82
  "babel-jest": "^29.7.0",
83
83
  concurrently: "^8.2.2",
84
- cypress: "^13.16.0",
84
+ cypress: "^14.0.1",
85
85
  eslint: "^8.2.0",
86
86
  "eslint-config-prettier": "^9.1.0",
87
87
  "eslint-plugin-cypress": "^2.12.1",
@@ -94,8 +94,8 @@ const devDependencies = {
94
94
  prettier: "3.2.5",
95
95
  react: "^18.3.1",
96
96
  "react-dom": "^18.3.1",
97
- "react-router-dom": "^6.26.2",
98
- "styled-components": "^6.1.13"
97
+ "react-router-dom": "^6.29.0",
98
+ "styled-components": "^6.1.14"
99
99
  };
100
100
  const author = {
101
101
  name: "Charlotte Vermandel <charlotte@meilisearch.com>"
@@ -211,7 +211,7 @@ const index = {
211
211
  defaultMessage: name
212
212
  },
213
213
  Component: async () => {
214
- const { App } = await Promise.resolve().then(() => require("./App-CIjhihi2.js"));
214
+ const { App } = await Promise.resolve().then(() => require("./App-4wYXCpIt.js"));
215
215
  return App;
216
216
  },
217
217
  permissions: PERMISSIONS.main
@@ -220,7 +220,7 @@ const index = {
220
220
  async registerTrads({ locales }) {
221
221
  const importedTranslations = await Promise.all(
222
222
  locales.map((locale) => {
223
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-CC11ft94.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-DA_jpbS7.js")) }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
223
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-CByedxRT.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-DA_jpbS7.js")) }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
224
224
  return {
225
225
  data: getTranslation(data),
226
226
  locale
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-DpsiLUFK.js");
2
+ const index = require("../_chunks/index-OgM-GMGo.js");
3
3
  module.exports = index.index;
@@ -1,4 +1,4 @@
1
- import { i } from "../_chunks/index-LIHGx_pt.mjs";
1
+ import { i } from "../_chunks/index-CnETd4ds.mjs";
2
2
  export {
3
3
  i as default
4
4
  };
@@ -644,10 +644,10 @@ const contentTypeService = ({ strapi: strapi2 }) => ({
644
644
  const contentTypes = strapi2.contentTypes;
645
645
  const contentTypeUids = Object.keys(contentTypes);
646
646
  if (contentTypeUids.includes(contentType2)) return contentType2;
647
- const contentTypdUid = contentTypeUids.find((uid) => {
647
+ const contentTypeUid = contentTypeUids.find((uid) => {
648
648
  return contentTypes[uid].modelName === contentType2;
649
649
  });
650
- return contentTypdUid;
650
+ return contentTypeUid;
651
651
  },
652
652
  /**
653
653
  * Get the content type uid in this format: "type::service.contentType".
@@ -1346,8 +1346,10 @@ const configurationService = ({ strapi: strapi2 }) => {
1346
1346
  },
1347
1347
  /**
1348
1348
  * Remove language entries.
1349
- * In the plugin entriesQuery, if `locale` is set and not equal to `all`
1350
- * all entries that do not have the specified language are removed.
1349
+ * In the plugin entriesQuery, if `locale` is set and not equal to
1350
+ * `all` (used with the i18n plugin for Strapi) or `*` (used with Strapi 5
1351
+ * native localization), all entries that do not have the specified
1352
+ * language are removed.
1351
1353
  *
1352
1354
  * @param {object} options
1353
1355
  * @param {Array<Object>} options.entries - The entries to filter.
@@ -1359,7 +1361,7 @@ const configurationService = ({ strapi: strapi2 }) => {
1359
1361
  const collection = contentTypeService2.getCollectionName({ contentType: contentType2 });
1360
1362
  const contentTypeConfig = meilisearchConfig[collection] || {};
1361
1363
  const entriesQuery = contentTypeConfig.entriesQuery || {};
1362
- if (!entriesQuery.locale || entriesQuery.locale === "all") {
1364
+ if (!entriesQuery.locale || entriesQuery.locale === "all" || entriesQuery.locale === "*") {
1363
1365
  return entries;
1364
1366
  } else {
1365
1367
  return entries.filter((entry) => entry.locale === entriesQuery.locale);
@@ -1367,7 +1369,7 @@ const configurationService = ({ strapi: strapi2 }) => {
1367
1369
  }
1368
1370
  };
1369
1371
  };
1370
- const version = "0.13.1";
1372
+ const version = "0.13.2";
1371
1373
  const Meilisearch = (config2) => {
1372
1374
  return new meilisearch$1.MeiliSearch({
1373
1375
  ...config2,
@@ -1469,35 +1471,46 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
1469
1471
  const client = Meilisearch({ apiKey, host });
1470
1472
  if (!Array.isArray(entries)) entries = [entries];
1471
1473
  const indexUids = config2.getIndexNamesOfContentType({ contentType: contentType2 });
1472
- await Promise.all(
1474
+ const addDocuments = await sanitizeEntries({
1475
+ contentType: contentType2,
1476
+ entries,
1477
+ config: config2,
1478
+ adapter
1479
+ });
1480
+ const deleteDocuments = entries.filter(
1481
+ (entry) => !addDocuments.map((document) => document.id).includes(entry.id)
1482
+ );
1483
+ const deleteTasks = await Promise.all(
1473
1484
  indexUids.map(async (indexUid) => {
1474
1485
  const tasks = await Promise.all(
1475
- entries.map(async (entry) => {
1476
- const sanitized = await sanitizeEntries({
1477
- entries: [entry],
1478
- contentType: contentType2,
1479
- config: config2,
1480
- adapter
1481
- });
1482
- if (sanitized.length === 0) {
1483
- const task = await client.index(indexUid).deleteDocument(
1484
- adapter.addCollectionNamePrefixToId({
1485
- contentType: contentType2,
1486
- entryId: entry.id
1487
- })
1488
- );
1489
- strapi2.log.info(
1490
- `A task to delete one document from the Meilisearch index "${indexUid}" has been enqueued (Task uid: ${task.taskUid}).`
1491
- );
1492
- return task;
1493
- } else {
1494
- return client.index(indexUid).updateDocuments(sanitized, { primaryKey: "_meilisearch_id" });
1495
- }
1486
+ deleteDocuments.map(async (document) => {
1487
+ const task = await client.index(indexUid).deleteDocument(
1488
+ adapter.addCollectionNamePrefixToId({
1489
+ contentType: contentType2,
1490
+ entryId: document.id
1491
+ })
1492
+ );
1493
+ strapi2.log.info(
1494
+ `A task to delete one document from the Meilisearch index "${indexUid}" has been enqueued (Task uid: ${task.taskUid}).`
1495
+ );
1496
+ return task;
1496
1497
  })
1497
1498
  );
1498
- return tasks.flat();
1499
+ return tasks;
1499
1500
  })
1500
1501
  );
1502
+ const updateTasks = await Promise.all(
1503
+ indexUids.map(async (indexUid) => {
1504
+ const task = client.index(indexUid).updateDocuments(addDocuments, {
1505
+ primaryKey: "_meilisearch_id"
1506
+ });
1507
+ strapi2.log.info(
1508
+ `A task to update ${addDocuments.length} documents to the Meilisearch index "${indexUid}" has been enqueued.`
1509
+ );
1510
+ return task;
1511
+ })
1512
+ );
1513
+ return [...deleteTasks.flat(), ...updateTasks];
1501
1514
  },
1502
1515
  /**
1503
1516
  * Get stats of an index with a safe guard in case of error.
@@ -1827,10 +1840,34 @@ const lifecycleService = ({ strapi: strapi2 }) => {
1827
1840
  );
1828
1841
  });
1829
1842
  },
1830
- async afterCreateMany() {
1831
- strapi2.log.error(
1832
- `Meilisearch does not work with \`afterCreateMany\` hook as the entries are provided without their id`
1833
- );
1843
+ async afterCreateMany(event) {
1844
+ const { result } = event;
1845
+ const meilisearch2 = strapi2.plugin("meilisearch").service("meilisearch");
1846
+ const nbrEntries = result.count;
1847
+ const ids = result.ids;
1848
+ const entries = [];
1849
+ const BATCH_SIZE = 500;
1850
+ for (let pos = 0; pos < nbrEntries; pos += BATCH_SIZE) {
1851
+ const batch = await contentTypeService2.getEntries({
1852
+ contentType: contentTypeUid,
1853
+ start: pos,
1854
+ limit: BATCH_SIZE,
1855
+ filters: {
1856
+ id: {
1857
+ $in: ids
1858
+ }
1859
+ }
1860
+ });
1861
+ entries.push(...batch);
1862
+ }
1863
+ meilisearch2.updateEntriesInMeilisearch({
1864
+ contentType: contentTypeUid,
1865
+ entries
1866
+ }).catch((e) => {
1867
+ strapi2.log.error(
1868
+ `Meilisearch could not update the entries: ${e.message}`
1869
+ );
1870
+ });
1834
1871
  },
1835
1872
  async afterUpdate(event) {
1836
1873
  const { result } = event;
@@ -643,10 +643,10 @@ const contentTypeService = ({ strapi: strapi2 }) => ({
643
643
  const contentTypes = strapi2.contentTypes;
644
644
  const contentTypeUids = Object.keys(contentTypes);
645
645
  if (contentTypeUids.includes(contentType2)) return contentType2;
646
- const contentTypdUid = contentTypeUids.find((uid) => {
646
+ const contentTypeUid = contentTypeUids.find((uid) => {
647
647
  return contentTypes[uid].modelName === contentType2;
648
648
  });
649
- return contentTypdUid;
649
+ return contentTypeUid;
650
650
  },
651
651
  /**
652
652
  * Get the content type uid in this format: "type::service.contentType".
@@ -1345,8 +1345,10 @@ const configurationService = ({ strapi: strapi2 }) => {
1345
1345
  },
1346
1346
  /**
1347
1347
  * Remove language entries.
1348
- * In the plugin entriesQuery, if `locale` is set and not equal to `all`
1349
- * all entries that do not have the specified language are removed.
1348
+ * In the plugin entriesQuery, if `locale` is set and not equal to
1349
+ * `all` (used with the i18n plugin for Strapi) or `*` (used with Strapi 5
1350
+ * native localization), all entries that do not have the specified
1351
+ * language are removed.
1350
1352
  *
1351
1353
  * @param {object} options
1352
1354
  * @param {Array<Object>} options.entries - The entries to filter.
@@ -1358,7 +1360,7 @@ const configurationService = ({ strapi: strapi2 }) => {
1358
1360
  const collection = contentTypeService2.getCollectionName({ contentType: contentType2 });
1359
1361
  const contentTypeConfig = meilisearchConfig[collection] || {};
1360
1362
  const entriesQuery = contentTypeConfig.entriesQuery || {};
1361
- if (!entriesQuery.locale || entriesQuery.locale === "all") {
1363
+ if (!entriesQuery.locale || entriesQuery.locale === "all" || entriesQuery.locale === "*") {
1362
1364
  return entries;
1363
1365
  } else {
1364
1366
  return entries.filter((entry) => entry.locale === entriesQuery.locale);
@@ -1366,7 +1368,7 @@ const configurationService = ({ strapi: strapi2 }) => {
1366
1368
  }
1367
1369
  };
1368
1370
  };
1369
- const version = "0.13.1";
1371
+ const version = "0.13.2";
1370
1372
  const Meilisearch = (config2) => {
1371
1373
  return new MeiliSearch({
1372
1374
  ...config2,
@@ -1468,35 +1470,46 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
1468
1470
  const client = Meilisearch({ apiKey, host });
1469
1471
  if (!Array.isArray(entries)) entries = [entries];
1470
1472
  const indexUids = config2.getIndexNamesOfContentType({ contentType: contentType2 });
1471
- await Promise.all(
1473
+ const addDocuments = await sanitizeEntries({
1474
+ contentType: contentType2,
1475
+ entries,
1476
+ config: config2,
1477
+ adapter
1478
+ });
1479
+ const deleteDocuments = entries.filter(
1480
+ (entry) => !addDocuments.map((document) => document.id).includes(entry.id)
1481
+ );
1482
+ const deleteTasks = await Promise.all(
1472
1483
  indexUids.map(async (indexUid) => {
1473
1484
  const tasks = await Promise.all(
1474
- entries.map(async (entry) => {
1475
- const sanitized = await sanitizeEntries({
1476
- entries: [entry],
1477
- contentType: contentType2,
1478
- config: config2,
1479
- adapter
1480
- });
1481
- if (sanitized.length === 0) {
1482
- const task = await client.index(indexUid).deleteDocument(
1483
- adapter.addCollectionNamePrefixToId({
1484
- contentType: contentType2,
1485
- entryId: entry.id
1486
- })
1487
- );
1488
- strapi2.log.info(
1489
- `A task to delete one document from the Meilisearch index "${indexUid}" has been enqueued (Task uid: ${task.taskUid}).`
1490
- );
1491
- return task;
1492
- } else {
1493
- return client.index(indexUid).updateDocuments(sanitized, { primaryKey: "_meilisearch_id" });
1494
- }
1485
+ deleteDocuments.map(async (document) => {
1486
+ const task = await client.index(indexUid).deleteDocument(
1487
+ adapter.addCollectionNamePrefixToId({
1488
+ contentType: contentType2,
1489
+ entryId: document.id
1490
+ })
1491
+ );
1492
+ strapi2.log.info(
1493
+ `A task to delete one document from the Meilisearch index "${indexUid}" has been enqueued (Task uid: ${task.taskUid}).`
1494
+ );
1495
+ return task;
1495
1496
  })
1496
1497
  );
1497
- return tasks.flat();
1498
+ return tasks;
1498
1499
  })
1499
1500
  );
1501
+ const updateTasks = await Promise.all(
1502
+ indexUids.map(async (indexUid) => {
1503
+ const task = client.index(indexUid).updateDocuments(addDocuments, {
1504
+ primaryKey: "_meilisearch_id"
1505
+ });
1506
+ strapi2.log.info(
1507
+ `A task to update ${addDocuments.length} documents to the Meilisearch index "${indexUid}" has been enqueued.`
1508
+ );
1509
+ return task;
1510
+ })
1511
+ );
1512
+ return [...deleteTasks.flat(), ...updateTasks];
1500
1513
  },
1501
1514
  /**
1502
1515
  * Get stats of an index with a safe guard in case of error.
@@ -1826,10 +1839,34 @@ const lifecycleService = ({ strapi: strapi2 }) => {
1826
1839
  );
1827
1840
  });
1828
1841
  },
1829
- async afterCreateMany() {
1830
- strapi2.log.error(
1831
- `Meilisearch does not work with \`afterCreateMany\` hook as the entries are provided without their id`
1832
- );
1842
+ async afterCreateMany(event) {
1843
+ const { result } = event;
1844
+ const meilisearch2 = strapi2.plugin("meilisearch").service("meilisearch");
1845
+ const nbrEntries = result.count;
1846
+ const ids = result.ids;
1847
+ const entries = [];
1848
+ const BATCH_SIZE = 500;
1849
+ for (let pos = 0; pos < nbrEntries; pos += BATCH_SIZE) {
1850
+ const batch = await contentTypeService2.getEntries({
1851
+ contentType: contentTypeUid,
1852
+ start: pos,
1853
+ limit: BATCH_SIZE,
1854
+ filters: {
1855
+ id: {
1856
+ $in: ids
1857
+ }
1858
+ }
1859
+ });
1860
+ entries.push(...batch);
1861
+ }
1862
+ meilisearch2.updateEntriesInMeilisearch({
1863
+ contentType: contentTypeUid,
1864
+ entries
1865
+ }).catch((e) => {
1866
+ strapi2.log.error(
1867
+ `Meilisearch could not update the entries: ${e.message}`
1868
+ );
1869
+ });
1833
1870
  },
1834
1871
  async afterUpdate(event) {
1835
1872
  const { result } = event;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-meilisearch",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "description": "Synchronise and search in your Strapi content-types with Meilisearch",
5
5
  "scripts": {
6
6
  "build": "strapi-plugin build",
@@ -44,25 +44,25 @@
44
44
  "dependencies": {
45
45
  "@strapi/design-system": "^2.0.0-rc.14",
46
46
  "@strapi/icons": "^2.0.0-rc.14",
47
- "meilisearch": "^0.45.0"
47
+ "meilisearch": "0.48.2"
48
48
  },
49
49
  "peerDependencies": {
50
- "@strapi/sdk-plugin": "^5.2.7",
51
- "@strapi/strapi": "^5.4.1",
50
+ "@strapi/sdk-plugin": "^5.2.8",
51
+ "@strapi/strapi": "^5.6.0",
52
52
  "react": "^18.3.1",
53
53
  "react-dom": "^18.3.1",
54
- "react-router-dom": "^6.26.2",
55
- "styled-components": "^6.1.13"
54
+ "react-router-dom": "^6.29.0",
55
+ "styled-components": "^6.1.14"
56
56
  },
57
57
  "devDependencies": {
58
- "@babel/core": "^7.25.2",
59
- "@babel/preset-env": "^7.25.4",
60
- "@strapi/sdk-plugin": "^5.2.7",
61
- "@strapi/strapi": "^5.4.1",
58
+ "@babel/core": "^7.26.7",
59
+ "@babel/preset-env": "^7.26.7",
60
+ "@strapi/sdk-plugin": "^5.2.8",
61
+ "@strapi/strapi": "^5.6.0",
62
62
  "@types/jest": "^29.5.12",
63
63
  "babel-jest": "^29.7.0",
64
64
  "concurrently": "^8.2.2",
65
- "cypress": "^13.16.0",
65
+ "cypress": "^14.0.1",
66
66
  "eslint": "^8.2.0",
67
67
  "eslint-config-prettier": "^9.1.0",
68
68
  "eslint-plugin-cypress": "^2.12.1",
@@ -75,8 +75,8 @@
75
75
  "prettier": "3.2.5",
76
76
  "react": "^18.3.1",
77
77
  "react-dom": "^18.3.1",
78
- "react-router-dom": "^6.26.2",
79
- "styled-components": "^6.1.13"
78
+ "react-router-dom": "^6.29.0",
79
+ "styled-components": "^6.1.14"
80
80
  },
81
81
  "author": {
82
82
  "name": "Charlotte Vermandel <charlotte@meilisearch.com>"
@@ -105,4 +105,4 @@
105
105
  "url": "git+https://github.com/meilisearch/strapi-plugin-meilisearch.git"
106
106
  },
107
107
  "homepage": "https://github.com/meilisearch/strapi-plugin-meilisearch#readme"
108
- }
108
+ }