@taurgis/bonsai 1.0.4 → 1.0.6
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.
- package/README.md +81 -2
- package/agents/agents/official-docs-researcher.agent.md +10 -1
- package/agents/agents/salesforce-docs-researcher.agent.md +126 -0
- package/agents/hooks/README.md +62 -0
- package/agents/hooks/claude-code/hooks/bonsai-web-fetch.sh +22 -0
- package/agents/hooks/claude-code/settings.json +16 -0
- package/agents/hooks/codex/hooks/bonsai-user-prompt-context.sh +18 -0
- package/agents/hooks/codex/hooks/bonsai-web-fetch.sh +22 -0
- package/agents/hooks/codex/hooks.json +28 -0
- package/agents/hooks/cursor/hooks/bonsai-web-fetch.sh +21 -0
- package/agents/hooks/cursor/hooks.json +12 -0
- package/agents/hooks/github-copilot/bonsai-web-fetch.json +23 -0
- package/agents/hooks/github-copilot/bonsai-web-fetch.sh +19 -0
- package/agents/instructions/salesforce-research.instructions.md +59 -0
- package/agents/instructions/web-research.instructions.md +5 -2
- package/agents/skills/web-research/SKILL.md +8 -3
- package/bin/cli.mjs +35 -8
- package/dist/base-command.d.ts +23 -0
- package/dist/base-command.js +67 -8
- package/dist/commands/config/base.d.ts +2 -0
- package/dist/commands/config/base.js +15 -1
- package/dist/commands/config/get.d.ts +1 -1
- package/dist/commands/config/get.js +6 -7
- package/dist/commands/config/index.d.ts +12 -0
- package/dist/commands/config/index.js +34 -0
- package/dist/commands/config/list.js +4 -4
- package/dist/commands/config/set.js +20 -14
- package/dist/commands/config/unset.d.ts +1 -1
- package/dist/commands/config/unset.js +11 -8
- package/dist/commands/fetch.d.ts +5 -0
- package/dist/commands/fetch.js +122 -47
- package/dist/commands/import.d.ts +4 -0
- package/dist/commands/import.js +99 -37
- package/dist/commands/inspect.d.ts +4 -0
- package/dist/commands/inspect.js +24 -19
- package/dist/commands/list.d.ts +2 -2
- package/dist/commands/list.js +39 -16
- package/dist/commands/prune.d.ts +1 -1
- package/dist/commands/prune.js +50 -17
- package/dist/commands/search.d.ts +4 -0
- package/dist/commands/search.js +102 -41
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.js +58 -31
- package/dist/commands.d.ts +2 -0
- package/dist/commands.js +2 -0
- package/dist/hooks/command-not-found/suggest.d.ts +9 -0
- package/dist/hooks/command-not-found/suggest.js +122 -0
- package/dist/lib/argv.d.ts +10 -0
- package/dist/lib/argv.js +53 -0
- package/dist/lib/config/index.d.ts +1 -1
- package/dist/lib/config/index.js +1 -1
- package/dist/lib/config/resolve.d.ts +7 -0
- package/dist/lib/config/resolve.js +23 -0
- package/dist/lib/envelope.d.ts +36 -0
- package/dist/lib/envelope.js +76 -0
- package/dist/lib/json-meta.d.ts +10 -0
- package/dist/lib/json-meta.js +98 -0
- package/dist/lib/research/browser.d.ts +12 -0
- package/dist/lib/research/browser.js +40 -3
- package/dist/lib/research/docs/capabilities.d.ts +1 -1
- package/dist/lib/research/docs/discovery-index.d.ts +14 -0
- package/dist/lib/research/docs/discovery-index.js +112 -0
- package/dist/lib/research/docs/machine-readable.d.ts +2 -2
- package/dist/lib/research/docs/machine-readable.js +3 -7
- package/dist/lib/research/docs/remote-search-runner.js +61 -1
- package/dist/lib/research/docs/sections.d.ts +1 -0
- package/dist/lib/research/docs/sections.js +19 -1
- package/dist/lib/research/freshness.d.ts +9 -1
- package/dist/lib/research/freshness.js +24 -2
- package/dist/lib/research/keywords.d.ts +10 -3
- package/dist/lib/research/keywords.js +32 -5
- package/dist/lib/research/revalidate.js +3 -1
- package/dist/lib/research/schema.d.ts +5 -2
- package/dist/lib/research/schema.js +12 -1
- package/dist/lib/research/secret-scan.js +4 -2
- package/dist/lib/research/url.js +5 -2
- package/dist/lib/text.d.ts +35 -0
- package/dist/lib/text.js +65 -0
- package/dist/sites/algolia.d.ts +9 -0
- package/dist/sites/algolia.js +26 -0
- package/dist/sites/auto.d.ts +8 -0
- package/dist/sites/auto.js +30 -0
- package/dist/sites/index.js +17 -1
- package/dist/sites/nextjs/index.d.ts +2 -0
- package/dist/sites/nextjs/index.js +52 -0
- package/dist/sites/react/index.d.ts +2 -0
- package/dist/sites/react/index.js +17 -0
- package/dist/sites/tailwind/index.d.ts +2 -0
- package/dist/sites/tailwind/index.js +17 -0
- package/dist/sites/vue/index.d.ts +2 -0
- package/dist/sites/vue/index.js +17 -0
- package/oclif.manifest.json +154 -81
- package/package.json +24 -4
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Display label when an artifact has no topic — not a filterable topic value. */
|
|
2
|
+
export declare const NO_TOPIC_LABEL = "(no topic)";
|
|
3
|
+
/**
|
|
4
|
+
* Pick the singular or plural noun for a count so human-readable output stays grammatical
|
|
5
|
+
* ("1 entry" / "2 entries"). English has irregular plurals, so the plural is passed explicitly
|
|
6
|
+
* rather than derived.
|
|
7
|
+
*/
|
|
8
|
+
export declare function pluralize(count: number, singular: string, plural: string): string;
|
|
9
|
+
/** How a command labels a result listing, so its heading and truncation notice stay consistent. */
|
|
10
|
+
export interface ResultListLabels {
|
|
11
|
+
/** Noun phrase after the count, e.g. "cached research"; the "entry/entries" plural is appended. */
|
|
12
|
+
noun: string;
|
|
13
|
+
/** Ordering word shown when truncated: "first" (recency order) or "top" (ranked order). */
|
|
14
|
+
order: 'first' | 'top';
|
|
15
|
+
/** The command's --limit ceiling, surfaced in the truncation hint. */
|
|
16
|
+
maxLimit: number;
|
|
17
|
+
}
|
|
18
|
+
/** Heading for a result listing; notes truncation inline when more matched than are shown. */
|
|
19
|
+
export declare function resultListHeading(total: number, shown: number, labels: ResultListLabels): string;
|
|
20
|
+
/**
|
|
21
|
+
* One-line truncation notice for stderr, or null when nothing was cut. Used under --json, where the
|
|
22
|
+
* stdout heading is suppressed and an agent would otherwise get no signal that results were capped.
|
|
23
|
+
*/
|
|
24
|
+
export declare function truncationNotice(total: number, shown: number, labels: ResultListLabels): string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Levenshtein edit distance: the minimum number of single-character insertions, deletions, or
|
|
27
|
+
* substitutions to turn `s1` into `s2`. Shared by fuzzy search ranking and command-typo suggestion.
|
|
28
|
+
*/
|
|
29
|
+
export declare function levenshtein(s1: string, s2: string): number;
|
|
30
|
+
/**
|
|
31
|
+
* The candidate nearest to `input` by edit distance, or null when even the closest is farther than
|
|
32
|
+
* `maxDistance`. The threshold keeps suggestions to plausible typos — input that resembles nothing
|
|
33
|
+
* gets no correction rather than an absurd one.
|
|
34
|
+
*/
|
|
35
|
+
export declare function closestMatch(input: string, candidates: readonly string[], maxDistance: number): string | null;
|
package/dist/lib/text.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** Display label when an artifact has no topic — not a filterable topic value. */
|
|
2
|
+
export const NO_TOPIC_LABEL = '(no topic)';
|
|
3
|
+
/**
|
|
4
|
+
* Pick the singular or plural noun for a count so human-readable output stays grammatical
|
|
5
|
+
* ("1 entry" / "2 entries"). English has irregular plurals, so the plural is passed explicitly
|
|
6
|
+
* rather than derived.
|
|
7
|
+
*/
|
|
8
|
+
export function pluralize(count, singular, plural) {
|
|
9
|
+
return count === 1 ? singular : plural;
|
|
10
|
+
}
|
|
11
|
+
/** Heading for a result listing; notes truncation inline when more matched than are shown. */
|
|
12
|
+
export function resultListHeading(total, shown, labels) {
|
|
13
|
+
const noun = `${labels.noun} ${pluralize(total, 'entry', 'entries')}`;
|
|
14
|
+
return total > shown
|
|
15
|
+
? `Found ${total} ${noun} (showing ${labels.order} ${shown}; raise --limit to see more):`
|
|
16
|
+
: `Found ${total} ${noun}:`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* One-line truncation notice for stderr, or null when nothing was cut. Used under --json, where the
|
|
20
|
+
* stdout heading is suppressed and an agent would otherwise get no signal that results were capped.
|
|
21
|
+
*/
|
|
22
|
+
export function truncationNotice(total, shown, labels) {
|
|
23
|
+
if (total <= shown)
|
|
24
|
+
return null;
|
|
25
|
+
return `${total} entries matched; returning the ${labels.order} ${shown}. Raise --limit (max ${labels.maxLimit}) to see more.`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Levenshtein edit distance: the minimum number of single-character insertions, deletions, or
|
|
29
|
+
* substitutions to turn `s1` into `s2`. Shared by fuzzy search ranking and command-typo suggestion.
|
|
30
|
+
*/
|
|
31
|
+
export function levenshtein(s1, s2) {
|
|
32
|
+
if (s1.length < s2.length)
|
|
33
|
+
return levenshtein(s2, s1);
|
|
34
|
+
if (s2.length === 0)
|
|
35
|
+
return s1.length;
|
|
36
|
+
let prevRow = Array.from({ length: s2.length + 1 }, (_, i) => i);
|
|
37
|
+
for (let i = 0; i < s1.length; i++) {
|
|
38
|
+
const currRow = [i + 1];
|
|
39
|
+
for (let j = 0; j < s2.length; j++) {
|
|
40
|
+
const deletions = prevRow[j + 1] + 1;
|
|
41
|
+
const insertions = currRow[j] + 1;
|
|
42
|
+
const substitutions = prevRow[j] + (s1[i] === s2[j] ? 0 : 1);
|
|
43
|
+
currRow.push(Math.min(deletions, insertions, substitutions));
|
|
44
|
+
}
|
|
45
|
+
prevRow = currRow;
|
|
46
|
+
}
|
|
47
|
+
return prevRow[s2.length];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The candidate nearest to `input` by edit distance, or null when even the closest is farther than
|
|
51
|
+
* `maxDistance`. The threshold keeps suggestions to plausible typos — input that resembles nothing
|
|
52
|
+
* gets no correction rather than an absurd one.
|
|
53
|
+
*/
|
|
54
|
+
export function closestMatch(input, candidates, maxDistance) {
|
|
55
|
+
let best = null;
|
|
56
|
+
let bestDistance = Infinity;
|
|
57
|
+
for (const candidate of candidates) {
|
|
58
|
+
const distance = levenshtein(input, candidate);
|
|
59
|
+
if (distance < bestDistance) {
|
|
60
|
+
bestDistance = distance;
|
|
61
|
+
best = candidate;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return bestDistance <= maxDistance ? best : null;
|
|
65
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SiteModule } from './types.js';
|
|
2
|
+
export declare function createAlgoliaSite(id: string, name: string, domains: string[], appId: string, apiKey: string, indexName: string): SiteModule;
|
|
3
|
+
export declare const react: SiteModule;
|
|
4
|
+
export declare const vue: SiteModule;
|
|
5
|
+
export declare const tailwind: SiteModule;
|
|
6
|
+
export declare const jest: SiteModule;
|
|
7
|
+
export declare const cypress: SiteModule;
|
|
8
|
+
export declare const vitest: SiteModule;
|
|
9
|
+
export declare const vitepress: SiteModule;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { algoliaQueryUrl, parseAlgoliaResponse } from '../lib/research/docs/remote-search.js';
|
|
2
|
+
import { postJson } from '../lib/research/fetcher.js';
|
|
3
|
+
export function createAlgoliaSite(id, name, domains, appId, apiKey, indexName) {
|
|
4
|
+
return {
|
|
5
|
+
id,
|
|
6
|
+
name,
|
|
7
|
+
domains,
|
|
8
|
+
search: async (query) => {
|
|
9
|
+
const url = algoliaQueryUrl({ appId, apiKey, indexName });
|
|
10
|
+
const bodyParams = { params: `query=${encodeURIComponent(query)}&hitsPerPage=20` };
|
|
11
|
+
const res = await postJson(url, bodyParams, {
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
'X-Algolia-API-Key': apiKey,
|
|
14
|
+
'X-Algolia-Application-Id': appId,
|
|
15
|
+
});
|
|
16
|
+
return parseAlgoliaResponse(res, url);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export const react = createAlgoliaSite('react', 'React', ['react.dev', 'legacy.reactjs.org'], '1FCF9AYYAT', '1b7ad4e1c89e645e351e59d40544eda1', 'beta-react');
|
|
21
|
+
export const vue = createAlgoliaSite('vue', 'Vue.js', ['vuejs.org'], 'ML0LEBN7FQ', '10e7a8b13e6aec4007343338ab134e05', 'vuejs');
|
|
22
|
+
export const tailwind = createAlgoliaSite('tailwind', 'Tailwind CSS', ['tailwindcss.com'], 'KNPXZI5B0M', '5fc87cef58bb80203d2207578309fab6', 'tailwindcss');
|
|
23
|
+
export const jest = createAlgoliaSite('jest', 'Jest', ['jestjs.io'], 'HP439UUSOL', 'e5e670fd16f8f17caada79d6b0931682', 'jest-v2');
|
|
24
|
+
export const cypress = createAlgoliaSite('cypress', 'Cypress', ['docs.cypress.io', 'cypress.io'], 'R9KDA5FMJB', 'b4af59e23bc2fa05281af7dcf13fcae5', 'cypress_docs');
|
|
25
|
+
export const vitest = createAlgoliaSite('vitest', 'Vitest', ['vitest.dev'], 'ZTF29HGJ69', '9c3ced6fed60d2670bb36ab7e8bed8bc', 'vitest');
|
|
26
|
+
export const vitepress = createAlgoliaSite('vitepress', 'VitePress', ['vitepress.dev'], '8J64VVRP8K', '52f578a92b88ad6abde815aae2b0ad7c', 'vitepress');
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SiteModule } from './types.js';
|
|
2
|
+
export declare function createAutoSite(id: string, name: string, domains: string[], docsUrl: string): SiteModule;
|
|
3
|
+
export declare const angular: SiteModule;
|
|
4
|
+
export declare const redux: SiteModule;
|
|
5
|
+
export declare const vite: SiteModule;
|
|
6
|
+
export declare const fastify: SiteModule;
|
|
7
|
+
export declare const rollup: SiteModule;
|
|
8
|
+
export declare const vueuse: SiteModule;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { runRemoteDocsSearch } from '../lib/research/docs/remote-search-runner.js';
|
|
2
|
+
import { fetchStaticHtml, fetchText, postJson } from '../lib/research/fetcher.js';
|
|
3
|
+
export function createAutoSite(id, name, domains, docsUrl) {
|
|
4
|
+
return {
|
|
5
|
+
id,
|
|
6
|
+
name,
|
|
7
|
+
domains,
|
|
8
|
+
search: async (query) => {
|
|
9
|
+
const deps = {
|
|
10
|
+
fetchStatic: async (url) => {
|
|
11
|
+
const res = await fetchStaticHtml(url);
|
|
12
|
+
return { content: res.content, finalUrl: res.finalUrl };
|
|
13
|
+
},
|
|
14
|
+
fetchText: async (url) => {
|
|
15
|
+
const res = await fetchText(url);
|
|
16
|
+
return { content: res.content, status: res.status };
|
|
17
|
+
},
|
|
18
|
+
postJson: (url, body, headers) => postJson(url, body, headers),
|
|
19
|
+
};
|
|
20
|
+
const { results } = await runRemoteDocsSearch(docsUrl, query, deps);
|
|
21
|
+
return results;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export const angular = createAutoSite('angular', 'Angular', ['angular.dev'], 'https://angular.dev');
|
|
26
|
+
export const redux = createAutoSite('redux', 'Redux', ['redux.js.org'], 'https://redux.js.org');
|
|
27
|
+
export const vite = createAutoSite('vite', 'Vite', ['vitejs.dev', 'vite.dev'], 'https://vite.dev');
|
|
28
|
+
export const fastify = createAutoSite('fastify', 'Fastify', ['fastify.dev', 'fastify.io'], 'https://fastify.dev');
|
|
29
|
+
export const rollup = createAutoSite('rollup', 'Rollup', ['rollupjs.org'], 'https://rollupjs.org');
|
|
30
|
+
export const vueuse = createAutoSite('vueuse', 'VueUse', ['vueuse.org'], 'https://vueuse.org');
|
package/dist/sites/index.js
CHANGED
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import { salesforce } from './salesforce/index.js';
|
|
2
2
|
import { salesforceDeveloper } from './salesforce-developer/index.js';
|
|
3
|
+
import { nextjs } from './nextjs/index.js';
|
|
4
|
+
import { react, vue, tailwind, jest, cypress, vitest, vitepress } from './algolia.js';
|
|
5
|
+
import { angular, redux, vite, fastify, rollup, vueuse } from './auto.js';
|
|
3
6
|
// The known documentation sites. A plain constant, not a registry: these ship
|
|
4
7
|
// with the CLI, so there is nothing to register at runtime. Sites with custom
|
|
5
8
|
// fetch/search behavior live in their own module (e.g. ./salesforce). Salesforce Help and
|
|
6
9
|
// Salesforce Developer are separate modules — different domains, different extraction.
|
|
7
10
|
export const SITES = [
|
|
8
|
-
|
|
11
|
+
react,
|
|
12
|
+
vue,
|
|
13
|
+
tailwind,
|
|
14
|
+
nextjs,
|
|
15
|
+
jest,
|
|
16
|
+
cypress,
|
|
17
|
+
vitest,
|
|
18
|
+
vitepress,
|
|
19
|
+
angular,
|
|
20
|
+
redux,
|
|
21
|
+
vite,
|
|
22
|
+
fastify,
|
|
23
|
+
rollup,
|
|
24
|
+
vueuse,
|
|
9
25
|
salesforce,
|
|
10
26
|
salesforceDeveloper,
|
|
11
27
|
// TanStack docs embed a GitHub "edit this page" link, so capture resolves the page's source
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { postJson } from '../../lib/research/fetcher.js';
|
|
2
|
+
export const nextjs = {
|
|
3
|
+
id: 'nextjs',
|
|
4
|
+
name: 'Next.js',
|
|
5
|
+
domains: ['nextjs.org'],
|
|
6
|
+
search: async (query) => {
|
|
7
|
+
const url = 'https://nextjs.org/api/search';
|
|
8
|
+
const bodyStr = await postJson(url, { query, version: 'stable', routerType: 'app' }, {});
|
|
9
|
+
let data;
|
|
10
|
+
try {
|
|
11
|
+
// The Next.js API returns a JSON array sometimes or a JSON object with 'hits'
|
|
12
|
+
const parsed = JSON.parse(bodyStr);
|
|
13
|
+
if (Array.isArray(parsed)) {
|
|
14
|
+
data = parsed;
|
|
15
|
+
}
|
|
16
|
+
else if (parsed && Array.isArray(parsed.hits)) {
|
|
17
|
+
data = parsed.hits;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
throw new Error('Unexpected response format from Next.js search');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
throw new Error(`Failed to parse Next.js search response: ${err.message}`);
|
|
25
|
+
}
|
|
26
|
+
const queryLower = query.toLowerCase();
|
|
27
|
+
return data.map((item) => {
|
|
28
|
+
const content = item.content || '';
|
|
29
|
+
let snippet = content;
|
|
30
|
+
const idx = content.toLowerCase().indexOf(queryLower);
|
|
31
|
+
if (idx !== -1) {
|
|
32
|
+
const start = Math.max(0, idx - 40);
|
|
33
|
+
const end = Math.min(content.length, idx + 110);
|
|
34
|
+
snippet = content.slice(start, end);
|
|
35
|
+
if (start > 0)
|
|
36
|
+
snippet = '...' + snippet;
|
|
37
|
+
if (end < content.length)
|
|
38
|
+
snippet = snippet + '...';
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
snippet = content.slice(0, 150);
|
|
42
|
+
}
|
|
43
|
+
// Clean up whitespace and newlines so it looks like a snippet and not a raw script
|
|
44
|
+
snippet = snippet.replace(/\s+/g, ' ').trim();
|
|
45
|
+
return {
|
|
46
|
+
url: `https://nextjs.org${item.path}${item.anchor ? `#${item.anchor}` : ''}`,
|
|
47
|
+
title: item.title ? `${item.pageTitle} - ${item.title}` : item.pageTitle || 'Untitled',
|
|
48
|
+
snippet,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { algoliaQueryUrl, parseAlgoliaResponse } from '../../lib/research/docs/remote-search.js';
|
|
2
|
+
import { postJson } from '../../lib/research/fetcher.js';
|
|
3
|
+
export const react = {
|
|
4
|
+
id: 'react',
|
|
5
|
+
name: 'React',
|
|
6
|
+
domains: ['react.dev', 'legacy.reactjs.org'],
|
|
7
|
+
search: async (query) => {
|
|
8
|
+
const config = {
|
|
9
|
+
appId: '1FCF9AYYAT',
|
|
10
|
+
apiKey: '1b7ad4e1c89e645e351e59d40544eda1',
|
|
11
|
+
indexName: 'beta-react'
|
|
12
|
+
};
|
|
13
|
+
const url = algoliaQueryUrl(config);
|
|
14
|
+
const body = await postJson(url, { params: `query=${encodeURIComponent(query)}` }, { 'X-Algolia-API-Key': config.apiKey, 'X-Algolia-Application-Id': config.appId });
|
|
15
|
+
return parseAlgoliaResponse(body, url);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { algoliaQueryUrl, parseAlgoliaResponse } from '../../lib/research/docs/remote-search.js';
|
|
2
|
+
import { postJson } from '../../lib/research/fetcher.js';
|
|
3
|
+
export const tailwind = {
|
|
4
|
+
id: 'tailwind',
|
|
5
|
+
name: 'Tailwind CSS',
|
|
6
|
+
domains: ['tailwindcss.com'],
|
|
7
|
+
search: async (query) => {
|
|
8
|
+
const config = {
|
|
9
|
+
appId: 'KNPXZI5B0M',
|
|
10
|
+
apiKey: '5fc87cef58bb80203d2207578309fab6',
|
|
11
|
+
indexName: 'tailwindcss'
|
|
12
|
+
};
|
|
13
|
+
const url = algoliaQueryUrl(config);
|
|
14
|
+
const body = await postJson(url, { params: `query=${encodeURIComponent(query)}` }, { 'X-Algolia-API-Key': config.apiKey, 'X-Algolia-Application-Id': config.appId });
|
|
15
|
+
return parseAlgoliaResponse(body, url);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { algoliaQueryUrl, parseAlgoliaResponse } from '../../lib/research/docs/remote-search.js';
|
|
2
|
+
import { postJson } from '../../lib/research/fetcher.js';
|
|
3
|
+
export const vue = {
|
|
4
|
+
id: 'vue',
|
|
5
|
+
name: 'Vue.js',
|
|
6
|
+
domains: ['vuejs.org'],
|
|
7
|
+
search: async (query) => {
|
|
8
|
+
const config = {
|
|
9
|
+
appId: 'ML0LEBN7FQ',
|
|
10
|
+
apiKey: '10e7a8b13e6aec4007343338ab134e05',
|
|
11
|
+
indexName: 'vuejs'
|
|
12
|
+
};
|
|
13
|
+
const url = algoliaQueryUrl(config);
|
|
14
|
+
const body = await postJson(url, { params: `query=${encodeURIComponent(query)}` }, { 'X-Algolia-API-Key': config.apiKey, 'X-Algolia-Application-Id': config.appId });
|
|
15
|
+
return parseAlgoliaResponse(body, url);
|
|
16
|
+
}
|
|
17
|
+
};
|