@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,
|
|
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
|
-
|
|
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' &&
|
|
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
|
|
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.
|
|
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/
|
|
54
|
-
"@payloadcms/
|
|
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.
|
|
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.
|
|
65
|
+
"payload": "3.83.0-internal.86b7bfb"
|
|
66
66
|
},
|
|
67
67
|
"publishConfig": {
|
|
68
68
|
"registry": "https://registry.npmjs.org/"
|