strapi-plugin-meilisearch 0.16.2 → 0.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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-B13pYJxT.js");
7
+ const index = require("./index-CAsW5hZR.js");
8
8
  const designSystem = require("@strapi/design-system");
9
9
  function _interopNamespace(e) {
10
10
  if (e && e.__esModule) return e;
@@ -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-D0WRGIBD.mjs";
6
+ import { p as pluginId, P as PERMISSIONS } from "./index-L3fjpmC9.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) {
@@ -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.16.2";
22
+ const version = "0.16.4";
23
23
  const description = "Synchronise and search in your Strapi content-types with Meilisearch";
24
24
  const scripts = {
25
25
  build: "strapi-plugin build",
@@ -216,7 +216,7 @@ const index = {
216
216
  defaultMessage: name
217
217
  },
218
218
  Component: async () => {
219
- const { App } = await Promise.resolve().then(() => require("./App-B3uJ14YG.js"));
219
+ const { App } = await Promise.resolve().then(() => require("./App-DN63hpzO.js"));
220
220
  return App;
221
221
  },
222
222
  permissions: PERMISSIONS.main
@@ -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.16.2";
21
+ const version = "0.16.4";
22
22
  const description = "Synchronise and search in your Strapi content-types with Meilisearch";
23
23
  const scripts = {
24
24
  build: "strapi-plugin build",
@@ -215,7 +215,7 @@ const index = {
215
215
  defaultMessage: name
216
216
  },
217
217
  Component: async () => {
218
- const { App } = await import("./App-BmxrI4i3.mjs");
218
+ const { App } = await import("./App-DsNeH1hv.mjs");
219
219
  return App;
220
220
  },
221
221
  permissions: PERMISSIONS.main
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-B13pYJxT.js");
2
+ const index = require("../_chunks/index-CAsW5hZR.js");
3
3
  module.exports = index.index;
@@ -1,4 +1,4 @@
1
- import { i } from "../_chunks/index-D0WRGIBD.mjs";
1
+ import { i } from "../_chunks/index-L3fjpmC9.mjs";
2
2
  export {
3
3
  i as default
4
4
  };
@@ -322,88 +322,290 @@ const configurationService = ({ strapi: strapi2 }) => {
322
322
  }
323
323
  };
324
324
  };
325
- async function registerDocumentMiddleware({ strapi: strapi2 }) {
326
- if (!strapi2?.documents || typeof strapi2.documents.use !== "function") {
327
- return;
328
- }
329
- const extractEntryCandidates = (result) => {
330
- if (result == null) return [];
331
- const candidates = [];
332
- const appendCandidate = (data, source) => {
333
- if (data != null && typeof data === "object") {
334
- candidates.push({ data, source });
335
- }
336
- };
337
- if (Array.isArray(result)) {
338
- result.forEach((data) => appendCandidate(data, "root"));
339
- return candidates;
340
- }
341
- appendCandidate(result, "root");
342
- if (Array.isArray(result.versions)) {
343
- result.versions.forEach((data) => appendCandidate(data, "versions"));
344
- }
345
- if (Array.isArray(result.entries)) {
346
- result.entries.forEach((data) => appendCandidate(data, "entries"));
325
+ const resolveDocumentIdsFromActionParams = (actionParams) => {
326
+ const explicitDocumentIds = Array.isArray(actionParams?.documentIds) ? actionParams.documentIds.filter(
327
+ (documentId) => typeof documentId === "string" && documentId.length > 0
328
+ ) : [];
329
+ const singleDocumentId = typeof actionParams?.documentId === "string" && actionParams.documentId.length > 0 ? [actionParams.documentId] : [];
330
+ return [.../* @__PURE__ */ new Set([...explicitDocumentIds, ...singleDocumentId])];
331
+ };
332
+ const resolveDocumentIds = ({
333
+ actionParams,
334
+ result,
335
+ preActionSnapshots
336
+ }) => {
337
+ const ids = [...resolveDocumentIdsFromActionParams(actionParams)];
338
+ const appendDocumentId = (documentId) => {
339
+ if (typeof documentId === "string" && documentId.length > 0) {
340
+ ids.push(documentId);
347
341
  }
348
- if (result.entry != null) {
349
- appendCandidate(result.entry, "entry");
342
+ };
343
+ const inspectCandidate = (candidate) => {
344
+ if (!candidate || typeof candidate !== "object") return;
345
+ appendDocumentId(candidate.documentId);
346
+ };
347
+ if (Array.isArray(result)) {
348
+ result.forEach(inspectCandidate);
349
+ } else {
350
+ inspectCandidate(result);
351
+ }
352
+ (preActionSnapshots || []).forEach(
353
+ (snapshot) => appendDocumentId(snapshot?.documentId)
354
+ );
355
+ return [...new Set(ids)];
356
+ };
357
+ const extractStrapiEntryCandidates = (result) => {
358
+ if (result == null) return [];
359
+ const candidates = [];
360
+ const appendCandidate = (data, source) => {
361
+ if (data != null && typeof data === "object") {
362
+ candidates.push({ data, source });
350
363
  }
351
- return candidates;
352
364
  };
353
- const isPublishedEntry = (entry) => !(entry?.publishedAt === void 0 || entry?.publishedAt === null);
354
- const rankEntryCandidates = (candidates) => {
355
- return [...candidates].sort((a, b) => {
356
- const aHasPrimaryKey = a.data?.id != null;
357
- const bHasPrimaryKey = b.data?.id != null;
358
- if (aHasPrimaryKey && !bHasPrimaryKey) return -1;
359
- if (!aHasPrimaryKey && bHasPrimaryKey) return 1;
360
- const aIsRoot = a.source === "root";
361
- const bIsRoot = b.source === "root";
362
- if (!aIsRoot && bIsRoot) return -1;
363
- if (aIsRoot && !bIsRoot) return 1;
364
- return 0;
365
- });
365
+ if (Array.isArray(result)) {
366
+ result.forEach((data) => appendCandidate(data, "root"));
367
+ return candidates;
368
+ }
369
+ appendCandidate(result, "root");
370
+ if (Array.isArray(result.versions)) {
371
+ result.versions.forEach((data) => appendCandidate(data, "versions"));
372
+ }
373
+ if (Array.isArray(result.entries)) {
374
+ result.entries.forEach((data) => appendCandidate(data, "entries"));
375
+ }
376
+ if (result.entry != null) {
377
+ appendCandidate(result.entry, "entry");
378
+ }
379
+ return candidates;
380
+ };
381
+ const isPublishedStrapiEntry = (entry) => !(entry?.publishedAt === void 0 || entry?.publishedAt === null);
382
+ const rankStrapiEntryCandidates = (candidates) => {
383
+ return [...candidates].sort((a, b) => {
384
+ const aHasPrimaryKey = a.data?.id != null;
385
+ const bHasPrimaryKey = b.data?.id != null;
386
+ if (aHasPrimaryKey && !bHasPrimaryKey) return -1;
387
+ if (!aHasPrimaryKey && bHasPrimaryKey) return 1;
388
+ const aIsRoot = a.source === "root";
389
+ const bIsRoot = b.source === "root";
390
+ if (!aIsRoot && bIsRoot) return -1;
391
+ if (aIsRoot && !bIsRoot) return 1;
392
+ return 0;
393
+ });
394
+ };
395
+ const getActionLocale = (actionParams) => {
396
+ return typeof actionParams?.locale === "string" && actionParams.locale.length > 0 ? actionParams.locale : null;
397
+ };
398
+ const resolveLocaleScopedRefetchQuery = ({
399
+ indexingQuery,
400
+ actionParams
401
+ }) => {
402
+ const actionLocale = getActionLocale(actionParams);
403
+ const baseQuery = { ...indexingQuery || {} };
404
+ if (!isWildcardLocale(baseQuery.locale) || actionLocale == null) {
405
+ return baseQuery;
406
+ }
407
+ return {
408
+ ...baseQuery,
409
+ locale: actionLocale
366
410
  };
367
- const getEntryFromResult = ({
368
- resultCandidates,
369
- documentId,
370
- entriesQuery
371
- }) => {
372
- const documentCandidates = (resultCandidates || []).filter(
373
- (candidate) => candidate?.data?.documentId === documentId
411
+ };
412
+ const resolveLocaleCodesToRemoveFromIndex = ({
413
+ actionParams,
414
+ preDeleteStrapiEntry,
415
+ localeVariants
416
+ }) => {
417
+ const actionLocale = getActionLocale(actionParams);
418
+ if (actionLocale && !isWildcardLocale(actionLocale)) {
419
+ return [actionLocale];
420
+ }
421
+ if (actionLocale == null) {
422
+ return typeof preDeleteStrapiEntry?.locale === "string" && preDeleteStrapiEntry.locale.length > 0 ? [preDeleteStrapiEntry.locale] : [];
423
+ }
424
+ return [
425
+ ...new Set(
426
+ (localeVariants || []).map((entry) => entry?.locale).filter((locale) => typeof locale === "string" && locale.length > 0)
427
+ )
428
+ ];
429
+ };
430
+ const collectLocaleCodesFromEntries = (entries) => {
431
+ return [
432
+ ...new Set(
433
+ (entries || []).map((entry) => entry?.locale).filter((locale) => typeof locale === "string" && locale.length > 0)
434
+ )
435
+ ];
436
+ };
437
+ const selectDraftEntriesForDiscardDraftResult = ({
438
+ resultCandidates,
439
+ documentId,
440
+ actionParams
441
+ }) => {
442
+ const actionLocale = getActionLocale(actionParams);
443
+ const rankedDraftEntryCandidates = rankStrapiEntryCandidates(
444
+ (resultCandidates || []).filter(
445
+ (candidate) => candidate?.data?.documentId === documentId && !isPublishedStrapiEntry(candidate.data)
446
+ )
447
+ );
448
+ const rankedLocalizedDraftEntryCandidates = rankedDraftEntryCandidates.filter(
449
+ (candidate) => typeof candidate?.data?.locale === "string" && candidate.data.locale.length > 0
450
+ );
451
+ if (rankedDraftEntryCandidates.length === 0) return [];
452
+ if (actionLocale && !isWildcardLocale(actionLocale)) {
453
+ const localeCandidate = rankedLocalizedDraftEntryCandidates.find(
454
+ (candidate) => candidate?.data?.locale === actionLocale
374
455
  );
375
- if (documentCandidates.length === 0) return null;
376
- const rankedCandidates = rankEntryCandidates(documentCandidates);
377
- if (entriesQuery?.status === "draft") {
378
- const draftCandidate = rankedCandidates.find(
379
- (candidate) => !isPublishedEntry(candidate.data)
380
- );
381
- return draftCandidate?.data || rankedCandidates[0]?.data || null;
456
+ return localeCandidate ? [localeCandidate.data] : [];
457
+ }
458
+ if (actionLocale && isWildcardLocale(actionLocale)) {
459
+ const entriesByLocale = /* @__PURE__ */ new Map();
460
+ rankedLocalizedDraftEntryCandidates.forEach((candidate) => {
461
+ const locale = candidate.data.locale;
462
+ if (!entriesByLocale.has(locale)) {
463
+ entriesByLocale.set(locale, candidate.data);
464
+ }
465
+ });
466
+ return [...entriesByLocale.values()];
467
+ }
468
+ return [
469
+ rankedLocalizedDraftEntryCandidates[0]?.data || rankedDraftEntryCandidates[0].data
470
+ ];
471
+ };
472
+ const fetchSingleEntryAfterTransaction = ({
473
+ contentTypeService: contentTypeService2,
474
+ contentType: contentType2,
475
+ documentId,
476
+ indexingQuery
477
+ }) => new Promise((resolve, reject) => {
478
+ setImmediate(async () => {
479
+ try {
480
+ const strapiEntry = await contentTypeService2.getEntry({
481
+ contentType: contentType2,
482
+ documentId,
483
+ entriesQuery: { ...indexingQuery || {} }
484
+ });
485
+ resolve(strapiEntry);
486
+ } catch (error2) {
487
+ reject(error2);
382
488
  }
383
- const publishedCandidate = rankedCandidates.find(
384
- (candidate) => isPublishedEntry(candidate.data)
385
- );
386
- return publishedCandidate?.data || null;
387
- };
388
- const getEntryOutsideTransaction = ({
389
- contentTypeService: contentTypeService2,
489
+ });
490
+ });
491
+ const fetchWildcardLocaleEntriesForIndexing = ({
492
+ contentTypeService: contentTypeService2,
493
+ contentType: contentType2,
494
+ documentId,
495
+ indexingQuery
496
+ }) => {
497
+ const baseIndexingQuery = indexingQuery || {};
498
+ return contentTypeService2.getEntries({
499
+ contentType: contentType2,
500
+ ...baseIndexingQuery,
501
+ locale: "*",
502
+ filters: {
503
+ ...baseIndexingQuery.filters || {},
504
+ documentId
505
+ }
506
+ });
507
+ };
508
+ const buildPreActionSnapshot = async ({
509
+ contentTypeService: contentTypeService2,
510
+ contentType: contentType2,
511
+ documentId,
512
+ indexingStatusFilter,
513
+ actionParams,
514
+ indexingQueryUsesWildcardLocale
515
+ }) => {
516
+ const preDeleteStrapiEntry = await contentTypeService2.getEntry({
390
517
  contentType: contentType2,
391
518
  documentId,
392
- entriesQuery
393
- }) => new Promise((resolve, reject) => {
394
- setImmediate(async () => {
395
- try {
396
- const entry = await contentTypeService2.getEntry({
397
- contentType: contentType2,
398
- documentId,
399
- entriesQuery: { ...entriesQuery }
400
- });
401
- resolve(entry);
402
- } catch (error2) {
403
- reject(error2);
404
- }
519
+ entriesQuery: { ...indexingStatusFilter || {} }
520
+ });
521
+ const shouldFetchLocaleVariants = indexingQueryUsesWildcardLocale && isWildcardLocale(actionParams?.locale);
522
+ const localeVariants = shouldFetchLocaleVariants ? await contentTypeService2.getEntries({
523
+ contentType: contentType2,
524
+ fields: ["documentId", "locale"],
525
+ locale: "*",
526
+ ...indexingStatusFilter || {},
527
+ filters: {
528
+ documentId
529
+ }
530
+ }) : [];
531
+ const localeCodesToRemove = indexingQueryUsesWildcardLocale ? resolveLocaleCodesToRemoveFromIndex({
532
+ actionParams,
533
+ preDeleteStrapiEntry,
534
+ localeVariants
535
+ }) : [];
536
+ return {
537
+ documentId,
538
+ preDeleteStrapiEntry,
539
+ localeVariants,
540
+ localeCodesToRemove
541
+ };
542
+ };
543
+ const collectPreActionSnapshots = async ({
544
+ documentIds,
545
+ contentTypeService: contentTypeService2,
546
+ contentType: contentType2,
547
+ indexingStatusFilter,
548
+ actionParams,
549
+ indexingQueryUsesWildcardLocale
550
+ }) => {
551
+ return Promise.all(
552
+ documentIds.map(
553
+ (documentId) => buildPreActionSnapshot({
554
+ contentTypeService: contentTypeService2,
555
+ contentType: contentType2,
556
+ documentId,
557
+ indexingStatusFilter,
558
+ actionParams,
559
+ indexingQueryUsesWildcardLocale
560
+ })
561
+ )
562
+ );
563
+ };
564
+ const normalizeLocaleCodes = (localeCodes) => {
565
+ return [
566
+ ...new Set(
567
+ (localeCodes || []).filter((locale) => typeof locale === "string" && locale.length > 0).map((locale) => locale.trim())
568
+ )
569
+ ];
570
+ };
571
+ const dispatchDeleteTargets = async ({
572
+ meilisearch: meilisearch2,
573
+ contentType: contentType2,
574
+ indexingQuery,
575
+ indexingQueryUsesWildcardLocale,
576
+ targets
577
+ }) => {
578
+ const validTargets = (targets || []).filter(
579
+ (target) => target && typeof target.documentId === "string" && target.documentId.length > 0
580
+ );
581
+ if (validTargets.length === 0) return;
582
+ const groupedTargets = /* @__PURE__ */ new Map();
583
+ validTargets.forEach((target) => {
584
+ const localeCodes = indexingQueryUsesWildcardLocale ? normalizeLocaleCodes(target.localeCodes) : [];
585
+ const groupKey = localeCodes.length > 0 ? [...localeCodes].sort().join("|") : "__no-locales__";
586
+ const currentGroup = groupedTargets.get(groupKey);
587
+ if (currentGroup) {
588
+ currentGroup.documentIds.push(target.documentId);
589
+ return;
590
+ }
591
+ groupedTargets.set(groupKey, {
592
+ documentIds: [target.documentId],
593
+ localeCodes
405
594
  });
406
595
  });
596
+ for (const group of groupedTargets.values()) {
597
+ await meilisearch2.deleteEntriesFromMeiliSearch({
598
+ contentType: contentType2,
599
+ documentIds: [...new Set(group.documentIds)],
600
+ entriesQuery: indexingQuery,
601
+ locales: indexingQueryUsesWildcardLocale && group.localeCodes.length > 0 ? group.localeCodes : void 0
602
+ });
603
+ }
604
+ };
605
+ async function registerDocumentMiddleware({ strapi: strapi2 }) {
606
+ if (!strapi2?.documents || typeof strapi2.documents.use !== "function") {
607
+ return;
608
+ }
407
609
  strapi2.documents.use(async (ctx, next) => {
408
610
  let result;
409
611
  try {
@@ -425,83 +627,183 @@ async function registerDocumentMiddleware({ strapi: strapi2 }) {
425
627
  "unpublish",
426
628
  "discardDraft"
427
629
  ];
428
- const entriesQuery = meilisearch2.entriesQuery({ contentType: contentType2 });
429
- const shouldDeleteByLocale = isWildcardLocale(entriesQuery.locale);
430
- const { status } = entriesQuery || {};
431
- const statusFilter = typeof status === "string" && status.length > 0 ? { status } : {};
432
- const preDeleteDocumentId = deleteActions.includes(ctx.action) && ctx?.params?.documentId ? ctx.params.documentId : null;
433
- let preDeleteEntry = null;
434
- let preDeleteLocales = [];
435
- if (preDeleteDocumentId != null) {
436
- preDeleteEntry = await contentTypeService2.getEntry({
437
- contentType: contentType2,
438
- documentId: preDeleteDocumentId,
439
- entriesQuery: { ...statusFilter }
440
- });
441
- if (shouldDeleteByLocale) {
442
- const localeVariants = await contentTypeService2.getEntries({
443
- contentType: contentType2,
444
- fields: ["documentId", "locale"],
445
- locale: "*",
446
- ...statusFilter,
447
- filters: {
448
- documentId: preDeleteDocumentId
449
- }
450
- });
451
- preDeleteLocales = [
452
- ...new Set(
453
- localeVariants.map((entry) => entry?.locale).filter(
454
- (locale) => typeof locale === "string" && locale.length > 0
455
- )
456
- )
457
- ];
458
- }
459
- }
630
+ const indexingQuery = meilisearch2.entriesQuery({ contentType: contentType2 });
631
+ const indexingQueryUsesWildcardLocale = isWildcardLocale(
632
+ indexingQuery.locale
633
+ );
634
+ const { status } = indexingQuery || {};
635
+ const indexingStatusFilter = typeof status === "string" && status.length > 0 ? { status } : {};
636
+ const isDraftIndex = status === "draft";
637
+ const isPublishedIndex = status === "published";
638
+ const shouldSkipDeleteAction = ctx.action === "unpublish" && isDraftIndex || ctx.action === "discardDraft" && isPublishedIndex;
639
+ const shouldProcessAsRefetchFirstIndexingAction = updateActions.includes(ctx.action) || ctx.action === "discardDraft" && isDraftIndex;
640
+ const shouldProcessAsDeleteAction = deleteActions.includes(ctx.action) && !shouldProcessAsRefetchFirstIndexingAction && !shouldSkipDeleteAction;
641
+ const preActionDocumentIds = resolveDocumentIdsFromActionParams(
642
+ ctx?.params
643
+ );
644
+ const shouldCollectPreActionSnapshots = shouldProcessAsDeleteAction || ctx.action === "discardDraft" && isDraftIndex;
645
+ const preActionSnapshots = shouldCollectPreActionSnapshots ? await collectPreActionSnapshots({
646
+ documentIds: preActionDocumentIds,
647
+ contentTypeService: contentTypeService2,
648
+ contentType: contentType2,
649
+ indexingStatusFilter,
650
+ actionParams: ctx?.params,
651
+ indexingQueryUsesWildcardLocale
652
+ }) : [];
653
+ const preActionSnapshotsByDocumentId = new Map(
654
+ preActionSnapshots.map((snapshot) => [snapshot.documentId, snapshot])
655
+ );
460
656
  result = await next();
461
- const contextDocumentId = typeof ctx?.params?.documentId === "string" && ctx.params.documentId.length > 0 ? ctx.params.documentId : null;
462
- const documentId = contextDocumentId ?? result?.documentId ?? preDeleteEntry?.documentId ?? preDeleteDocumentId ?? null;
463
- if (updateActions.includes(ctx.action) && documentId != null) {
464
- const resultCandidates = extractEntryCandidates(result);
465
- let entry = getEntryFromResult({
466
- resultCandidates,
467
- documentId,
468
- entriesQuery
469
- });
470
- if (!entry) {
471
- entry = await getEntryOutsideTransaction({
472
- contentTypeService: contentTypeService2,
473
- contentType: contentType2,
474
- documentId,
475
- entriesQuery
657
+ const documentIds = resolveDocumentIds({
658
+ actionParams: ctx?.params,
659
+ result,
660
+ preActionSnapshots
661
+ });
662
+ if (shouldProcessAsRefetchFirstIndexingAction && documentIds.length > 0) {
663
+ const actionResultCandidates = extractStrapiEntryCandidates(result);
664
+ const entriesToIndex = [];
665
+ const deleteTargets = [];
666
+ for (const documentId of documentIds) {
667
+ if (ctx.action === "discardDraft" && isDraftIndex) {
668
+ const preActionSnapshot = preActionSnapshotsByDocumentId.get(documentId) || null;
669
+ const actionLocale2 = getActionLocale(ctx?.params);
670
+ const shouldLoadDraftEntriesAcrossLocales = indexingQueryUsesWildcardLocale && isWildcardLocale(actionLocale2);
671
+ const draftEntriesFromActionResult = selectDraftEntriesForDiscardDraftResult({
672
+ resultCandidates: actionResultCandidates,
673
+ documentId,
674
+ actionParams: ctx?.params
675
+ });
676
+ let draftEntriesToIndex = shouldLoadDraftEntriesAcrossLocales ? await contentTypeService2.getEntries({
677
+ contentType: contentType2,
678
+ locale: "*",
679
+ ...indexingStatusFilter,
680
+ filters: {
681
+ documentId
682
+ }
683
+ }) : draftEntriesFromActionResult;
684
+ draftEntriesToIndex = (draftEntriesToIndex || []).filter(
685
+ (entry) => entry && !isPublishedStrapiEntry(entry)
686
+ );
687
+ if (draftEntriesToIndex.length === 0 && shouldLoadDraftEntriesAcrossLocales) {
688
+ draftEntriesToIndex = draftEntriesFromActionResult;
689
+ }
690
+ if (draftEntriesToIndex.length === 0 && !shouldLoadDraftEntriesAcrossLocales) {
691
+ const refetchedDraftEntry = await fetchSingleEntryAfterTransaction({
692
+ contentTypeService: contentTypeService2,
693
+ contentType: contentType2,
694
+ documentId,
695
+ indexingQuery: resolveLocaleScopedRefetchQuery({
696
+ indexingQuery,
697
+ actionParams: ctx?.params
698
+ })
699
+ });
700
+ if (refetchedDraftEntry && !isPublishedStrapiEntry(refetchedDraftEntry)) {
701
+ draftEntriesToIndex = [refetchedDraftEntry];
702
+ }
703
+ }
704
+ if (draftEntriesToIndex.length > 0) {
705
+ const normalizedDraftEntries = draftEntriesToIndex.map(
706
+ (entry) => entry.documentId === documentId ? entry : { ...entry, documentId }
707
+ );
708
+ entriesToIndex.push(...normalizedDraftEntries);
709
+ }
710
+ const preActionLocaleCodes = resolveLocaleCodesToRemoveFromIndex({
711
+ actionParams: ctx?.params,
712
+ preDeleteStrapiEntry: preActionSnapshot?.preDeleteStrapiEntry || null,
713
+ localeVariants: preActionSnapshot?.localeVariants || []
714
+ });
715
+ const remainingLocaleCodes = collectLocaleCodesFromEntries(draftEntriesToIndex);
716
+ const localeCodesToDelete = preActionLocaleCodes.filter(
717
+ (localeCode) => !remainingLocaleCodes.includes(localeCode)
718
+ );
719
+ if (localeCodesToDelete.length > 0) {
720
+ deleteTargets.push({
721
+ documentId,
722
+ localeCodes: localeCodesToDelete
723
+ });
724
+ }
725
+ continue;
726
+ }
727
+ let refetchedEntriesForDocument = [];
728
+ const actionLocale = getActionLocale(ctx?.params);
729
+ const localeScopedRefetchQuery = resolveLocaleScopedRefetchQuery({
730
+ indexingQuery,
731
+ actionParams: ctx?.params
476
732
  });
733
+ const indexingQueryStoresDrafts = indexingQuery?.status === "draft";
734
+ const shouldRefetchAllLocales = indexingQueryUsesWildcardLocale && isWildcardLocale(actionLocale) && isWildcardLocale(indexingQuery?.locale) && !indexingQueryStoresDrafts;
735
+ if (shouldRefetchAllLocales) {
736
+ refetchedEntriesForDocument = await fetchWildcardLocaleEntriesForIndexing({
737
+ contentTypeService: contentTypeService2,
738
+ contentType: contentType2,
739
+ documentId,
740
+ indexingQuery
741
+ });
742
+ } else {
743
+ const refetchedStrapiEntry = await fetchSingleEntryAfterTransaction(
744
+ {
745
+ contentTypeService: contentTypeService2,
746
+ contentType: contentType2,
747
+ documentId,
748
+ indexingQuery: localeScopedRefetchQuery
749
+ }
750
+ );
751
+ if (refetchedStrapiEntry) {
752
+ refetchedEntriesForDocument = [refetchedStrapiEntry];
753
+ }
754
+ }
755
+ if (refetchedEntriesForDocument.length > 0) {
756
+ const normalizedEntries = refetchedEntriesForDocument.map(
757
+ (entry) => entry.documentId === documentId ? entry : { ...entry, documentId }
758
+ );
759
+ entriesToIndex.push(...normalizedEntries);
760
+ } else if (ctx.action === "create" || ctx.action === "publish") {
761
+ const createPublishLocaleCodesToRemove = indexingQueryUsesWildcardLocale && typeof localeScopedRefetchQuery?.locale === "string" && localeScopedRefetchQuery.locale.length > 0 && !isWildcardLocale(localeScopedRefetchQuery.locale) ? [localeScopedRefetchQuery.locale] : [];
762
+ if (createPublishLocaleCodesToRemove.length > 0) {
763
+ deleteTargets.push({
764
+ documentId,
765
+ localeCodes: createPublishLocaleCodesToRemove
766
+ });
767
+ }
768
+ } else {
769
+ strapi2.log.info(
770
+ `Meilisearch document middleware skipped indexing ${contentType2} documentId=${documentId} for action ${ctx.action}: no indexable Strapi entry after refetch`
771
+ );
772
+ }
477
773
  }
478
- if (entry) {
479
- const normalizedEntry = entry.documentId === documentId ? entry : { ...entry, documentId };
774
+ if (entriesToIndex.length > 0) {
480
775
  await meilisearch2.updateEntriesInMeilisearch({
481
776
  contentType: contentType2,
482
- entries: [normalizedEntry]
777
+ entries: entriesToIndex
483
778
  });
484
- } else if (ctx.action === "create" || ctx.action === "publish") {
485
- await meilisearch2.deleteEntriesFromMeiliSearch({
779
+ }
780
+ if (deleteTargets.length > 0) {
781
+ await dispatchDeleteTargets({
782
+ meilisearch: meilisearch2,
486
783
  contentType: contentType2,
487
- documentIds: [documentId],
488
- entriesQuery
784
+ indexingQuery,
785
+ indexingQueryUsesWildcardLocale,
786
+ targets: deleteTargets
489
787
  });
490
- } else {
491
- strapi2.log.info(
492
- `Meilisearch document middleware skipped indexing ${contentType2} documentId=${documentId} for action ${ctx.action}: no indexable entry in result payload`
493
- );
494
788
  }
495
- } else if (deleteActions.includes(ctx.action)) {
496
- if (documentId != null) {
789
+ } else if (shouldProcessAsDeleteAction) {
790
+ if (documentIds.length > 0) {
791
+ const deleteTargets = documentIds.map((documentId) => {
792
+ const preActionSnapshot = preActionSnapshotsByDocumentId.get(documentId) || null;
793
+ return {
794
+ documentId,
795
+ localeCodes: indexingQueryUsesWildcardLocale ? preActionSnapshot?.localeCodesToRemove || [] : []
796
+ };
797
+ });
497
798
  strapi2.log.info(
498
- `Meilisearch document middleware deleting ${contentType2} documentId=${documentId}`
799
+ `Meilisearch document middleware deleting ${contentType2} documentIds=${documentIds.join(",")}`
499
800
  );
500
- await meilisearch2.deleteEntriesFromMeiliSearch({
801
+ await dispatchDeleteTargets({
802
+ meilisearch: meilisearch2,
501
803
  contentType: contentType2,
502
- documentIds: [documentId],
503
- entriesQuery,
504
- locales: shouldDeleteByLocale && preDeleteLocales.length > 0 ? preDeleteLocales : void 0
804
+ indexingQuery,
805
+ indexingQueryUsesWildcardLocale,
806
+ targets: deleteTargets
505
807
  });
506
808
  } else {
507
809
  strapi2.log.info(
@@ -1636,7 +1938,7 @@ const store = ({ strapi: strapi2 }) => {
1636
1938
  ...createStoreConnector({ strapi: strapi2 })
1637
1939
  };
1638
1940
  };
1639
- const version = "0.16.2";
1941
+ const version = "0.16.4";
1640
1942
  const Meilisearch = (config2) => {
1641
1943
  return new meilisearch$1.MeiliSearch({
1642
1944
  ...config2,
@@ -321,88 +321,290 @@ const configurationService = ({ strapi: strapi2 }) => {
321
321
  }
322
322
  };
323
323
  };
324
- async function registerDocumentMiddleware({ strapi: strapi2 }) {
325
- if (!strapi2?.documents || typeof strapi2.documents.use !== "function") {
326
- return;
327
- }
328
- const extractEntryCandidates = (result) => {
329
- if (result == null) return [];
330
- const candidates = [];
331
- const appendCandidate = (data, source) => {
332
- if (data != null && typeof data === "object") {
333
- candidates.push({ data, source });
334
- }
335
- };
336
- if (Array.isArray(result)) {
337
- result.forEach((data) => appendCandidate(data, "root"));
338
- return candidates;
339
- }
340
- appendCandidate(result, "root");
341
- if (Array.isArray(result.versions)) {
342
- result.versions.forEach((data) => appendCandidate(data, "versions"));
343
- }
344
- if (Array.isArray(result.entries)) {
345
- result.entries.forEach((data) => appendCandidate(data, "entries"));
324
+ const resolveDocumentIdsFromActionParams = (actionParams) => {
325
+ const explicitDocumentIds = Array.isArray(actionParams?.documentIds) ? actionParams.documentIds.filter(
326
+ (documentId) => typeof documentId === "string" && documentId.length > 0
327
+ ) : [];
328
+ const singleDocumentId = typeof actionParams?.documentId === "string" && actionParams.documentId.length > 0 ? [actionParams.documentId] : [];
329
+ return [.../* @__PURE__ */ new Set([...explicitDocumentIds, ...singleDocumentId])];
330
+ };
331
+ const resolveDocumentIds = ({
332
+ actionParams,
333
+ result,
334
+ preActionSnapshots
335
+ }) => {
336
+ const ids = [...resolveDocumentIdsFromActionParams(actionParams)];
337
+ const appendDocumentId = (documentId) => {
338
+ if (typeof documentId === "string" && documentId.length > 0) {
339
+ ids.push(documentId);
346
340
  }
347
- if (result.entry != null) {
348
- appendCandidate(result.entry, "entry");
341
+ };
342
+ const inspectCandidate = (candidate) => {
343
+ if (!candidate || typeof candidate !== "object") return;
344
+ appendDocumentId(candidate.documentId);
345
+ };
346
+ if (Array.isArray(result)) {
347
+ result.forEach(inspectCandidate);
348
+ } else {
349
+ inspectCandidate(result);
350
+ }
351
+ (preActionSnapshots || []).forEach(
352
+ (snapshot) => appendDocumentId(snapshot?.documentId)
353
+ );
354
+ return [...new Set(ids)];
355
+ };
356
+ const extractStrapiEntryCandidates = (result) => {
357
+ if (result == null) return [];
358
+ const candidates = [];
359
+ const appendCandidate = (data, source) => {
360
+ if (data != null && typeof data === "object") {
361
+ candidates.push({ data, source });
349
362
  }
350
- return candidates;
351
363
  };
352
- const isPublishedEntry = (entry) => !(entry?.publishedAt === void 0 || entry?.publishedAt === null);
353
- const rankEntryCandidates = (candidates) => {
354
- return [...candidates].sort((a, b) => {
355
- const aHasPrimaryKey = a.data?.id != null;
356
- const bHasPrimaryKey = b.data?.id != null;
357
- if (aHasPrimaryKey && !bHasPrimaryKey) return -1;
358
- if (!aHasPrimaryKey && bHasPrimaryKey) return 1;
359
- const aIsRoot = a.source === "root";
360
- const bIsRoot = b.source === "root";
361
- if (!aIsRoot && bIsRoot) return -1;
362
- if (aIsRoot && !bIsRoot) return 1;
363
- return 0;
364
- });
364
+ if (Array.isArray(result)) {
365
+ result.forEach((data) => appendCandidate(data, "root"));
366
+ return candidates;
367
+ }
368
+ appendCandidate(result, "root");
369
+ if (Array.isArray(result.versions)) {
370
+ result.versions.forEach((data) => appendCandidate(data, "versions"));
371
+ }
372
+ if (Array.isArray(result.entries)) {
373
+ result.entries.forEach((data) => appendCandidate(data, "entries"));
374
+ }
375
+ if (result.entry != null) {
376
+ appendCandidate(result.entry, "entry");
377
+ }
378
+ return candidates;
379
+ };
380
+ const isPublishedStrapiEntry = (entry) => !(entry?.publishedAt === void 0 || entry?.publishedAt === null);
381
+ const rankStrapiEntryCandidates = (candidates) => {
382
+ return [...candidates].sort((a, b) => {
383
+ const aHasPrimaryKey = a.data?.id != null;
384
+ const bHasPrimaryKey = b.data?.id != null;
385
+ if (aHasPrimaryKey && !bHasPrimaryKey) return -1;
386
+ if (!aHasPrimaryKey && bHasPrimaryKey) return 1;
387
+ const aIsRoot = a.source === "root";
388
+ const bIsRoot = b.source === "root";
389
+ if (!aIsRoot && bIsRoot) return -1;
390
+ if (aIsRoot && !bIsRoot) return 1;
391
+ return 0;
392
+ });
393
+ };
394
+ const getActionLocale = (actionParams) => {
395
+ return typeof actionParams?.locale === "string" && actionParams.locale.length > 0 ? actionParams.locale : null;
396
+ };
397
+ const resolveLocaleScopedRefetchQuery = ({
398
+ indexingQuery,
399
+ actionParams
400
+ }) => {
401
+ const actionLocale = getActionLocale(actionParams);
402
+ const baseQuery = { ...indexingQuery || {} };
403
+ if (!isWildcardLocale(baseQuery.locale) || actionLocale == null) {
404
+ return baseQuery;
405
+ }
406
+ return {
407
+ ...baseQuery,
408
+ locale: actionLocale
365
409
  };
366
- const getEntryFromResult = ({
367
- resultCandidates,
368
- documentId,
369
- entriesQuery
370
- }) => {
371
- const documentCandidates = (resultCandidates || []).filter(
372
- (candidate) => candidate?.data?.documentId === documentId
410
+ };
411
+ const resolveLocaleCodesToRemoveFromIndex = ({
412
+ actionParams,
413
+ preDeleteStrapiEntry,
414
+ localeVariants
415
+ }) => {
416
+ const actionLocale = getActionLocale(actionParams);
417
+ if (actionLocale && !isWildcardLocale(actionLocale)) {
418
+ return [actionLocale];
419
+ }
420
+ if (actionLocale == null) {
421
+ return typeof preDeleteStrapiEntry?.locale === "string" && preDeleteStrapiEntry.locale.length > 0 ? [preDeleteStrapiEntry.locale] : [];
422
+ }
423
+ return [
424
+ ...new Set(
425
+ (localeVariants || []).map((entry) => entry?.locale).filter((locale) => typeof locale === "string" && locale.length > 0)
426
+ )
427
+ ];
428
+ };
429
+ const collectLocaleCodesFromEntries = (entries) => {
430
+ return [
431
+ ...new Set(
432
+ (entries || []).map((entry) => entry?.locale).filter((locale) => typeof locale === "string" && locale.length > 0)
433
+ )
434
+ ];
435
+ };
436
+ const selectDraftEntriesForDiscardDraftResult = ({
437
+ resultCandidates,
438
+ documentId,
439
+ actionParams
440
+ }) => {
441
+ const actionLocale = getActionLocale(actionParams);
442
+ const rankedDraftEntryCandidates = rankStrapiEntryCandidates(
443
+ (resultCandidates || []).filter(
444
+ (candidate) => candidate?.data?.documentId === documentId && !isPublishedStrapiEntry(candidate.data)
445
+ )
446
+ );
447
+ const rankedLocalizedDraftEntryCandidates = rankedDraftEntryCandidates.filter(
448
+ (candidate) => typeof candidate?.data?.locale === "string" && candidate.data.locale.length > 0
449
+ );
450
+ if (rankedDraftEntryCandidates.length === 0) return [];
451
+ if (actionLocale && !isWildcardLocale(actionLocale)) {
452
+ const localeCandidate = rankedLocalizedDraftEntryCandidates.find(
453
+ (candidate) => candidate?.data?.locale === actionLocale
373
454
  );
374
- if (documentCandidates.length === 0) return null;
375
- const rankedCandidates = rankEntryCandidates(documentCandidates);
376
- if (entriesQuery?.status === "draft") {
377
- const draftCandidate = rankedCandidates.find(
378
- (candidate) => !isPublishedEntry(candidate.data)
379
- );
380
- return draftCandidate?.data || rankedCandidates[0]?.data || null;
455
+ return localeCandidate ? [localeCandidate.data] : [];
456
+ }
457
+ if (actionLocale && isWildcardLocale(actionLocale)) {
458
+ const entriesByLocale = /* @__PURE__ */ new Map();
459
+ rankedLocalizedDraftEntryCandidates.forEach((candidate) => {
460
+ const locale = candidate.data.locale;
461
+ if (!entriesByLocale.has(locale)) {
462
+ entriesByLocale.set(locale, candidate.data);
463
+ }
464
+ });
465
+ return [...entriesByLocale.values()];
466
+ }
467
+ return [
468
+ rankedLocalizedDraftEntryCandidates[0]?.data || rankedDraftEntryCandidates[0].data
469
+ ];
470
+ };
471
+ const fetchSingleEntryAfterTransaction = ({
472
+ contentTypeService: contentTypeService2,
473
+ contentType: contentType2,
474
+ documentId,
475
+ indexingQuery
476
+ }) => new Promise((resolve, reject) => {
477
+ setImmediate(async () => {
478
+ try {
479
+ const strapiEntry = await contentTypeService2.getEntry({
480
+ contentType: contentType2,
481
+ documentId,
482
+ entriesQuery: { ...indexingQuery || {} }
483
+ });
484
+ resolve(strapiEntry);
485
+ } catch (error2) {
486
+ reject(error2);
381
487
  }
382
- const publishedCandidate = rankedCandidates.find(
383
- (candidate) => isPublishedEntry(candidate.data)
384
- );
385
- return publishedCandidate?.data || null;
386
- };
387
- const getEntryOutsideTransaction = ({
388
- contentTypeService: contentTypeService2,
488
+ });
489
+ });
490
+ const fetchWildcardLocaleEntriesForIndexing = ({
491
+ contentTypeService: contentTypeService2,
492
+ contentType: contentType2,
493
+ documentId,
494
+ indexingQuery
495
+ }) => {
496
+ const baseIndexingQuery = indexingQuery || {};
497
+ return contentTypeService2.getEntries({
498
+ contentType: contentType2,
499
+ ...baseIndexingQuery,
500
+ locale: "*",
501
+ filters: {
502
+ ...baseIndexingQuery.filters || {},
503
+ documentId
504
+ }
505
+ });
506
+ };
507
+ const buildPreActionSnapshot = async ({
508
+ contentTypeService: contentTypeService2,
509
+ contentType: contentType2,
510
+ documentId,
511
+ indexingStatusFilter,
512
+ actionParams,
513
+ indexingQueryUsesWildcardLocale
514
+ }) => {
515
+ const preDeleteStrapiEntry = await contentTypeService2.getEntry({
389
516
  contentType: contentType2,
390
517
  documentId,
391
- entriesQuery
392
- }) => new Promise((resolve, reject) => {
393
- setImmediate(async () => {
394
- try {
395
- const entry = await contentTypeService2.getEntry({
396
- contentType: contentType2,
397
- documentId,
398
- entriesQuery: { ...entriesQuery }
399
- });
400
- resolve(entry);
401
- } catch (error2) {
402
- reject(error2);
403
- }
518
+ entriesQuery: { ...indexingStatusFilter || {} }
519
+ });
520
+ const shouldFetchLocaleVariants = indexingQueryUsesWildcardLocale && isWildcardLocale(actionParams?.locale);
521
+ const localeVariants = shouldFetchLocaleVariants ? await contentTypeService2.getEntries({
522
+ contentType: contentType2,
523
+ fields: ["documentId", "locale"],
524
+ locale: "*",
525
+ ...indexingStatusFilter || {},
526
+ filters: {
527
+ documentId
528
+ }
529
+ }) : [];
530
+ const localeCodesToRemove = indexingQueryUsesWildcardLocale ? resolveLocaleCodesToRemoveFromIndex({
531
+ actionParams,
532
+ preDeleteStrapiEntry,
533
+ localeVariants
534
+ }) : [];
535
+ return {
536
+ documentId,
537
+ preDeleteStrapiEntry,
538
+ localeVariants,
539
+ localeCodesToRemove
540
+ };
541
+ };
542
+ const collectPreActionSnapshots = async ({
543
+ documentIds,
544
+ contentTypeService: contentTypeService2,
545
+ contentType: contentType2,
546
+ indexingStatusFilter,
547
+ actionParams,
548
+ indexingQueryUsesWildcardLocale
549
+ }) => {
550
+ return Promise.all(
551
+ documentIds.map(
552
+ (documentId) => buildPreActionSnapshot({
553
+ contentTypeService: contentTypeService2,
554
+ contentType: contentType2,
555
+ documentId,
556
+ indexingStatusFilter,
557
+ actionParams,
558
+ indexingQueryUsesWildcardLocale
559
+ })
560
+ )
561
+ );
562
+ };
563
+ const normalizeLocaleCodes = (localeCodes) => {
564
+ return [
565
+ ...new Set(
566
+ (localeCodes || []).filter((locale) => typeof locale === "string" && locale.length > 0).map((locale) => locale.trim())
567
+ )
568
+ ];
569
+ };
570
+ const dispatchDeleteTargets = async ({
571
+ meilisearch: meilisearch2,
572
+ contentType: contentType2,
573
+ indexingQuery,
574
+ indexingQueryUsesWildcardLocale,
575
+ targets
576
+ }) => {
577
+ const validTargets = (targets || []).filter(
578
+ (target) => target && typeof target.documentId === "string" && target.documentId.length > 0
579
+ );
580
+ if (validTargets.length === 0) return;
581
+ const groupedTargets = /* @__PURE__ */ new Map();
582
+ validTargets.forEach((target) => {
583
+ const localeCodes = indexingQueryUsesWildcardLocale ? normalizeLocaleCodes(target.localeCodes) : [];
584
+ const groupKey = localeCodes.length > 0 ? [...localeCodes].sort().join("|") : "__no-locales__";
585
+ const currentGroup = groupedTargets.get(groupKey);
586
+ if (currentGroup) {
587
+ currentGroup.documentIds.push(target.documentId);
588
+ return;
589
+ }
590
+ groupedTargets.set(groupKey, {
591
+ documentIds: [target.documentId],
592
+ localeCodes
404
593
  });
405
594
  });
595
+ for (const group of groupedTargets.values()) {
596
+ await meilisearch2.deleteEntriesFromMeiliSearch({
597
+ contentType: contentType2,
598
+ documentIds: [...new Set(group.documentIds)],
599
+ entriesQuery: indexingQuery,
600
+ locales: indexingQueryUsesWildcardLocale && group.localeCodes.length > 0 ? group.localeCodes : void 0
601
+ });
602
+ }
603
+ };
604
+ async function registerDocumentMiddleware({ strapi: strapi2 }) {
605
+ if (!strapi2?.documents || typeof strapi2.documents.use !== "function") {
606
+ return;
607
+ }
406
608
  strapi2.documents.use(async (ctx, next) => {
407
609
  let result;
408
610
  try {
@@ -424,83 +626,183 @@ async function registerDocumentMiddleware({ strapi: strapi2 }) {
424
626
  "unpublish",
425
627
  "discardDraft"
426
628
  ];
427
- const entriesQuery = meilisearch2.entriesQuery({ contentType: contentType2 });
428
- const shouldDeleteByLocale = isWildcardLocale(entriesQuery.locale);
429
- const { status } = entriesQuery || {};
430
- const statusFilter = typeof status === "string" && status.length > 0 ? { status } : {};
431
- const preDeleteDocumentId = deleteActions.includes(ctx.action) && ctx?.params?.documentId ? ctx.params.documentId : null;
432
- let preDeleteEntry = null;
433
- let preDeleteLocales = [];
434
- if (preDeleteDocumentId != null) {
435
- preDeleteEntry = await contentTypeService2.getEntry({
436
- contentType: contentType2,
437
- documentId: preDeleteDocumentId,
438
- entriesQuery: { ...statusFilter }
439
- });
440
- if (shouldDeleteByLocale) {
441
- const localeVariants = await contentTypeService2.getEntries({
442
- contentType: contentType2,
443
- fields: ["documentId", "locale"],
444
- locale: "*",
445
- ...statusFilter,
446
- filters: {
447
- documentId: preDeleteDocumentId
448
- }
449
- });
450
- preDeleteLocales = [
451
- ...new Set(
452
- localeVariants.map((entry) => entry?.locale).filter(
453
- (locale) => typeof locale === "string" && locale.length > 0
454
- )
455
- )
456
- ];
457
- }
458
- }
629
+ const indexingQuery = meilisearch2.entriesQuery({ contentType: contentType2 });
630
+ const indexingQueryUsesWildcardLocale = isWildcardLocale(
631
+ indexingQuery.locale
632
+ );
633
+ const { status } = indexingQuery || {};
634
+ const indexingStatusFilter = typeof status === "string" && status.length > 0 ? { status } : {};
635
+ const isDraftIndex = status === "draft";
636
+ const isPublishedIndex = status === "published";
637
+ const shouldSkipDeleteAction = ctx.action === "unpublish" && isDraftIndex || ctx.action === "discardDraft" && isPublishedIndex;
638
+ const shouldProcessAsRefetchFirstIndexingAction = updateActions.includes(ctx.action) || ctx.action === "discardDraft" && isDraftIndex;
639
+ const shouldProcessAsDeleteAction = deleteActions.includes(ctx.action) && !shouldProcessAsRefetchFirstIndexingAction && !shouldSkipDeleteAction;
640
+ const preActionDocumentIds = resolveDocumentIdsFromActionParams(
641
+ ctx?.params
642
+ );
643
+ const shouldCollectPreActionSnapshots = shouldProcessAsDeleteAction || ctx.action === "discardDraft" && isDraftIndex;
644
+ const preActionSnapshots = shouldCollectPreActionSnapshots ? await collectPreActionSnapshots({
645
+ documentIds: preActionDocumentIds,
646
+ contentTypeService: contentTypeService2,
647
+ contentType: contentType2,
648
+ indexingStatusFilter,
649
+ actionParams: ctx?.params,
650
+ indexingQueryUsesWildcardLocale
651
+ }) : [];
652
+ const preActionSnapshotsByDocumentId = new Map(
653
+ preActionSnapshots.map((snapshot) => [snapshot.documentId, snapshot])
654
+ );
459
655
  result = await next();
460
- const contextDocumentId = typeof ctx?.params?.documentId === "string" && ctx.params.documentId.length > 0 ? ctx.params.documentId : null;
461
- const documentId = contextDocumentId ?? result?.documentId ?? preDeleteEntry?.documentId ?? preDeleteDocumentId ?? null;
462
- if (updateActions.includes(ctx.action) && documentId != null) {
463
- const resultCandidates = extractEntryCandidates(result);
464
- let entry = getEntryFromResult({
465
- resultCandidates,
466
- documentId,
467
- entriesQuery
468
- });
469
- if (!entry) {
470
- entry = await getEntryOutsideTransaction({
471
- contentTypeService: contentTypeService2,
472
- contentType: contentType2,
473
- documentId,
474
- entriesQuery
656
+ const documentIds = resolveDocumentIds({
657
+ actionParams: ctx?.params,
658
+ result,
659
+ preActionSnapshots
660
+ });
661
+ if (shouldProcessAsRefetchFirstIndexingAction && documentIds.length > 0) {
662
+ const actionResultCandidates = extractStrapiEntryCandidates(result);
663
+ const entriesToIndex = [];
664
+ const deleteTargets = [];
665
+ for (const documentId of documentIds) {
666
+ if (ctx.action === "discardDraft" && isDraftIndex) {
667
+ const preActionSnapshot = preActionSnapshotsByDocumentId.get(documentId) || null;
668
+ const actionLocale2 = getActionLocale(ctx?.params);
669
+ const shouldLoadDraftEntriesAcrossLocales = indexingQueryUsesWildcardLocale && isWildcardLocale(actionLocale2);
670
+ const draftEntriesFromActionResult = selectDraftEntriesForDiscardDraftResult({
671
+ resultCandidates: actionResultCandidates,
672
+ documentId,
673
+ actionParams: ctx?.params
674
+ });
675
+ let draftEntriesToIndex = shouldLoadDraftEntriesAcrossLocales ? await contentTypeService2.getEntries({
676
+ contentType: contentType2,
677
+ locale: "*",
678
+ ...indexingStatusFilter,
679
+ filters: {
680
+ documentId
681
+ }
682
+ }) : draftEntriesFromActionResult;
683
+ draftEntriesToIndex = (draftEntriesToIndex || []).filter(
684
+ (entry) => entry && !isPublishedStrapiEntry(entry)
685
+ );
686
+ if (draftEntriesToIndex.length === 0 && shouldLoadDraftEntriesAcrossLocales) {
687
+ draftEntriesToIndex = draftEntriesFromActionResult;
688
+ }
689
+ if (draftEntriesToIndex.length === 0 && !shouldLoadDraftEntriesAcrossLocales) {
690
+ const refetchedDraftEntry = await fetchSingleEntryAfterTransaction({
691
+ contentTypeService: contentTypeService2,
692
+ contentType: contentType2,
693
+ documentId,
694
+ indexingQuery: resolveLocaleScopedRefetchQuery({
695
+ indexingQuery,
696
+ actionParams: ctx?.params
697
+ })
698
+ });
699
+ if (refetchedDraftEntry && !isPublishedStrapiEntry(refetchedDraftEntry)) {
700
+ draftEntriesToIndex = [refetchedDraftEntry];
701
+ }
702
+ }
703
+ if (draftEntriesToIndex.length > 0) {
704
+ const normalizedDraftEntries = draftEntriesToIndex.map(
705
+ (entry) => entry.documentId === documentId ? entry : { ...entry, documentId }
706
+ );
707
+ entriesToIndex.push(...normalizedDraftEntries);
708
+ }
709
+ const preActionLocaleCodes = resolveLocaleCodesToRemoveFromIndex({
710
+ actionParams: ctx?.params,
711
+ preDeleteStrapiEntry: preActionSnapshot?.preDeleteStrapiEntry || null,
712
+ localeVariants: preActionSnapshot?.localeVariants || []
713
+ });
714
+ const remainingLocaleCodes = collectLocaleCodesFromEntries(draftEntriesToIndex);
715
+ const localeCodesToDelete = preActionLocaleCodes.filter(
716
+ (localeCode) => !remainingLocaleCodes.includes(localeCode)
717
+ );
718
+ if (localeCodesToDelete.length > 0) {
719
+ deleteTargets.push({
720
+ documentId,
721
+ localeCodes: localeCodesToDelete
722
+ });
723
+ }
724
+ continue;
725
+ }
726
+ let refetchedEntriesForDocument = [];
727
+ const actionLocale = getActionLocale(ctx?.params);
728
+ const localeScopedRefetchQuery = resolveLocaleScopedRefetchQuery({
729
+ indexingQuery,
730
+ actionParams: ctx?.params
475
731
  });
732
+ const indexingQueryStoresDrafts = indexingQuery?.status === "draft";
733
+ const shouldRefetchAllLocales = indexingQueryUsesWildcardLocale && isWildcardLocale(actionLocale) && isWildcardLocale(indexingQuery?.locale) && !indexingQueryStoresDrafts;
734
+ if (shouldRefetchAllLocales) {
735
+ refetchedEntriesForDocument = await fetchWildcardLocaleEntriesForIndexing({
736
+ contentTypeService: contentTypeService2,
737
+ contentType: contentType2,
738
+ documentId,
739
+ indexingQuery
740
+ });
741
+ } else {
742
+ const refetchedStrapiEntry = await fetchSingleEntryAfterTransaction(
743
+ {
744
+ contentTypeService: contentTypeService2,
745
+ contentType: contentType2,
746
+ documentId,
747
+ indexingQuery: localeScopedRefetchQuery
748
+ }
749
+ );
750
+ if (refetchedStrapiEntry) {
751
+ refetchedEntriesForDocument = [refetchedStrapiEntry];
752
+ }
753
+ }
754
+ if (refetchedEntriesForDocument.length > 0) {
755
+ const normalizedEntries = refetchedEntriesForDocument.map(
756
+ (entry) => entry.documentId === documentId ? entry : { ...entry, documentId }
757
+ );
758
+ entriesToIndex.push(...normalizedEntries);
759
+ } else if (ctx.action === "create" || ctx.action === "publish") {
760
+ const createPublishLocaleCodesToRemove = indexingQueryUsesWildcardLocale && typeof localeScopedRefetchQuery?.locale === "string" && localeScopedRefetchQuery.locale.length > 0 && !isWildcardLocale(localeScopedRefetchQuery.locale) ? [localeScopedRefetchQuery.locale] : [];
761
+ if (createPublishLocaleCodesToRemove.length > 0) {
762
+ deleteTargets.push({
763
+ documentId,
764
+ localeCodes: createPublishLocaleCodesToRemove
765
+ });
766
+ }
767
+ } else {
768
+ strapi2.log.info(
769
+ `Meilisearch document middleware skipped indexing ${contentType2} documentId=${documentId} for action ${ctx.action}: no indexable Strapi entry after refetch`
770
+ );
771
+ }
476
772
  }
477
- if (entry) {
478
- const normalizedEntry = entry.documentId === documentId ? entry : { ...entry, documentId };
773
+ if (entriesToIndex.length > 0) {
479
774
  await meilisearch2.updateEntriesInMeilisearch({
480
775
  contentType: contentType2,
481
- entries: [normalizedEntry]
776
+ entries: entriesToIndex
482
777
  });
483
- } else if (ctx.action === "create" || ctx.action === "publish") {
484
- await meilisearch2.deleteEntriesFromMeiliSearch({
778
+ }
779
+ if (deleteTargets.length > 0) {
780
+ await dispatchDeleteTargets({
781
+ meilisearch: meilisearch2,
485
782
  contentType: contentType2,
486
- documentIds: [documentId],
487
- entriesQuery
783
+ indexingQuery,
784
+ indexingQueryUsesWildcardLocale,
785
+ targets: deleteTargets
488
786
  });
489
- } else {
490
- strapi2.log.info(
491
- `Meilisearch document middleware skipped indexing ${contentType2} documentId=${documentId} for action ${ctx.action}: no indexable entry in result payload`
492
- );
493
787
  }
494
- } else if (deleteActions.includes(ctx.action)) {
495
- if (documentId != null) {
788
+ } else if (shouldProcessAsDeleteAction) {
789
+ if (documentIds.length > 0) {
790
+ const deleteTargets = documentIds.map((documentId) => {
791
+ const preActionSnapshot = preActionSnapshotsByDocumentId.get(documentId) || null;
792
+ return {
793
+ documentId,
794
+ localeCodes: indexingQueryUsesWildcardLocale ? preActionSnapshot?.localeCodesToRemove || [] : []
795
+ };
796
+ });
496
797
  strapi2.log.info(
497
- `Meilisearch document middleware deleting ${contentType2} documentId=${documentId}`
798
+ `Meilisearch document middleware deleting ${contentType2} documentIds=${documentIds.join(",")}`
498
799
  );
499
- await meilisearch2.deleteEntriesFromMeiliSearch({
800
+ await dispatchDeleteTargets({
801
+ meilisearch: meilisearch2,
500
802
  contentType: contentType2,
501
- documentIds: [documentId],
502
- entriesQuery,
503
- locales: shouldDeleteByLocale && preDeleteLocales.length > 0 ? preDeleteLocales : void 0
803
+ indexingQuery,
804
+ indexingQueryUsesWildcardLocale,
805
+ targets: deleteTargets
504
806
  });
505
807
  } else {
506
808
  strapi2.log.info(
@@ -1635,7 +1937,7 @@ const store = ({ strapi: strapi2 }) => {
1635
1937
  ...createStoreConnector({ strapi: strapi2 })
1636
1938
  };
1637
1939
  };
1638
- const version = "0.16.2";
1940
+ const version = "0.16.4";
1639
1941
  const Meilisearch = (config2) => {
1640
1942
  return new MeiliSearch({
1641
1943
  ...config2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-meilisearch",
3
- "version": "0.16.2",
3
+ "version": "0.16.4",
4
4
  "description": "Synchronise and search in your Strapi content-types with Meilisearch",
5
5
  "scripts": {
6
6
  "build": "strapi-plugin build",