@payloadcms/plugin-search 3.83.0-internal.06ac84e → 3.83.0-internal.86b7bfb

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.
@@ -1 +1 @@
1
- {"version":3,"file":"generateReindexHandler.d.ts","sourceRoot":"","sources":["../../src/utilities/generateReindexHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAS,MAAM,SAAS,CAAA;AAWpD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AAS9D,eAAO,MAAM,sBAAsB,iBAClB,2BAA2B,KAAG,cA+M5C,CAAA"}
1
+ {"version":3,"file":"generateReindexHandler.d.ts","sourceRoot":"","sources":["../../src/utilities/generateReindexHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAS,MAAM,SAAS,CAAA;AAWpD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AAS9D,eAAO,MAAM,sBAAsB,iBAClB,2BAA2B,KAAG,cAwN5C,CAAA"}
@@ -88,9 +88,6 @@ export const generateReindexHandler = (pluginConfig)=>async (req)=>{
88
88
  equals: 'published'
89
89
  }
90
90
  };
91
- let aggregateDocsWithDrafts = 0;
92
- let aggregateErrors = 0;
93
- let aggregateDocs = 0;
94
91
  async function countDocuments(collection, drafts) {
95
92
  const { totalDocs } = await payload.count({
96
93
  collection,
@@ -120,8 +117,7 @@ export const generateReindexHandler = (pluginConfig)=>async (req)=>{
120
117
  const totalDocsWithDrafts = await countDocuments(collection, true);
121
118
  const totalDocs = syncDrafts || !draftsEnabled ? totalDocsWithDrafts : await countDocuments(collection, !draftsEnabled);
122
119
  const totalBatches = Math.ceil(totalDocs / batchSize);
123
- aggregateDocsWithDrafts += totalDocsWithDrafts;
124
- aggregateDocs += totalDocs;
120
+ let localErrors = 0;
125
121
  // Loop through batches, then documents, then locales per document
126
122
  for(let i = 0; i < totalBatches; i++){
127
123
  const defaultLocale = req.payload.config.localization ? req.payload.config.localization.defaultLocale : req.locale;
@@ -171,7 +167,7 @@ export const generateReindexHandler = (pluginConfig)=>async (req)=>{
171
167
  data: doc,
172
168
  doc,
173
169
  locale: localeToSync,
174
- onSyncError: ()=>operation === 'create' && aggregateErrors++,
170
+ onSyncError: ()=>operation === 'create' && localErrors++,
175
171
  operation,
176
172
  pluginConfig,
177
173
  req
@@ -179,13 +175,22 @@ export const generateReindexHandler = (pluginConfig)=>async (req)=>{
179
175
  }
180
176
  }
181
177
  }
178
+ return {
179
+ docs: totalDocs,
180
+ docsWithDrafts: totalDocsWithDrafts,
181
+ errors: localErrors
182
+ };
182
183
  }
183
184
  const shouldCommit = await initTransaction(req);
185
+ // Collections are processed sequentially to avoid race conditions within the shared transaction.
186
+ // Concurrent writes to the search collection interleave on the same DB connection and can cause
187
+ // locale data to be missing non-deterministically.
188
+ const results = [];
184
189
  try {
185
- const promises = collections.map(async (collection)=>{
190
+ for (const collection of collections){
186
191
  try {
187
192
  await deleteIndexes(collection);
188
- await reindexCollection(collection);
193
+ results.push(await reindexCollection(collection));
189
194
  } catch (err) {
190
195
  const message = t('error:unableToReindexCollection', {
191
196
  collection
@@ -194,20 +199,27 @@ export const generateReindexHandler = (pluginConfig)=>async (req)=>{
194
199
  err,
195
200
  msg: message
196
201
  });
202
+ results.push({
203
+ docs: 0,
204
+ docsWithDrafts: 0,
205
+ errors: 0
206
+ });
197
207
  }
198
- });
199
- await Promise.all(promises);
208
+ }
200
209
  } catch (err) {
201
210
  if (shouldCommit) {
202
211
  await killTransaction(req);
203
212
  }
204
213
  return Response.json({
205
- message: err.message
214
+ message: err instanceof Error ? err.message : String(err)
206
215
  }, {
207
216
  headers,
208
217
  status: 500
209
218
  });
210
219
  }
220
+ const aggregateDocsWithDrafts = results.reduce((sum, r)=>sum + r.docsWithDrafts, 0);
221
+ const aggregateDocs = results.reduce((sum, r)=>sum + r.docs, 0);
222
+ const aggregateErrors = results.reduce((sum, r)=>sum + r.errors, 0);
211
223
  const message = t('general:successfullyReindexed', {
212
224
  collections: collections.join(', '),
213
225
  count: aggregateDocs - aggregateErrors,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/generateReindexHandler.ts"],"sourcesContent":["import type { PayloadHandler, Where } from 'payload'\n\nimport {\n addLocalesToRequestFromData,\n commitTransaction,\n getAccessResults,\n headersWithCors,\n initTransaction,\n killTransaction,\n} from 'payload'\n\nimport type { SanitizedSearchPluginConfig } from '../types.js'\n\nimport { syncDocAsSearchIndex } from './syncDocAsSearchIndex.js'\n\ntype ValidationResult = {\n isValid: boolean\n message?: string\n}\n\nexport const generateReindexHandler =\n (pluginConfig: SanitizedSearchPluginConfig): PayloadHandler =>\n async (req) => {\n addLocalesToRequestFromData(req)\n if (!req.json) {\n return new Response('Req.json is undefined', { status: 400 })\n }\n const { collections = [] } = (await req.json()) as { collections: string[] }\n const t = req.t\n\n const searchSlug = pluginConfig?.searchOverrides?.slug || 'search'\n const searchCollections = pluginConfig?.collections || []\n\n async function validatePermissions(): Promise<ValidationResult> {\n const accessResults = await getAccessResults({ req })\n const searchAccessResults = accessResults.collections?.[searchSlug]\n if (!searchAccessResults) {\n return { isValid: false, message: t('error:notAllowedToPerformAction') }\n }\n\n const permissions = [searchAccessResults.delete, searchAccessResults.update]\n // plugin doesn't allow create by default:\n // if user provided, then add it to check\n if (pluginConfig.searchOverrides?.access?.create) {\n permissions.push(searchAccessResults.create)\n }\n // plugin allows reads by anyone by default:\n // so if user provided, then add to check\n if (pluginConfig.searchOverrides?.access?.read) {\n permissions.push(searchAccessResults.read)\n }\n return permissions.every(Boolean)\n ? { isValid: true }\n : { isValid: false, message: t('error:notAllowedToPerformAction') }\n }\n\n function validateCollections(): ValidationResult {\n const collectionsAreValid = collections.every((col) => searchCollections.includes(col))\n return collections.length && collectionsAreValid\n ? { isValid: true }\n : { isValid: false, message: t('error:invalidRequestArgs', { args: `'collections'` }) }\n }\n\n const headers = headersWithCors({\n headers: new Headers(),\n req,\n })\n\n const { isValid: hasPermissions, message: permissionError } = await validatePermissions()\n if (!hasPermissions) {\n return Response.json({ message: permissionError }, { headers, status: 401 })\n }\n\n const { isValid: validCollections, message: collectionError } = validateCollections()\n if (!validCollections) {\n return Response.json({ message: collectionError }, { headers, status: 400 })\n }\n\n const payload = req.payload\n const { reindexBatchSize: batchSize, syncDrafts } = pluginConfig\n\n const defaultLocalApiProps = {\n overrideAccess: false,\n req,\n user: req.user,\n }\n const whereStatusPublished: Where = {\n _status: {\n equals: 'published',\n },\n }\n let aggregateDocsWithDrafts = 0\n let aggregateErrors = 0\n let aggregateDocs = 0\n\n async function countDocuments(collection: string, drafts?: boolean): Promise<number> {\n const { totalDocs } = await payload.count({\n collection,\n ...defaultLocalApiProps,\n req: undefined,\n where: drafts ? undefined : whereStatusPublished,\n })\n return totalDocs\n }\n\n async function deleteIndexes(collection: string) {\n await payload.delete({\n collection: searchSlug,\n depth: 0,\n select: { id: true },\n where: { 'doc.relationTo': { equals: collection } },\n ...defaultLocalApiProps,\n })\n }\n\n async function reindexCollection(collection: string) {\n const draftsEnabled = Boolean(payload.collections[collection]?.config.versions?.drafts)\n\n const totalDocsWithDrafts = await countDocuments(collection, true)\n const totalDocs =\n syncDrafts || !draftsEnabled\n ? totalDocsWithDrafts\n : await countDocuments(collection, !draftsEnabled)\n const totalBatches = Math.ceil(totalDocs / batchSize)\n\n aggregateDocsWithDrafts += totalDocsWithDrafts\n aggregateDocs += totalDocs\n\n // Loop through batches, then documents, then locales per document\n for (let i = 0; i < totalBatches; i++) {\n const defaultLocale = req.payload.config.localization\n ? req.payload.config.localization.defaultLocale\n : req.locale\n\n const { docs } = await payload.find({\n collection,\n depth: 0,\n limit: batchSize,\n locale: defaultLocale,\n page: i + 1,\n where: syncDrafts || !draftsEnabled ? undefined : whereStatusPublished,\n ...defaultLocalApiProps,\n })\n\n for (const doc of docs) {\n // Get all configured locales\n // If no localization, use [undefined] to sync once without a locale\n const allLocales = req.payload.config.localization\n ? req.payload.config.localization.localeCodes\n : [undefined]\n\n // Loop through all locales and check each one\n let firstAllowedLocale = true\n for (const localeToSync of allLocales) {\n // Check if we should skip this locale for this document\n let shouldSkip = false\n if (typeof pluginConfig.skipSync === 'function') {\n try {\n shouldSkip = await pluginConfig.skipSync({\n collectionSlug: collection,\n doc,\n locale: localeToSync,\n req,\n })\n } catch (err) {\n req.payload.logger.error({\n err,\n msg: 'Search plugin: Error executing skipSync. Proceeding with sync.',\n })\n }\n }\n\n if (shouldSkip) {\n continue // Skip this locale\n }\n\n // Sync this locale (create first index, then update with other locales accordingly)\n const operation = firstAllowedLocale ? 'create' : 'update'\n firstAllowedLocale = false\n\n await syncDocAsSearchIndex({\n collection,\n data: doc,\n doc,\n locale: localeToSync,\n onSyncError: () => operation === 'create' && aggregateErrors++,\n operation,\n pluginConfig,\n req,\n })\n }\n }\n }\n }\n\n const shouldCommit = await initTransaction(req)\n\n try {\n const promises = collections.map(async (collection) => {\n try {\n await deleteIndexes(collection)\n await reindexCollection(collection)\n } catch (err) {\n const message = t('error:unableToReindexCollection', { collection })\n payload.logger.error({ err, msg: message })\n }\n })\n\n await Promise.all(promises)\n } catch (err: any) {\n if (shouldCommit) {\n await killTransaction(req)\n }\n return Response.json({ message: err.message }, { headers, status: 500 })\n }\n\n const message = t('general:successfullyReindexed', {\n collections: collections.join(', '),\n count: aggregateDocs - aggregateErrors,\n skips: syncDrafts ? 0 : aggregateDocsWithDrafts - aggregateDocs,\n total: aggregateDocsWithDrafts,\n })\n\n if (shouldCommit) {\n await commitTransaction(req)\n }\n\n return Response.json({ message }, { headers, status: 200 })\n }\n"],"names":["addLocalesToRequestFromData","commitTransaction","getAccessResults","headersWithCors","initTransaction","killTransaction","syncDocAsSearchIndex","generateReindexHandler","pluginConfig","req","json","Response","status","collections","t","searchSlug","searchOverrides","slug","searchCollections","validatePermissions","accessResults","searchAccessResults","isValid","message","permissions","delete","update","access","create","push","read","every","Boolean","validateCollections","collectionsAreValid","col","includes","length","args","headers","Headers","hasPermissions","permissionError","validCollections","collectionError","payload","reindexBatchSize","batchSize","syncDrafts","defaultLocalApiProps","overrideAccess","user","whereStatusPublished","_status","equals","aggregateDocsWithDrafts","aggregateErrors","aggregateDocs","countDocuments","collection","drafts","totalDocs","count","undefined","where","deleteIndexes","depth","select","id","reindexCollection","draftsEnabled","config","versions","totalDocsWithDrafts","totalBatches","Math","ceil","i","defaultLocale","localization","locale","docs","find","limit","page","doc","allLocales","localeCodes","firstAllowedLocale","localeToSync","shouldSkip","skipSync","collectionSlug","err","logger","error","msg","operation","data","onSyncError","shouldCommit","promises","map","Promise","all","join","skips","total"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/generateReindexHandler.ts"],"sourcesContent":["import type { PayloadHandler, Where } from 'payload'\n\nimport {\n addLocalesToRequestFromData,\n commitTransaction,\n getAccessResults,\n headersWithCors,\n initTransaction,\n killTransaction,\n} from 'payload'\n\nimport type { SanitizedSearchPluginConfig } from '../types.js'\n\nimport { syncDocAsSearchIndex } from './syncDocAsSearchIndex.js'\n\ntype ValidationResult = {\n isValid: boolean\n message?: string\n}\n\nexport const generateReindexHandler =\n (pluginConfig: SanitizedSearchPluginConfig): PayloadHandler =>\n async (req) => {\n addLocalesToRequestFromData(req)\n if (!req.json) {\n return new Response('Req.json is undefined', { status: 400 })\n }\n const { collections = [] } = (await req.json()) as { collections: string[] }\n const t = req.t\n\n const searchSlug = pluginConfig?.searchOverrides?.slug || 'search'\n const searchCollections = pluginConfig?.collections || []\n\n async function validatePermissions(): Promise<ValidationResult> {\n const accessResults = await getAccessResults({ req })\n const searchAccessResults = accessResults.collections?.[searchSlug]\n if (!searchAccessResults) {\n return { isValid: false, message: t('error:notAllowedToPerformAction') }\n }\n\n const permissions = [searchAccessResults.delete, searchAccessResults.update]\n // plugin doesn't allow create by default:\n // if user provided, then add it to check\n if (pluginConfig.searchOverrides?.access?.create) {\n permissions.push(searchAccessResults.create)\n }\n // plugin allows reads by anyone by default:\n // so if user provided, then add to check\n if (pluginConfig.searchOverrides?.access?.read) {\n permissions.push(searchAccessResults.read)\n }\n return permissions.every(Boolean)\n ? { isValid: true }\n : { isValid: false, message: t('error:notAllowedToPerformAction') }\n }\n\n function validateCollections(): ValidationResult {\n const collectionsAreValid = collections.every((col) => searchCollections.includes(col))\n return collections.length && collectionsAreValid\n ? { isValid: true }\n : { isValid: false, message: t('error:invalidRequestArgs', { args: `'collections'` }) }\n }\n\n const headers = headersWithCors({\n headers: new Headers(),\n req,\n })\n\n const { isValid: hasPermissions, message: permissionError } = await validatePermissions()\n if (!hasPermissions) {\n return Response.json({ message: permissionError }, { headers, status: 401 })\n }\n\n const { isValid: validCollections, message: collectionError } = validateCollections()\n if (!validCollections) {\n return Response.json({ message: collectionError }, { headers, status: 400 })\n }\n\n const payload = req.payload\n const { reindexBatchSize: batchSize, syncDrafts } = pluginConfig\n\n const defaultLocalApiProps = {\n overrideAccess: false,\n req,\n user: req.user,\n }\n const whereStatusPublished: Where = {\n _status: {\n equals: 'published',\n },\n }\n async function countDocuments(collection: string, drafts?: boolean): Promise<number> {\n const { totalDocs } = await payload.count({\n collection,\n ...defaultLocalApiProps,\n req: undefined,\n where: drafts ? undefined : whereStatusPublished,\n })\n return totalDocs\n }\n\n async function deleteIndexes(collection: string) {\n await payload.delete({\n collection: searchSlug,\n depth: 0,\n select: { id: true },\n where: { 'doc.relationTo': { equals: collection } },\n ...defaultLocalApiProps,\n })\n }\n\n async function reindexCollection(\n collection: string,\n ): Promise<{ docs: number; docsWithDrafts: number; errors: number }> {\n const draftsEnabled = Boolean(payload.collections[collection]?.config.versions?.drafts)\n\n const totalDocsWithDrafts = await countDocuments(collection, true)\n const totalDocs =\n syncDrafts || !draftsEnabled\n ? totalDocsWithDrafts\n : await countDocuments(collection, !draftsEnabled)\n const totalBatches = Math.ceil(totalDocs / batchSize)\n\n let localErrors = 0\n\n // Loop through batches, then documents, then locales per document\n for (let i = 0; i < totalBatches; i++) {\n const defaultLocale = req.payload.config.localization\n ? req.payload.config.localization.defaultLocale\n : req.locale\n\n const { docs } = await payload.find({\n collection,\n depth: 0,\n limit: batchSize,\n locale: defaultLocale,\n page: i + 1,\n where: syncDrafts || !draftsEnabled ? undefined : whereStatusPublished,\n ...defaultLocalApiProps,\n })\n\n for (const doc of docs) {\n // Get all configured locales\n // If no localization, use [undefined] to sync once without a locale\n const allLocales = req.payload.config.localization\n ? req.payload.config.localization.localeCodes\n : [undefined]\n\n // Loop through all locales and check each one\n let firstAllowedLocale = true\n for (const localeToSync of allLocales) {\n // Check if we should skip this locale for this document\n let shouldSkip = false\n if (typeof pluginConfig.skipSync === 'function') {\n try {\n shouldSkip = await pluginConfig.skipSync({\n collectionSlug: collection,\n doc,\n locale: localeToSync,\n req,\n })\n } catch (err) {\n req.payload.logger.error({\n err,\n msg: 'Search plugin: Error executing skipSync. Proceeding with sync.',\n })\n }\n }\n\n if (shouldSkip) {\n continue // Skip this locale\n }\n\n // Sync this locale (create first index, then update with other locales accordingly)\n const operation = firstAllowedLocale ? 'create' : 'update'\n firstAllowedLocale = false\n\n await syncDocAsSearchIndex({\n collection,\n data: doc,\n doc,\n locale: localeToSync,\n onSyncError: () => operation === 'create' && localErrors++,\n operation,\n pluginConfig,\n req,\n })\n }\n }\n }\n\n return { docs: totalDocs, docsWithDrafts: totalDocsWithDrafts, errors: localErrors }\n }\n\n const shouldCommit = await initTransaction(req)\n\n // Collections are processed sequentially to avoid race conditions within the shared transaction.\n // Concurrent writes to the search collection interleave on the same DB connection and can cause\n // locale data to be missing non-deterministically.\n const results: Array<{ docs: number; docsWithDrafts: number; errors: number }> = []\n try {\n for (const collection of collections) {\n try {\n await deleteIndexes(collection)\n results.push(await reindexCollection(collection))\n } catch (err) {\n const message = t('error:unableToReindexCollection', { collection })\n payload.logger.error({ err, msg: message })\n results.push({ docs: 0, docsWithDrafts: 0, errors: 0 })\n }\n }\n } catch (err: unknown) {\n if (shouldCommit) {\n await killTransaction(req)\n }\n return Response.json(\n { message: err instanceof Error ? err.message : String(err) },\n { headers, status: 500 },\n )\n }\n\n const aggregateDocsWithDrafts = results.reduce((sum, r) => sum + r.docsWithDrafts, 0)\n const aggregateDocs = results.reduce((sum, r) => sum + r.docs, 0)\n const aggregateErrors = results.reduce((sum, r) => sum + r.errors, 0)\n\n const message = t('general:successfullyReindexed', {\n collections: collections.join(', '),\n count: aggregateDocs - aggregateErrors,\n skips: syncDrafts ? 0 : aggregateDocsWithDrafts - aggregateDocs,\n total: aggregateDocsWithDrafts,\n })\n\n if (shouldCommit) {\n await commitTransaction(req)\n }\n\n return Response.json({ message }, { headers, status: 200 })\n }\n"],"names":["addLocalesToRequestFromData","commitTransaction","getAccessResults","headersWithCors","initTransaction","killTransaction","syncDocAsSearchIndex","generateReindexHandler","pluginConfig","req","json","Response","status","collections","t","searchSlug","searchOverrides","slug","searchCollections","validatePermissions","accessResults","searchAccessResults","isValid","message","permissions","delete","update","access","create","push","read","every","Boolean","validateCollections","collectionsAreValid","col","includes","length","args","headers","Headers","hasPermissions","permissionError","validCollections","collectionError","payload","reindexBatchSize","batchSize","syncDrafts","defaultLocalApiProps","overrideAccess","user","whereStatusPublished","_status","equals","countDocuments","collection","drafts","totalDocs","count","undefined","where","deleteIndexes","depth","select","id","reindexCollection","draftsEnabled","config","versions","totalDocsWithDrafts","totalBatches","Math","ceil","localErrors","i","defaultLocale","localization","locale","docs","find","limit","page","doc","allLocales","localeCodes","firstAllowedLocale","localeToSync","shouldSkip","skipSync","collectionSlug","err","logger","error","msg","operation","data","onSyncError","docsWithDrafts","errors","shouldCommit","results","Error","String","aggregateDocsWithDrafts","reduce","sum","r","aggregateDocs","aggregateErrors","join","skips","total"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/plugin-search",
3
- "version": "3.83.0-internal.06ac84e",
3
+ "version": "3.83.0-internal.86b7bfb",
4
4
  "description": "Search plugin for Payload",
5
5
  "keywords": [
6
6
  "payload",
@@ -50,19 +50,19 @@
50
50
  "dist"
51
51
  ],
52
52
  "dependencies": {
53
- "@payloadcms/next": "3.83.0-internal.06ac84e",
54
- "@payloadcms/ui": "3.83.0-internal.06ac84e"
53
+ "@payloadcms/ui": "3.83.0-internal.86b7bfb",
54
+ "@payloadcms/next": "3.83.0-internal.86b7bfb"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/react": "19.2.9",
58
58
  "@types/react-dom": "19.2.3",
59
59
  "@payloadcms/eslint-config": "3.28.0",
60
- "payload": "3.83.0-internal.06ac84e"
60
+ "payload": "3.83.0-internal.86b7bfb"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "react": "^19.0.1 || ^19.1.2 || ^19.2.1",
64
64
  "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1",
65
- "payload": "3.83.0-internal.06ac84e"
65
+ "payload": "3.83.0-internal.86b7bfb"
66
66
  },
67
67
  "publishConfig": {
68
68
  "registry": "https://registry.npmjs.org/"