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