@dalencatt/strapi-plugin-fuzzy-search-private 0.0.0-development

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.
@@ -0,0 +1,677 @@
1
+ import * as yup from "yup";
2
+ import { object, string } from "yup";
3
+ import { errors } from "@strapi/utils";
4
+ import fuzzysort from "fuzzysort";
5
+ import { transliterate } from "transliteration";
6
+ const bootstrap = () => {
7
+ };
8
+ const pluginConfigSchema = yup.object({
9
+ contentTypes: yup.array().of(
10
+ yup.object({
11
+ uid: yup.string().required(),
12
+ modelName: yup.string().required(),
13
+ transliterate: yup.boolean(),
14
+ fuzzysortOptions: yup.object({
15
+ threshold: yup.number(),
16
+ limit: yup.number(),
17
+ keys: yup.array().of(
18
+ yup.object({
19
+ name: yup.string().required(),
20
+ weight: yup.number()
21
+ })
22
+ )
23
+ }).required()
24
+ })
25
+ )
26
+ }).noUnknown();
27
+ const config = {
28
+ default() {
29
+ return {
30
+ contentTypes: {}
31
+ };
32
+ },
33
+ async validator(config2) {
34
+ await pluginConfigSchema.validate(config2);
35
+ }
36
+ };
37
+ const paginationSchema = object({
38
+ pageSize: string().matches(/^\d+$/, "pageSize must be an integer"),
39
+ page: string().matches(/^\d+$/, "page must be an integer"),
40
+ withCount: string().oneOf(
41
+ ["true", "false"],
42
+ "withCount must either be 'true' or 'false'"
43
+ )
44
+ });
45
+ string().required();
46
+ const querySchema = object({
47
+ query: string().required(),
48
+ locale: string(),
49
+ filters: object({
50
+ contentTypes: string()
51
+ })
52
+ });
53
+ const { ValidationError } = errors;
54
+ const validateFilteredContentTypes = (configModels, filterModel) => {
55
+ if (!configModels.has(filterModel))
56
+ throw new Error(
57
+ `'${filterModel}' was found in contentTypes filter query, however this model is not configured in the fuzzy-search config`
58
+ );
59
+ };
60
+ const validatePaginationQueryParams = async (configModels, pagination) => {
61
+ const paginatedEntries = Object.entries(pagination);
62
+ for (const [pluralName, paginationValues] of paginatedEntries) {
63
+ if (!configModels.has(pluralName)) {
64
+ throw new Error(
65
+ `Pagination queries for model '${pluralName}' were found, however this model is not configured in the fuzzy-search config`
66
+ );
67
+ }
68
+ await paginationSchema.validate(paginationValues);
69
+ }
70
+ };
71
+ const validateNestedQueryParams = (configModels, nestedParams) => {
72
+ const filterKeys = Object.keys(nestedParams);
73
+ filterKeys.forEach((key) => {
74
+ if (key !== "contentTypes" && !configModels.has(key)) {
75
+ throw new Error(
76
+ `Query params for model '${key}' were found, however this model is not configured in the fuzzy-search config`
77
+ );
78
+ }
79
+ });
80
+ };
81
+ const validateQueryParams = async (query, contentTypes, pagination, populate, filteredContentTypes) => {
82
+ const configModels = new Set(
83
+ contentTypes.map((contentType) => contentType.info.pluralName)
84
+ );
85
+ await querySchema.validate(query);
86
+ if (pagination) await validatePaginationQueryParams(configModels, pagination);
87
+ if (query.filters) validateNestedQueryParams(configModels, query.filters);
88
+ if (populate) validateNestedQueryParams(configModels, populate);
89
+ if (filteredContentTypes)
90
+ filteredContentTypes.forEach(
91
+ (model) => validateFilteredContentTypes(configModels, model)
92
+ );
93
+ };
94
+ const validateQuery = async (contentType, locale) => {
95
+ if (contentType.kind !== "collectionType")
96
+ throw new ValidationError(
97
+ `Content type: '${contentType.modelName}' is not a collectionType`
98
+ );
99
+ contentType.fuzzysortOptions.keys.forEach((key) => {
100
+ const attributeKeys = Object.keys(contentType.attributes);
101
+ if (!attributeKeys.includes(key.name))
102
+ throw new ValidationError(
103
+ `Key: '${key.name}' is not a valid field for model: '${contentType.modelName}`
104
+ );
105
+ });
106
+ if (!locale) return;
107
+ const isLocalizedContentType = await strapi.plugins.i18n.services["content-types"].isLocalizedContentType(
108
+ contentType
109
+ );
110
+ if (!isLocalizedContentType) {
111
+ throw new ValidationError(
112
+ `A query for the locale: '${locale}' was found, however model: '${contentType.modelName}' is not a localized content type. Enable localization for all content types if you want to query for localized entries via the locale parameter.`
113
+ );
114
+ }
115
+ };
116
+ const weightScores = (a, keys) => {
117
+ const weightedScores = keys.map((key, index2) => {
118
+ const weight = key.weight || 0;
119
+ return a[index2] ? +a[index2].score + weight : -9999;
120
+ });
121
+ return Math.max(...weightedScores);
122
+ };
123
+ const transformEntryKeysToString = (entries, keys) => entries.map(
124
+ (entry) => transformEntry(entry, keys, (value) => value?.toString())
125
+ );
126
+ const limitCharacters = (entries, characterLimit, keys) => entries.map(
127
+ (entry) => transformEntry(
128
+ entry,
129
+ keys,
130
+ (value) => value?.toString().slice(0, characterLimit)
131
+ )
132
+ );
133
+ const transformEntry = (entry, keys, transformFn) => {
134
+ const transformedEntry = { ...entry };
135
+ const entryKeys = Object.keys(transformedEntry);
136
+ entryKeys.forEach((key) => {
137
+ if (!keys.includes(key)) return;
138
+ transformedEntry[key] = transformFn(transformedEntry[key]);
139
+ });
140
+ return transformedEntry;
141
+ };
142
+ const buildResult = ({
143
+ entries,
144
+ fuzzysortOptions,
145
+ keys,
146
+ query
147
+ }) => {
148
+ const transformedEntries = fuzzysortOptions.characterLimit ? limitCharacters(entries, fuzzysortOptions.characterLimit, keys) : transformEntryKeysToString(entries, keys);
149
+ return fuzzysort.go(query, transformedEntries, {
150
+ threshold: fuzzysortOptions.threshold,
151
+ limit: fuzzysortOptions.limit,
152
+ keys,
153
+ scoreFn: (a) => weightScores(a, fuzzysortOptions.keys)
154
+ });
155
+ };
156
+ const transliterateEntries = (entries) => entries.map((entry) => {
157
+ const entryKeys = Object.keys(entry);
158
+ entry.transliterations = {};
159
+ entryKeys.forEach((key) => {
160
+ if (!entry[key]) return;
161
+ entry.transliterations[key] = transliterate(entry[key]);
162
+ });
163
+ return entry;
164
+ });
165
+ const buildTransliteratedResult = ({
166
+ entries,
167
+ fuzzysortOptions,
168
+ keys,
169
+ query,
170
+ result
171
+ }) => {
172
+ const { keys: fuzzysortKeys, threshold, limit } = fuzzysortOptions;
173
+ const transliteratedEntries = transliterateEntries(entries);
174
+ const transliterationKeys = keys.map((key) => `transliterations.${key}`);
175
+ const transliteratedResult = fuzzysort.go(
176
+ query,
177
+ transliteratedEntries,
178
+ {
179
+ threshold,
180
+ limit,
181
+ keys: transliterationKeys,
182
+ scoreFn: (a) => weightScores(a, fuzzysortKeys)
183
+ }
184
+ );
185
+ entries.forEach((entry) => delete entry.transliterations);
186
+ if (!result.total) return transliteratedResult;
187
+ const newResults = [...result];
188
+ transliteratedResult.forEach((res) => {
189
+ const origIndex = newResults.findIndex(
190
+ (origRes) => origRes.obj.id === res.obj.id && origRes.score <= res.score
191
+ );
192
+ if (origIndex >= 0) newResults[origIndex] = res;
193
+ });
194
+ newResults.sort((a, b) => b.score - a.score);
195
+ return newResults;
196
+ };
197
+ async function getResult({
198
+ contentType,
199
+ query,
200
+ filters,
201
+ populate,
202
+ locale,
203
+ status
204
+ }) {
205
+ const buildFilteredEntries = async () => {
206
+ await validateQuery(contentType, locale);
207
+ return await strapi.documents(contentType.uid).findMany({
208
+ ...filters && { filters },
209
+ ...locale && { locale },
210
+ ...populate && { populate },
211
+ status: status ?? "published"
212
+ });
213
+ };
214
+ const filteredEntries = await buildFilteredEntries();
215
+ const keys = contentType.fuzzysortOptions.keys.map((key) => key.name);
216
+ let result = buildResult({
217
+ entries: filteredEntries,
218
+ fuzzysortOptions: contentType.fuzzysortOptions,
219
+ keys,
220
+ query
221
+ });
222
+ if (contentType.transliterate) {
223
+ result = buildTransliteratedResult({
224
+ entries: filteredEntries,
225
+ fuzzysortOptions: contentType.fuzzysortOptions,
226
+ keys,
227
+ query,
228
+ result
229
+ });
230
+ }
231
+ return {
232
+ fuzzysortResults: result,
233
+ schema: contentType
234
+ };
235
+ }
236
+ const parsePaginationArgs = ({
237
+ page: pageQuery = "1",
238
+ pageSize: pageSizeQuery = "25",
239
+ withCount: withCountQuery = "true"
240
+ }) => {
241
+ const page = parseInt(pageQuery, 10);
242
+ const pageSize = parseInt(pageSizeQuery, 10);
243
+ const withCount = withCountQuery === "true";
244
+ return { page, pageSize, withCount };
245
+ };
246
+ const paginateRestResults = async (pagination, pluralNames, resultsResponse) => {
247
+ const currentResult = { ...resultsResponse };
248
+ const paginatedResult = {};
249
+ const buildPaginatedResults = (pluralName) => {
250
+ const { page, pageSize, withCount } = parsePaginationArgs(
251
+ pagination[pluralName]
252
+ );
253
+ paginatedResult[pluralName] = {
254
+ data: [],
255
+ meta: { pagination: { page: 1, pageSize: 25 } }
256
+ };
257
+ const startIndex = pageSize * (page - 1);
258
+ const endIndex = startIndex + pageSize;
259
+ paginatedResult[pluralName].data = currentResult[pluralName].slice(
260
+ startIndex,
261
+ endIndex
262
+ );
263
+ const meta = {
264
+ pagination: {
265
+ page,
266
+ pageSize
267
+ }
268
+ };
269
+ if (withCount) {
270
+ const total = resultsResponse[pluralName].length;
271
+ meta.pagination.total = total;
272
+ meta.pagination.pageCount = Math.ceil(total / pageSize);
273
+ }
274
+ paginatedResult[pluralName].meta = meta;
275
+ };
276
+ pluralNames.forEach((pluralName) => {
277
+ if (!pagination[pluralName]) return;
278
+ buildPaginatedResults(pluralName);
279
+ });
280
+ return { ...resultsResponse, ...paginatedResult };
281
+ };
282
+ const paginateGraphQlResults = (results, { limit, start }) => {
283
+ const resultsCopy = [...results];
284
+ const data = resultsCopy.slice(start, start + limit);
285
+ const meta = {
286
+ start,
287
+ limit
288
+ };
289
+ return { data, meta };
290
+ };
291
+ const { sanitize } = strapi.contentAPI;
292
+ const sanitizeOutput = (data, schema, auth) => sanitize.output(data, schema, { auth });
293
+ const buildGraphqlResponse = async (searchResult, schema, auth, pagination) => {
294
+ const { service: getService } = strapi.plugin("graphql");
295
+ const { returnTypes } = getService("format");
296
+ const { toEntityResponseCollection } = returnTypes;
297
+ const results = await Promise.all(
298
+ searchResult.map(
299
+ async (fuzzyRes) => await sanitizeOutput(fuzzyRes.obj, schema, auth)
300
+ )
301
+ );
302
+ const { data: nodes, meta } = paginateGraphQlResults(results, pagination);
303
+ return toEntityResponseCollection(nodes, {
304
+ args: meta,
305
+ resourceUID: schema.uid
306
+ });
307
+ };
308
+ const buildRestResponse = async (searchResults, auth, pagination, queriedContentTypes) => {
309
+ const resultsResponse = {};
310
+ for (const res of searchResults) {
311
+ const sanitizeEntry = async (fuzzyRes) => {
312
+ return await sanitizeOutput(fuzzyRes.obj, res.schema, auth);
313
+ };
314
+ const buildSanitizedEntries = async () => res.fuzzysortResults.map(
315
+ async (fuzzyRes) => await sanitizeEntry(fuzzyRes)
316
+ );
317
+ resultsResponse[res.schema.info.pluralName] = await Promise.all(
318
+ await buildSanitizedEntries()
319
+ );
320
+ }
321
+ if (!pagination) return resultsResponse;
322
+ const modelNames = queriedContentTypes || Object.keys(pagination);
323
+ return await paginateRestResults(pagination, modelNames, resultsResponse);
324
+ };
325
+ const name = "strapi-plugin-fuzzy-search";
326
+ const version = "0.0.0-development";
327
+ const description = "Register a weighted fuzzy search endpoint for Strapi Headless CMS you can add your content types to in no time.";
328
+ const strapi$1 = {
329
+ displayName: "Fuzzy Search",
330
+ name: "fuzzy-search",
331
+ description: "Register a weighted fuzzy search endpoint to your content types in no time.",
332
+ kind: "plugin"
333
+ };
334
+ const type = "commonjs";
335
+ const exports = {
336
+ "./package.json": "./package.json",
337
+ "./strapi-server": {
338
+ types: "./dist/server/src/index.d.ts",
339
+ source: "./server/src/index.ts",
340
+ "import": "./dist/server/index.mjs",
341
+ require: "./dist/server/index.js",
342
+ "default": "./dist/server/index.js"
343
+ }
344
+ };
345
+ const files = [
346
+ "dist"
347
+ ];
348
+ const scripts = {
349
+ "semantic-release": "semantic-release",
350
+ build: "strapi-plugin build",
351
+ watch: "strapi-plugin watch",
352
+ "watch:link": "strapi-plugin watch:link",
353
+ verify: "strapi-plugin verify",
354
+ "test:ts:back": "run -T tsc -p server/tsconfig.json",
355
+ typecheck: "tsc --noEmit -p server/tsconfig.json",
356
+ test: "vitest",
357
+ "test:coverage": "vitest run --coverage",
358
+ "test:coverage:json": "vitest run --coverage.enabled --coverage.reporter=json-summary",
359
+ lint: "eslint .",
360
+ "prettier:check": "prettier --check ./server ./tests",
361
+ "prettier:write": "prettier --write ./server ./tests"
362
+ };
363
+ const publishConfig = {
364
+ registry: "https://registry.npmjs.org/",
365
+ tag: "latest"
366
+ };
367
+ const release = {
368
+ branches: [
369
+ "main",
370
+ {
371
+ name: "beta",
372
+ prerelease: true
373
+ }
374
+ ]
375
+ };
376
+ const dependencies = {
377
+ fuzzysort: "3.1.0",
378
+ transliteration: "2.3.5"
379
+ };
380
+ const peerDependencies = {
381
+ "@strapi/sdk-plugin": "^5.2.7",
382
+ "@strapi/strapi": "^5.1.1",
383
+ "@strapi/utils": "^5.1.1",
384
+ yup: "1.4.0"
385
+ };
386
+ const devDependencies = {
387
+ "@eslint/compat": "^1.2.2",
388
+ "@eslint/eslintrc": "^3.1.0",
389
+ "@eslint/js": "^9.13.0",
390
+ "@strapi/sdk-plugin": "^5.2.7",
391
+ "@strapi/strapi": "^5.1.1",
392
+ "@strapi/typescript-utils": "^5.1.1",
393
+ "@typescript-eslint/eslint-plugin": "8.12.1",
394
+ "@typescript-eslint/parser": "8.12.1",
395
+ "@vitest/coverage-v8": "2.1.4",
396
+ "all-contributors-cli": "^6.20.0",
397
+ eslint: "^9.13.0",
398
+ "eslint-config-prettier": "9.1.0",
399
+ "eslint-plugin-import": "2.31.0",
400
+ "eslint-plugin-prettier": "5.2.1",
401
+ "eslint-plugin-promise": "7.1.0",
402
+ globals: "^15.11.0",
403
+ prettier: "3.3.3",
404
+ "semantic-release": "^24.0.0",
405
+ typescript: "^5.6.3",
406
+ "typescript-eslint": "^8.12.1",
407
+ vitest: "2.1.4"
408
+ };
409
+ const author = "@DomDew (https://github.com/DomDew)";
410
+ const maintainers = [
411
+ "@DomDew (https://github.com/DomDew)",
412
+ "@wfproductions (https://github.com/wfproductions)"
413
+ ];
414
+ const engines = {
415
+ node: ">=18.x.x <=20.x.x",
416
+ npm: ">=6.0.0"
417
+ };
418
+ const license = "MIT";
419
+ const repository = {
420
+ type: "git",
421
+ url: "https://github.com/DomDew/strapi-plugin-fuzzy-search.git"
422
+ };
423
+ const keywords = [
424
+ "strapi",
425
+ "fuzzysort",
426
+ "fuzzysearch",
427
+ "search"
428
+ ];
429
+ const bugs = {
430
+ url: "https://github.com/DomDew/strapi-plugin-fuzzy-search/issues"
431
+ };
432
+ const homepage = "https://github.com/DomDew/strapi-plugin-fuzzy-search#readme";
433
+ const packageJson = {
434
+ name,
435
+ version,
436
+ description,
437
+ strapi: strapi$1,
438
+ type,
439
+ exports,
440
+ files,
441
+ scripts,
442
+ publishConfig,
443
+ release,
444
+ dependencies,
445
+ peerDependencies,
446
+ devDependencies,
447
+ author,
448
+ maintainers,
449
+ engines,
450
+ license,
451
+ repository,
452
+ keywords,
453
+ bugs,
454
+ homepage
455
+ };
456
+ const pluginId = packageJson.strapi.name;
457
+ const settingsService = () => ({
458
+ get() {
459
+ return strapi.config.get(`plugin::${pluginId}`);
460
+ },
461
+ set(settings) {
462
+ return strapi.config.set(`plugin::${pluginId}`, settings);
463
+ },
464
+ build(settings) {
465
+ return {
466
+ ...settings,
467
+ contentTypes: settings.contentTypes.map((contentType) => ({
468
+ ...contentType,
469
+ ...strapi.contentTypes[contentType.uid]
470
+ }))
471
+ };
472
+ }
473
+ });
474
+ const { NotFoundError } = errors;
475
+ const searchController = () => ({
476
+ async search(ctx) {
477
+ const { contentTypes } = settingsService().get();
478
+ const {
479
+ query,
480
+ pagination,
481
+ filters: filtersQuery,
482
+ locale,
483
+ populate,
484
+ status: statusQuery
485
+ } = ctx.query;
486
+ const { auth } = ctx.state;
487
+ const queriedContentTypes = filtersQuery && filtersQuery.contentTypes ? filtersQuery.contentTypes?.split(",") : void 0;
488
+ try {
489
+ await validateQueryParams(
490
+ ctx.query,
491
+ contentTypes,
492
+ pagination,
493
+ populate,
494
+ queriedContentTypes
495
+ );
496
+ } catch (err) {
497
+ let message = "unknown error";
498
+ if (err instanceof Error) message = err.message;
499
+ return ctx.badRequest("Invalid query", message);
500
+ }
501
+ const queriedContentTypesSet = new Set(queriedContentTypes);
502
+ const filteredContentTypes = filtersQuery?.contentTypes ? [...contentTypes].filter(
503
+ (contentType) => queriedContentTypesSet.has(contentType.info.pluralName)
504
+ ) : contentTypes;
505
+ const results = await Promise.all(
506
+ filteredContentTypes.map(
507
+ async (contentType) => await getResult({
508
+ contentType,
509
+ query,
510
+ filters: filtersQuery?.[contentType.info.pluralName],
511
+ populate: populate?.[contentType.info.pluralName],
512
+ locale: filtersQuery?.[contentType.info.pluralName]?.locale || locale,
513
+ status: statusQuery?.[contentType.info.pluralName] || "published"
514
+ })
515
+ )
516
+ );
517
+ const response = await buildRestResponse(
518
+ results,
519
+ auth,
520
+ pagination,
521
+ queriedContentTypes
522
+ );
523
+ if (response) {
524
+ return response;
525
+ } else {
526
+ throw new NotFoundError();
527
+ }
528
+ }
529
+ });
530
+ const controllers = { searchController };
531
+ const getResolversConfig = () => {
532
+ return {
533
+ "Query.search": {
534
+ auth: {
535
+ scope: "plugin::fuzzy-search.searchController.search"
536
+ }
537
+ }
538
+ };
539
+ };
540
+ const getCustomTypes = (strapi2, nexus) => {
541
+ const { service: getService } = strapi2.plugin("graphql");
542
+ const { naming } = getService("utils");
543
+ const { utils } = getService("builders");
544
+ const { contentTypes } = settingsService().get();
545
+ const {
546
+ getEntityResponseCollectionName,
547
+ getFindQueryName,
548
+ getFiltersInputTypeName
549
+ } = naming;
550
+ const { transformArgs, getContentTypeArgs } = utils;
551
+ const extendSearchType = (nexus2, model) => {
552
+ return nexus2.extendType({
553
+ type: "SearchResponse",
554
+ definition(t) {
555
+ t.field(getFindQueryName(model), {
556
+ type: getEntityResponseCollectionName(model),
557
+ args: getContentTypeArgs(model, { multiple: true }),
558
+ async resolve(parent, args, ctx, info) {
559
+ const { query, locale: parentLocaleQuery } = parent;
560
+ const {
561
+ pagination,
562
+ filters,
563
+ locale: contentTypeLocaleQuery,
564
+ status: contentTypeStatusQuery
565
+ } = args;
566
+ const locale = contentTypeLocaleQuery || parentLocaleQuery;
567
+ const {
568
+ start: transformedStart,
569
+ limit: transformedLimit,
570
+ filters: transformedFilters
571
+ } = transformArgs(
572
+ { pagination, filters },
573
+ {
574
+ contentType: model,
575
+ usePagination: true
576
+ }
577
+ );
578
+ const contentType = contentTypes.find(
579
+ (contentType2) => contentType2.modelName === model.modelName
580
+ );
581
+ if (!contentType) return;
582
+ const results = await getResult({
583
+ contentType,
584
+ query,
585
+ filters: transformedFilters,
586
+ populate: void 0,
587
+ locale,
588
+ status: contentTypeStatusQuery
589
+ });
590
+ const resultsResponse = await buildGraphqlResponse(
591
+ results.fuzzysortResults,
592
+ contentType,
593
+ ctx.state?.auth,
594
+ { start: transformedStart, limit: transformedLimit }
595
+ );
596
+ if (resultsResponse) return resultsResponse;
597
+ throw new Error(ctx.koaContext.response.message);
598
+ }
599
+ });
600
+ }
601
+ });
602
+ };
603
+ const searchResponseType = nexus.extendType({
604
+ type: "Query",
605
+ definition(t) {
606
+ t.field("search", {
607
+ type: "SearchResponse",
608
+ args: {
609
+ query: nexus.nonNull(
610
+ nexus.stringArg(
611
+ "The query string by which the models are searched"
612
+ )
613
+ ),
614
+ locale: nexus.stringArg("The locale by which to filter the models")
615
+ },
616
+ async resolve(_parent, args, ctx) {
617
+ const { query, locale } = args;
618
+ const { auth } = ctx.state;
619
+ return { query, locale, auth };
620
+ }
621
+ });
622
+ }
623
+ });
624
+ const returnTypes = [searchResponseType];
625
+ contentTypes.forEach((type2) => {
626
+ returnTypes.unshift(extendSearchType(nexus, type2));
627
+ });
628
+ return returnTypes;
629
+ };
630
+ const registerGraphlQLQuery = (strapi2) => {
631
+ const extension = ({ nexus }) => ({
632
+ types: getCustomTypes(strapi2, nexus),
633
+ resolversConfig: getResolversConfig()
634
+ });
635
+ strapi2.plugin("graphql").service("extension").use(extension);
636
+ };
637
+ const register = ({ strapi: strapi2 }) => {
638
+ const {
639
+ get: getSettings,
640
+ build: buildSettings,
641
+ set: setSettings
642
+ } = settingsService();
643
+ const settings = getSettings();
644
+ const normalizedSettings = buildSettings(settings);
645
+ setSettings(normalizedSettings);
646
+ if (strapi2.plugin("graphql")) {
647
+ strapi2.log.info("[fuzzy-search] graphql detected, registering queries");
648
+ registerGraphlQLQuery(strapi2);
649
+ }
650
+ };
651
+ const searchRoutes = [
652
+ {
653
+ method: "GET",
654
+ path: "/search",
655
+ handler: "searchController.search"
656
+ }
657
+ ];
658
+ const routes = {
659
+ "content-api": {
660
+ type: "content-api",
661
+ routes: searchRoutes
662
+ }
663
+ };
664
+ const services = {
665
+ settingsService
666
+ };
667
+ const index = {
668
+ bootstrap,
669
+ register,
670
+ config,
671
+ controllers,
672
+ routes,
673
+ services
674
+ };
675
+ export {
676
+ index as default
677
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: () => void;
2
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import * as yup from 'yup';
2
+ declare const pluginConfigSchema: yup.ObjectSchema<{
3
+ contentTypes: {
4
+ uid?: string;
5
+ modelName?: string;
6
+ transliterate?: boolean;
7
+ fuzzysortOptions?: {
8
+ threshold?: number;
9
+ limit?: number;
10
+ keys?: {
11
+ name?: string;
12
+ weight?: number;
13
+ }[];
14
+ };
15
+ }[];
16
+ }, yup.AnyObject, {
17
+ contentTypes: "";
18
+ }, "">;
19
+ export default pluginConfigSchema;
@@ -0,0 +1,8 @@
1
+ import { Config } from '../interfaces/interfaces';
2
+ declare const _default: {
3
+ default(): {
4
+ contentTypes: {};
5
+ };
6
+ validator(config: Config): Promise<void>;
7
+ };
8
+ export default _default;