@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 +21 -0
- package/assets/catalog.json +132 -0
- package/dist/_internal/build-index.d.ts +14 -0
- package/dist/_internal/build-index.js +13 -0
- package/dist/catalog-types.d.ts +52 -0
- package/dist/catalog-types.js +21 -0
- package/dist/catalog.d.ts +85 -0
- package/dist/catalog.js +227 -0
- package/dist/discovery.d.ts +110 -0
- package/dist/discovery.js +402 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +422 -0
- package/dist/loader.d.ts +21 -0
- package/dist/loader.js +296 -0
- package/dist/search.d.ts +72 -0
- package/dist/search.js +254 -0
- package/dist/site-cjs/discovery.js +409 -0
- package/dist/site-cjs/package.json +1 -0
- package/dist/site-cjs/types.js +2 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.js +2 -0
- package/package.json +62 -0
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
|
package/dist/catalog.js
ADDED
|
@@ -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
|