@microsoft/rayfin-docs 1.27.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) Microsoft Corporation.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,132 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "generatedAt": "2026-05-07T05:00:00Z",
4
+ "packages": [
5
+ {
6
+ "name": "@microsoft/rayfin-core",
7
+ "kind": "sdk",
8
+ "summary": "Code-first decorators for data model definition. The CLI reads this metadata to generate Data API Builder configuration.",
9
+ "topics": [
10
+ "entity",
11
+ "decorator",
12
+ "data-model",
13
+ "schema",
14
+ "dab",
15
+ "fabric"
16
+ ],
17
+ "modules": ["rayfin-core"]
18
+ },
19
+ {
20
+ "name": "@microsoft/rayfin-data",
21
+ "kind": "sdk",
22
+ "summary": "DAB-compliant data client for GraphQL access patterns against the generated DAB endpoint.",
23
+ "topics": ["graphql", "data", "client", "query", "mutation", "dab"],
24
+ "modules": ["rayfin-data"]
25
+ },
26
+ {
27
+ "name": "@microsoft/rayfin-auth",
28
+ "kind": "sdk",
29
+ "summary": "Authentication helpers: magic-link sign-in, token management, sign-in flows for Rayfin Builder apps.",
30
+ "topics": [
31
+ "auth",
32
+ "authentication",
33
+ "magic-link",
34
+ "signin",
35
+ "login",
36
+ "token",
37
+ "session"
38
+ ],
39
+ "modules": ["rayfin-auth"]
40
+ },
41
+ {
42
+ "name": "@microsoft/rayfin-client",
43
+ "kind": "sdk",
44
+ "summary": "High-level Rayfin client entrypoint composing auth and data APIs behind a single configured client.",
45
+ "topics": ["client", "service", "composition", "high-level"],
46
+ "modules": ["rayfin-client"]
47
+ },
48
+ {
49
+ "name": "@microsoft/rayfin-lib",
50
+ "kind": "sdk",
51
+ "summary": "Shared HTTP and client utilities used by higher-level Rayfin SDKs.",
52
+ "topics": ["http", "shared", "utility", "internal"],
53
+ "modules": ["rayfin-lib"]
54
+ },
55
+ {
56
+ "name": "@microsoft/rayfin-functions",
57
+ "kind": "sdk",
58
+ "summary": "TypeScript helpers for function-style workflows on top of Rayfin core.",
59
+ "topics": ["functions", "serverless", "azure-functions", "workflow"],
60
+ "modules": []
61
+ },
62
+ {
63
+ "name": "@microsoft/rayfin-storage",
64
+ "kind": "sdk",
65
+ "summary": "Type-safe blob storage client for Rayfin storage backends.",
66
+ "topics": ["storage", "blob", "azure-blob", "file", "upload"],
67
+ "modules": []
68
+ },
69
+ {
70
+ "name": "@microsoft/rayfin-auth-provider-fabric",
71
+ "kind": "sdk",
72
+ "summary": "Microsoft Fabric token provider for Rayfin auth flows.",
73
+ "topics": ["fabric", "auth-provider", "token", "msal"],
74
+ "modules": ["rayfin-auth-provider-fabric"]
75
+ },
76
+ {
77
+ "name": "@microsoft/rayfin-cli",
78
+ "kind": "tool",
79
+ "summary": "Rayfin command-line interface: scaffolding, configuration, deployment, and the `rayfin docs` command group for offline-friendly agent grounding.",
80
+ "topics": ["cli", "scaffolding", "init", "deploy", "docs"],
81
+ "modules": []
82
+ },
83
+ {
84
+ "name": "@microsoft/rayfin-mcp",
85
+ "kind": "tool",
86
+ "summary": "Model Context Protocol server exposing Rayfin docs as `list_docs`, `search_docs`, `get_doc`, and `discover_packages` tools.",
87
+ "topics": ["mcp", "agent", "docs-server", "model-context-protocol"],
88
+ "modules": []
89
+ },
90
+ {
91
+ "name": "@microsoft/rayfin-docs",
92
+ "kind": "tool",
93
+ "summary": "Docs indexing/discovery library powering the CLI and MCP server. Handles the `rayfinDocs` per-package convention and merges installed package docs.",
94
+ "topics": ["docs-library", "indexer", "search", "discovery"],
95
+ "modules": []
96
+ },
97
+ {
98
+ "name": "@microsoft/rayfin-guide",
99
+ "kind": "guide",
100
+ "summary": "Cross-cutting Builder guides — getting started, auth overview, data permissions, CLI commands. Discovered via the `rayfinDocs` field.",
101
+ "topics": [
102
+ "guide",
103
+ "tutorial",
104
+ "quickstart",
105
+ "builder",
106
+ "getting-started"
107
+ ],
108
+ "modules": ["rayfin-guide"]
109
+ },
110
+ {
111
+ "name": "@microsoft/rayfin-host-docs",
112
+ "kind": "host",
113
+ "summary": "Host service reference docs for Rayfin .NET hosting components (WebService, Auth, Storage, DataApi, Function). Discovered via the rayfinDocs field.",
114
+ "topics": [
115
+ "host",
116
+ "dotnet",
117
+ "web-service",
118
+ "asp-net-core",
119
+ "graphql-endpoint",
120
+ "data-api-builder"
121
+ ],
122
+ "modules": ["rayfin-host"]
123
+ },
124
+ {
125
+ "name": "@microsoft/create-rayfin",
126
+ "kind": "tool",
127
+ "summary": "App scaffolding tool for bootstrapping new Rayfin projects via `npm create rayfin@latest`.",
128
+ "topics": ["scaffolding", "create", "init", "bootstrap"],
129
+ "modules": []
130
+ }
131
+ ]
132
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Internal subpath export for build tooling that needs the lower-level
3
+ * docs index primitives (loader + index-builder + serializer) — for
4
+ * example, build-time compatibility tooling that emits a static search
5
+ * index from package docs.
6
+ *
7
+ * Not part of the public API. Subject to change between minor versions.
8
+ * Library consumers should use `DocsService` from the package root.
9
+ */
10
+ export { loadDocs } from '../loader.js';
11
+ export { createDocsIndex, serializeDocsIndex, DOCS_INDEX_SCHEMA_VERSION, DOCS_SEARCH_CONFIG_FINGERPRINT, } from '../search.js';
12
+ export { DOCS_DEFAULT_MODULES } from '../index.js';
13
+ export type { DocModule } from '../types.js';
14
+ //# sourceMappingURL=build-index.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Internal subpath export for build tooling that needs the lower-level
3
+ * docs index primitives (loader + index-builder + serializer) — for
4
+ * example, build-time compatibility tooling that emits a static search
5
+ * index from package docs.
6
+ *
7
+ * Not part of the public API. Subject to change between minor versions.
8
+ * Library consumers should use `DocsService` from the package root.
9
+ */
10
+ export { loadDocs } from '../loader.js';
11
+ export { createDocsIndex, serializeDocsIndex, DOCS_INDEX_SCHEMA_VERSION, DOCS_SEARCH_CONFIG_FINGERPRINT, } from '../search.js';
12
+ export { DOCS_DEFAULT_MODULES } from '../index.js';
13
+ //# sourceMappingURL=build-index.js.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Bundled static manifest of Rayfin packages.
3
+ *
4
+ * Shipped inside `@microsoft/rayfin-docs` to power:
5
+ * - `rayfin docs discover <query>` (CLI)
6
+ * - the `discover_packages` MCP tool
7
+ *
8
+ * The catalog answers "what packages exist, what could I install, and
9
+ * what should I update if the installed docs do not include a feature?"
10
+ * It is INTENTIONALLY decoupled from runtime discovery (which only sees
11
+ * what's installed in `node_modules`). The two compose: the agent first
12
+ * checks installed packages via `DocsService.searchDocs(...)`, and if
13
+ * nothing relevant comes back, falls through to `discoverPackages(query)`
14
+ * to surface install recommendations.
15
+ *
16
+ * Phase 4 of the `docs-package-architecture` migration. The catalog
17
+ * shape is hand-curated and bundled with `@microsoft/rayfin-docs`;
18
+ * updates ship as `rayfin-docs` version bumps (no hosted endpoint).
19
+ */
20
+ export type CatalogPackageKind = 'sdk' | 'tool' | 'guide' | 'host' | 'sample' | 'external';
21
+ /** A single entry in the catalog. */
22
+ export interface CatalogPackage {
23
+ /** Full npm name (e.g. `@microsoft/rayfin-core`). */
24
+ name: string;
25
+ /** Kind, used to group results in CLI/MCP surfaces. */
26
+ kind: CatalogPackageKind;
27
+ /** One-line summary surfaced in discover results. */
28
+ summary: string;
29
+ /** Searchable topics - used by the relevance scorer in
30
+ * `discoverPackages(query)`. Should be lowercased. */
31
+ topics: string[];
32
+ /** Doc modules this package contributes when installed. Mirrors the
33
+ * `rayfinDocs.module` field on the package itself. Empty when the
34
+ * package doesn't ship docs yet; SDK entries with no modules are
35
+ * kept for package awareness but are omitted from discover results. */
36
+ modules: string[];
37
+ /** Optional homepage URL - defaults to the npm page. */
38
+ homepageUrl?: string;
39
+ /** Optional install command override - defaults to `npm install <name>`. */
40
+ installCommand?: string;
41
+ /** Optional update command override - defaults to `npm install <name>@latest`. */
42
+ updateCommand?: string;
43
+ }
44
+ export interface Catalog {
45
+ schemaVersion: 1;
46
+ /** ISO-8601 timestamp when this catalog was last regenerated. Used by
47
+ * consumers to display a "catalog generated YYYY-MM-DD" footer when
48
+ * `rayfin docs catalog show` is invoked. */
49
+ generatedAt: string;
50
+ packages: CatalogPackage[];
51
+ }
52
+ //# sourceMappingURL=catalog-types.d.ts.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Bundled static manifest of Rayfin packages.
3
+ *
4
+ * Shipped inside `@microsoft/rayfin-docs` to power:
5
+ * - `rayfin docs discover <query>` (CLI)
6
+ * - the `discover_packages` MCP tool
7
+ *
8
+ * The catalog answers "what packages exist, what could I install, and
9
+ * what should I update if the installed docs do not include a feature?"
10
+ * It is INTENTIONALLY decoupled from runtime discovery (which only sees
11
+ * what's installed in `node_modules`). The two compose: the agent first
12
+ * checks installed packages via `DocsService.searchDocs(...)`, and if
13
+ * nothing relevant comes back, falls through to `discoverPackages(query)`
14
+ * to surface install recommendations.
15
+ *
16
+ * Phase 4 of the `docs-package-architecture` migration. The catalog
17
+ * shape is hand-curated and bundled with `@microsoft/rayfin-docs`;
18
+ * updates ship as `rayfin-docs` version bumps (no hosted endpoint).
19
+ */
20
+ export {};
21
+ //# sourceMappingURL=catalog-types.js.map
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Catalog of known Rayfin packages - what exists, what each does, how
3
+ * to install. Lives in `@microsoft/rayfin-docs` alongside the indexer
4
+ * because catalog updates and indexer changes share the same trigger
5
+ * ("we shipped a new SDK package"); splitting them across packages
6
+ * just multiplies release coordination overhead.
7
+ *
8
+ * - {@link getCatalog} returns the static manifest (cached, frozen).
9
+ * - {@link discoverPackages} ranks catalog packages by query relevance —
10
+ * used to power `rayfin docs discover <query>` and the MCP
11
+ * `discover_packages` tool when an agent's search through the
12
+ * installed corpus comes up empty or the installed package version
13
+ * appears too old to contain the requested feature.
14
+ *
15
+ * The catalog ships as a static JSON file inside this package's
16
+ * `assets/` directory. Updates are rolled out as `rayfin-docs` version
17
+ * bumps - there is no hosted-endpoint refresh path.
18
+ */
19
+ export type { Catalog, CatalogPackage, CatalogPackageKind, } from './catalog-types.js';
20
+ import type { Catalog, CatalogPackage, CatalogPackageKind } from './catalog-types.js';
21
+ export declare function getCatalog(): Catalog;
22
+ /**
23
+ * Reset the in-memory catalog cache so the next `getCatalog()` re-reads
24
+ * the bundled JSON. Test-only export.
25
+ */
26
+ export declare function _resetCatalogForTesting(): void;
27
+ /** Ranking signal score breakdown - exposed for tests + diagnostics. */
28
+ export interface DiscoverScore {
29
+ package: CatalogPackage;
30
+ score: number;
31
+ /** Which fields contributed. Useful for "why did this match?" UX. */
32
+ matchedOn: Array<'name' | 'summary' | 'topics' | 'kind'>;
33
+ }
34
+ /**
35
+ * Rank catalog packages by query relevance. Used by CLI/MCP discover
36
+ * surfaces. Scoring (deterministic, no embedding):
37
+ *
38
+ * - **name** exact substring match: +5
39
+ * - **kind** exact match (e.g. query "sdk"): +3
40
+ * - **topic** word match: +2 per matching topic
41
+ * - **summary** word match: +1 per matching token
42
+ *
43
+ * Returns scored packages sorted descending by score; ties broken by
44
+ * alphabetical package name. Packages with score 0 are excluded.
45
+ * SDK catalog-only entries with no docs modules are also excluded so
46
+ * discover results never recommend installing an SDK package that cannot
47
+ * contribute searchable docs yet.
48
+ *
49
+ * Stop-words and tokens shorter than 3 chars are ignored to keep the
50
+ * signal-to-noise ratio high - the rare "auth" 4-char query still
51
+ * matches because tokenization is on word boundaries, but "is"/"a"
52
+ * never match.
53
+ */
54
+ export declare function discoverPackages(query: string, catalog?: Catalog): DiscoverScore[];
55
+ /** Wire-shape item returned by both the CLI `rayfin docs discover --json`
56
+ * and the MCP `discover_packages` tool. Defined here so the two
57
+ * surfaces stay in lockstep - adding a field once updates both. */
58
+ export interface DiscoverItem {
59
+ name: string;
60
+ kind: CatalogPackageKind;
61
+ summary: string;
62
+ topics: string[];
63
+ installCommand: string;
64
+ updateCommand: string;
65
+ versionLockedDocs: string;
66
+ homepageUrl?: string;
67
+ score: number;
68
+ matchedOn: Array<'name' | 'summary' | 'topics' | 'kind'>;
69
+ }
70
+ /** Map a {@link DiscoverScore} to the wire shape consumed by both
71
+ * CLI and MCP. Defensive copies of array fields ensure consumers
72
+ * can't mutate the catalog singleton's frozen inner arrays via the
73
+ * result. */
74
+ export declare function mapDiscoverResult(score: DiscoverScore): DiscoverItem;
75
+ /** Derive an install command for a catalog package. Defaults to
76
+ * `npm install <name>` unless the catalog entry specifies an
77
+ * `installCommand` override (e.g. `npm create rayfin@latest`).
78
+ */
79
+ export declare function deriveInstallCommand(pkg: CatalogPackage): string;
80
+ /** Derive an update command for a catalog package. Agents surface this
81
+ * when the package is already installed but version-locked docs do not
82
+ * contain the requested feature.
83
+ */
84
+ export declare function deriveUpdateCommand(pkg: CatalogPackage): string;
85
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1,227 @@
1
+ import { readFileSync } from 'fs';
2
+ import { fileURLToPath } from 'url';
3
+ /**
4
+ * Read the static catalog JSON shipped inside this package's `assets/`
5
+ * directory. `import.meta.url` after compile points at `dist/catalog.js`;
6
+ * `assets/catalog.json` lives one level up at the package root.
7
+ *
8
+ * Loaded once per process and cached for the lifetime of the process.
9
+ */
10
+ let catalogCache;
11
+ function loadCatalog() {
12
+ if (catalogCache)
13
+ return catalogCache;
14
+ const path = fileURLToPath(new URL('../assets/catalog.json', import.meta.url));
15
+ const raw = readFileSync(path, 'utf8');
16
+ catalogCache = JSON.parse(raw);
17
+ return catalogCache;
18
+ }
19
+ const CATALOG_SCHEMA_VERSION = 1;
20
+ /**
21
+ * Return the static catalog as shipped by this package version. The
22
+ * returned object is the package's own data - frozen so consumers
23
+ * can't mutate the in-memory copy.
24
+ */
25
+ let frozenCatalog;
26
+ export function getCatalog() {
27
+ if (!frozenCatalog) {
28
+ const data = loadCatalog();
29
+ frozenCatalog = freezeCatalog(data);
30
+ }
31
+ return frozenCatalog;
32
+ }
33
+ /**
34
+ * Reset the in-memory catalog cache so the next `getCatalog()` re-reads
35
+ * the bundled JSON. Test-only export.
36
+ */
37
+ export function _resetCatalogForTesting() {
38
+ frozenCatalog = undefined;
39
+ catalogCache = undefined;
40
+ }
41
+ function freezeCatalog(data) {
42
+ const schemaVersion = data.schemaVersion;
43
+ if (schemaVersion !== CATALOG_SCHEMA_VERSION) {
44
+ throw new Error('Unsupported Rayfin docs catalog schema version.');
45
+ }
46
+ // Deep freeze on first read. Defensive copy of the embedded JSON so
47
+ // package consumers can't reach in and mutate the singleton.
48
+ const copy = {
49
+ schemaVersion: data.schemaVersion,
50
+ generatedAt: data.generatedAt,
51
+ packages: data.packages.map((p) => ({
52
+ ...p,
53
+ topics: [...p.topics],
54
+ modules: [...p.modules],
55
+ })),
56
+ };
57
+ Object.freeze(copy);
58
+ Object.freeze(copy.packages);
59
+ for (const p of copy.packages) {
60
+ Object.freeze(p);
61
+ Object.freeze(p.topics);
62
+ Object.freeze(p.modules);
63
+ }
64
+ return copy;
65
+ }
66
+ /**
67
+ * Rank catalog packages by query relevance. Used by CLI/MCP discover
68
+ * surfaces. Scoring (deterministic, no embedding):
69
+ *
70
+ * - **name** exact substring match: +5
71
+ * - **kind** exact match (e.g. query "sdk"): +3
72
+ * - **topic** word match: +2 per matching topic
73
+ * - **summary** word match: +1 per matching token
74
+ *
75
+ * Returns scored packages sorted descending by score; ties broken by
76
+ * alphabetical package name. Packages with score 0 are excluded.
77
+ * SDK catalog-only entries with no docs modules are also excluded so
78
+ * discover results never recommend installing an SDK package that cannot
79
+ * contribute searchable docs yet.
80
+ *
81
+ * Stop-words and tokens shorter than 3 chars are ignored to keep the
82
+ * signal-to-noise ratio high - the rare "auth" 4-char query still
83
+ * matches because tokenization is on word boundaries, but "is"/"a"
84
+ * never match.
85
+ */
86
+ export function discoverPackages(query, catalog = getCatalog()) {
87
+ const tokens = tokenize(query);
88
+ if (tokens.length === 0)
89
+ return [];
90
+ const queryLower = query.toLowerCase().trim();
91
+ const scored = [];
92
+ for (const pkg of catalog.packages) {
93
+ if (pkg.kind === 'sdk' && pkg.modules.length === 0) {
94
+ continue;
95
+ }
96
+ let score = 0;
97
+ const matchedOn = [];
98
+ // Name substring match - strongest signal
99
+ const nameLower = pkg.name.toLowerCase();
100
+ if (nameLower.includes(queryLower)) {
101
+ score += 5;
102
+ matchedOn.push('name');
103
+ }
104
+ else {
105
+ // Word-by-word match on name (e.g. query "auth fabric" matches
106
+ // `@microsoft/rayfin-auth-provider-fabric`)
107
+ for (const token of tokens) {
108
+ if (nameLower.includes(token)) {
109
+ score += 2;
110
+ if (!matchedOn.includes('name'))
111
+ matchedOn.push('name');
112
+ }
113
+ }
114
+ }
115
+ // Kind match
116
+ if (tokens.includes(pkg.kind)) {
117
+ score += 3;
118
+ matchedOn.push('kind');
119
+ }
120
+ // Topic match - strong signal because topics are curated
121
+ for (const topic of pkg.topics) {
122
+ const topicLower = topic.toLowerCase();
123
+ if (tokens.includes(topicLower)) {
124
+ score += 2;
125
+ if (!matchedOn.includes('topics'))
126
+ matchedOn.push('topics');
127
+ }
128
+ else {
129
+ // Partial topic match (substring) - weaker signal
130
+ for (const token of tokens) {
131
+ if (token.length >= 4 && topicLower.includes(token)) {
132
+ score += 1;
133
+ if (!matchedOn.includes('topics'))
134
+ matchedOn.push('topics');
135
+ }
136
+ }
137
+ }
138
+ }
139
+ // Summary word match - weakest signal
140
+ const summaryTokens = tokenize(pkg.summary);
141
+ for (const token of tokens) {
142
+ if (summaryTokens.includes(token)) {
143
+ score += 1;
144
+ if (!matchedOn.includes('summary'))
145
+ matchedOn.push('summary');
146
+ }
147
+ }
148
+ if (score > 0) {
149
+ scored.push({ package: pkg, score, matchedOn });
150
+ }
151
+ }
152
+ scored.sort((a, b) => {
153
+ if (a.score !== b.score)
154
+ return b.score - a.score;
155
+ return a.package.name.localeCompare(b.package.name);
156
+ });
157
+ return scored;
158
+ }
159
+ /** Map a {@link DiscoverScore} to the wire shape consumed by both
160
+ * CLI and MCP. Defensive copies of array fields ensure consumers
161
+ * can't mutate the catalog singleton's frozen inner arrays via the
162
+ * result. */
163
+ export function mapDiscoverResult(score) {
164
+ const item = {
165
+ name: score.package.name,
166
+ kind: score.package.kind,
167
+ summary: score.package.summary,
168
+ topics: [...score.package.topics],
169
+ installCommand: deriveInstallCommand(score.package),
170
+ updateCommand: deriveUpdateCommand(score.package),
171
+ versionLockedDocs: 'Docs are served from the package version installed in the current project. If this package is already installed but the feature is missing from search results, upgrade the package and re-run the docs query.',
172
+ score: score.score,
173
+ matchedOn: [...score.matchedOn],
174
+ };
175
+ if (score.package.homepageUrl) {
176
+ item.homepageUrl = score.package.homepageUrl;
177
+ }
178
+ return item;
179
+ }
180
+ /** Derive an install command for a catalog package. Defaults to
181
+ * `npm install <name>` unless the catalog entry specifies an
182
+ * `installCommand` override (e.g. `npm create rayfin@latest`).
183
+ */
184
+ export function deriveInstallCommand(pkg) {
185
+ if (pkg.installCommand)
186
+ return pkg.installCommand;
187
+ if (pkg.name === '@microsoft/create-rayfin') {
188
+ return 'npm create rayfin@latest';
189
+ }
190
+ return `npm install ${pkg.name}`;
191
+ }
192
+ /** Derive an update command for a catalog package. Agents surface this
193
+ * when the package is already installed but version-locked docs do not
194
+ * contain the requested feature.
195
+ */
196
+ export function deriveUpdateCommand(pkg) {
197
+ if (pkg.updateCommand)
198
+ return pkg.updateCommand;
199
+ if (pkg.name === '@microsoft/create-rayfin') {
200
+ return 'npm create rayfin@latest';
201
+ }
202
+ return `npm install ${pkg.name}@latest`;
203
+ }
204
+ const STOPWORDS = new Set([
205
+ 'and',
206
+ 'the',
207
+ 'for',
208
+ 'with',
209
+ 'how',
210
+ 'what',
211
+ 'when',
212
+ 'where',
213
+ 'this',
214
+ 'that',
215
+ 'from',
216
+ 'into',
217
+ 'onto',
218
+ 'use',
219
+ 'using',
220
+ ]);
221
+ function tokenize(input) {
222
+ return input
223
+ .toLowerCase()
224
+ .split(/[^a-z0-9]+/)
225
+ .filter((t) => t.length >= 3 && !STOPWORDS.has(t));
226
+ }
227
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1,110 @@
1
+ import type { DocKind, RayfinDocsManifest } from './types.js';
2
+ export type { DocKind } from './types.js';
3
+ /**
4
+ * A package discovered to declare `rayfinDocs`. Returned by
5
+ * {@link discoverRayfinDocsPackages} for {@link DocsService} to load.
6
+ */
7
+ export interface DiscoveredPackage {
8
+ packageName: string;
9
+ packageVersion: string;
10
+ packageRoot: string;
11
+ manifest: RayfinDocsManifest;
12
+ }
13
+ /**
14
+ * Function deciding whether a candidate package should be considered
15
+ * trusted enough to discover. The default ({@link defaultTrust}) accepts
16
+ * only `@microsoft/rayfin-*` packages. Tests override this.
17
+ */
18
+ export type TrustPredicate = (packageName: string) => boolean;
19
+ /** Default trust predicate. Auto-trusts the Microsoft Rayfin namespace. */
20
+ export declare const defaultTrust: TrustPredicate;
21
+ /**
22
+ * Inputs to {@link discoverRayfinDocsPackages}. Callers must choose exactly one
23
+ * discovery source: `candidates` to probe a fixed catalog list,
24
+ * `packageRoots` for explicit workspace package folders, or
25
+ * `scanInstalledPackages: true` to walk all packages under ancestor
26
+ * `node_modules` directories.
27
+ */
28
+ export interface DiscoveryOptions {
29
+ /**
30
+ * Module identifier or directory used as the resolution base. The
31
+ * walker calls `createRequire(from).resolve('<pkg>/package.json')`
32
+ * to locate each candidate. Pass `import.meta.url` from the consuming
33
+ * module, or a directory path that exists in the project.
34
+ */
35
+ from: string;
36
+ /**
37
+ * Optional candidate package names to probe for `rayfinDocs`.
38
+ * An empty array is still an explicit source and returns no packages.
39
+ */
40
+ candidates?: readonly string[];
41
+ /**
42
+ * Optional explicit package roots to inspect. Used by in-repo tooling such
43
+ * as the Docusaurus site where package docs are read directly from workspace
44
+ * package folders instead of an installed `node_modules` tree. An empty
45
+ * array is still an explicit source and returns no packages.
46
+ */
47
+ packageRoots?: readonly string[];
48
+ /**
49
+ * Explicit opt-in for scanning every installed package under the nearest
50
+ * `node_modules` chain. Prefer `candidates` for CLI/MCP agent paths so
51
+ * discovery stays bounded to the Rayfin package catalog.
52
+ */
53
+ scanInstalledPackages?: boolean;
54
+ /** Trust predicate; defaults to {@link defaultTrust}. */
55
+ trust?: TrustPredicate;
56
+ }
57
+ /**
58
+ * Returns whether callers already selected a discovery source.
59
+ * Wrappers use this to decide whether to inject their own bounded defaults.
60
+ */
61
+ export declare function hasExplicitDiscoverySource(options: DiscoveryOptions): boolean;
62
+ /**
63
+ * Resolve each candidate package's `package.json`, validate the
64
+ * `rayfinDocs` field, and return discovered packages.
65
+ *
66
+ * Untrusted packages (per {@link TrustPredicate}) are skipped with a
67
+ * structured `untrustedSkipped` entry so callers can surface the skip.
68
+ * Packages that fail manifest validation produce a structured
69
+ * `invalidManifest` entry rather than throwing - discovery is
70
+ * defensive: a single broken package shouldn't crash the indexer.
71
+ */
72
+ export interface DiscoveryResult {
73
+ discovered: DiscoveredPackage[];
74
+ notInstalled: string[];
75
+ untrustedSkipped: string[];
76
+ invalidManifest: Array<{
77
+ packageName: string;
78
+ reason: string;
79
+ }>;
80
+ }
81
+ export declare function discoverRayfinDocsPackages(options: DiscoveryOptions): DiscoveryResult;
82
+ type ManifestValidation = {
83
+ ok: true;
84
+ manifest: RayfinDocsManifest;
85
+ } | {
86
+ ok: false;
87
+ kind: 'missing';
88
+ } | {
89
+ ok: false;
90
+ kind: 'invalid';
91
+ reason: string;
92
+ };
93
+ /**
94
+ * Validate the `rayfinDocs` field on a parsed `package.json`. Returns
95
+ * a discriminated result so callers can distinguish "no manifest"
96
+ * (silently skip) from "broken manifest" (surface as warning).
97
+ *
98
+ * Path validation rejects absolute paths and parent-directory
99
+ * traversal in `dir` - discovered packages must keep their docs
100
+ * inside their own root.
101
+ */
102
+ export declare function validateRayfinDocsManifest(pkgJson: unknown, packageName: string): ManifestValidation;
103
+ /**
104
+ * Map a `DocKind` to the legacy `DocModule` value used throughout the
105
+ * existing CLI/MCP surfaces. Phase 2 keeps the `DocModule` union for
106
+ * back-compat; `--module ts-sdk` continues to mean "all api-reference
107
+ * docs" for end users.
108
+ */
109
+ export declare function docKindToModule(kind: DocKind): 'guide' | 'host' | 'ts-sdk';
110
+ //# sourceMappingURL=discovery.d.ts.map