okf-search-native 0.3.4 → 0.5.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/README.md CHANGED
@@ -1,13 +1,9 @@
1
1
  # `okf-search-native`
2
2
 
3
3
  Search [Open Knowledge Format (OKF)](https://github.com/GoogleCloudPlatform/open-knowledge-format)
4
- collections at native speed from Node.js. `okf-search-native` builds an in-memory
5
- index with Rust and Tantivy and returns the best matching section from each
6
- document.
7
-
8
- Use the package root for Markdown files or strings. Most users should start
9
- there. Use `okf-search-native/prepared` only when your application already
10
- produces prepared OKF documents.
4
+ Markdown collections at native speed from Node.js, powered by Rust and Tantivy.
5
+ Get the best matching section from each document, with its source path, line
6
+ numbers, and snippet.
11
7
 
12
8
  ## Install
13
9
 
@@ -15,138 +11,174 @@ produces prepared OKF documents.
15
11
  npm install okf-search-native
16
12
  ```
17
13
 
18
- The package requires Node.js `>=22.19.0` and includes TypeScript declarations.
19
- See [Requirements and tested platforms](#requirements-and-tested-platforms) for
20
- the available native artifacts.
14
+ Requires Node.js `>=22.19.0`. Includes TypeScript declarations and native
15
+ binaries for macOS x64/arm64 and Linux x64 (glibc >= 2.17); Windows x64 is
16
+ experimental. Browsers and Alpine/musl are not supported.
17
+ See the [full platform list](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/API.md#requirements-and-tested-platforms).
21
18
 
22
- ## Raw Markdown API
19
+ ## Search a collection
23
20
 
24
- `createOkfSearch(documents)` synchronously indexes Markdown already in memory.
25
- `openOkf(root)` recursively reads lowercase `.md` files from a Node.js
26
- directory. Files named exactly `index.md` or `log.md` are reserved and are not
27
- indexed.
21
+ Given a directory of OKF Markdown files at `./knowledge`:
28
22
 
29
23
  ```js
30
- import {
31
- createOkfSearch,
32
- openOkf,
33
- validateOkfDocument,
34
- } from "okf-search-native";
35
-
36
- const document = {
37
- path: "notes/memory.md",
38
- markdown: "---\ntype: note\n---\nMemory safety matters.\n",
39
- };
24
+ import { openOkf } from "okf-search-native";
40
25
 
41
- const validation = validateOkfDocument(document);
42
- const index = createOkfSearch([document]);
43
- const hits = index.search("memory", { limit: 10, fields: ["body"] });
26
+ const index = await openOkf("./knowledge");
27
+ const hits = index.search("rollback deployment");
44
28
 
45
- const directoryIndex = await openOkf("./knowledge");
46
- directoryIndex.ingest({
47
- path: "notes/new.md",
48
- markdown: "---\ntype: note\n---\nNew material.\n",
49
- });
50
- directoryIndex.remove("notes/new.md");
29
+ for (const hit of hits) {
30
+ console.log(hit.path, hit.headingPath, hit.snippet);
31
+ }
51
32
  ```
52
33
 
53
- Both constructors return an in-memory search handle. `ingest` adds or replaces
54
- one document after successful validation. `remove` changes only the current
55
- index, not its source file. Reopening a directory rebuilds the index from the
56
- files on disk.
34
+ To try this with one document, save the following as
35
+ `knowledge/runbooks/deployment.md` before running the example:
57
36
 
58
- ### Search behavior
37
+ ```markdown
38
+ ---
39
+ type: runbook
40
+ ---
41
+ # Deployment
59
42
 
60
- Search supports any or all term matching, field selection and boosts, fuzzy
61
- matching, final-term prefix matching, and filters for OKF type, tags, status,
62
- trust tier, staleness, and conformance.
43
+ ## Rollback
63
44
 
64
- Results contain at most one hit per document. Each hit represents its
65
- highest-ranked matching section and includes the document path, heading path,
66
- line range, matched fields, and snippet. The handle also provides `listTypes()`
67
- and `listDegradedDocuments()` for inspecting the current collection.
45
+ To rollback a deployment, restore the previous release and check service health.
46
+ ```
68
47
 
69
- ### Validation
48
+ The result points to the rollback section (selected fields shown):
70
49
 
71
- `validateOkfDocument` checks one Markdown document without changing an index.
72
- A strict document is valid and indexable. A degraded document remains indexable
73
- and searchable, with diagnostics describing fields that need repair. A document
74
- with a fatal path, parsing, Markdown, or `type` problem is not indexable.
75
- Expected validation failures are returned as diagnostics rather than thrown.
50
+ ```js
51
+ {
52
+ path: "runbooks/deployment.md",
53
+ headingPath: "Deployment > Rollback",
54
+ startLine: 6,
55
+ endLine: 8,
56
+ snippet: "To rollback a deployment, restore the previous release and check service health."
57
+ }
58
+ ```
76
59
 
77
- See the [OKF v0.2 specification](https://github.com/GoogleCloudPlatform/open-knowledge-format/blob/ad30107c31c06aec8a7d5636e0d1058118604e6f/SPEC.md)
78
- for the document format and field semantics.
60
+ Use the path and line numbers to open the source, and the heading and snippet
61
+ to display a preview. Results contain at most one hit per document, ordered by
62
+ relevance. See the [complete result shape](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/API.md#results).
79
63
 
80
- ### Differences from `okf-minisearch`
64
+ **Open once and reuse the handle.** Opening reads and indexes the collection
65
+ into memory; every new `openOkf` call rebuilds it. The handle does not watch
66
+ files, write changes to disk, or persist the index. Reopen to pick up filesystem
67
+ changes.
81
68
 
82
- The native backend uses Tantivy, so its ranking, scores, snippets, and fuzzy
83
- candidates can differ from `okf-minisearch`. Browser use is not supported.
84
- `autoSuggest` is also unsupported and throws an `OkfError` with code
85
- `ERR_OKF_UNSUPPORTED`.
69
+ `openOkf` recursively reads lowercase `.md` files, excluding files named exactly
70
+ `index.md` or `log.md`.
86
71
 
87
- ## Prepared API
72
+ ## Already have Markdown strings?
88
73
 
89
- Most users can skip this section. Use the prepared API when another part of
90
- your application already produces `PreparedDocument` values and you want to
91
- pass them directly to the native backend.
74
+ Use `createOkfSearch` instead of reading a directory. It builds the same kind
75
+ of handle synchronously:
92
76
 
93
77
  ```js
94
- import { NativeOkfSearch } from "okf-search-native/prepared";
78
+ import { createOkfSearch } from "okf-search-native";
95
79
 
96
- const index = NativeOkfSearch.fromPrepared(preparedDocuments);
97
- const hits = index.search("memory", { limit: 10, fields: ["body"] });
98
- index.ingestPrepared(preparedDocument);
99
- index.removeDocument("docs/old");
80
+ const index = createOkfSearch([{
81
+ path: "runbooks/deployment.md",
82
+ markdown: "---\ntype: runbook\n---\nTo rollback a deployment, restore the previous release.\n",
83
+ }]);
84
+
85
+ const hits = index.search("rollback deployment");
100
86
  ```
101
87
 
102
- `fromPrepared` builds an index from prepared documents. `ingestPrepared`
103
- replaces every indexed section owned by one document, and `removeDocument`
104
- removes them together. `PreparedDocument` contains document-wide metadata once;
105
- each `PreparedSection` contains only its ID, heading path, text, and line
106
- bounds. The DTO declarations are exported from `okf-search-native/prepared`,
107
- not from the package root.
88
+ ## Refine a search
89
+
90
+ Require all query terms and restrict results to runbooks:
108
91
 
109
- ## Requirements and tested platforms
92
+ ```js
93
+ index.search("rollback deployment", {
94
+ match: "all",
95
+ where: { types: ["runbook"] },
96
+ });
97
+ ```
98
+
99
+ Enable typo tolerance:
110
100
 
111
- Linux x64 and macOS x64/arm64 are fully supported. Windows x64 is experimental.
112
- All targets require Node.js `>=22.19.0` and use Node-API 8.
101
+ ```js
102
+ index.search("deploymnt", { fuzzy: true });
103
+ ```
113
104
 
114
- | Platform | Native artifact |
115
- | --- | --- |
116
- | macOS x64 | `okf-search-native.darwin-x64.node` |
117
- | macOS arm64 | `okf-search-native.darwin-arm64.node` |
118
- | Windows x64 (MSVC) | `okf-search-native.win32-x64-msvc.node` |
119
- | Linux x64 (glibc >= 2.17) | `okf-search-native.linux-x64-gnu.node` |
105
+ By default, searches return up to ten documents, match any query term across
106
+ all searchable fields, and disable fuzzy matching. The final term still
107
+ matches prefixes when it has at least three characters: `"deploy"` can match
108
+ `"deployment"`, even with `fuzzy: false`.
120
109
 
121
- Linux musl/Alpine, Linux arm64, Windows arm64, Bun, Deno, browsers, and other
122
- Node versions are not covered by this matrix.
110
+ Use `limit` to change the result count and `fields` to restrict where terms
111
+ match. Filters also support tags, status, trust tier, staleness, and conformance.
112
+ See [search options and defaults](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/API.md#search)
113
+ for field boosts, filter combinations, and detailed matching rules.
123
114
 
124
- ## Development
115
+ ## Update the in-memory index
125
116
 
126
- Development requires Rust `1.88.0`:
117
+ `ingest` adds a document or replaces the document with the same path. `remove`
118
+ returns whether the document was present. Neither operation changes files:
127
119
 
128
- ```sh
129
- pnpm install
130
- pnpm --filter okf-search-native run build
131
- pnpm --filter okf-search-native run check:rust
132
- pnpm --filter okf-search-native run test
120
+ ```js
121
+ index.ingest({
122
+ path: "runbooks/restart.md",
123
+ markdown: "---\ntype: runbook\n---\nRestart the service after draining active requests.\n",
124
+ });
125
+
126
+ index.remove("runbooks/restart.md");
127
+ ```
128
+
129
+ Use relative `.md` paths, such as `runbooks/restart.md`. If preparation of a
130
+ replacement fails, the existing document remains searchable.
131
+ See [update results and path rules](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/API.md#update-and-reuse-the-handle).
132
+
133
+ ## Check documents and handle failures
134
+
135
+ Documents with valid OKF metadata are **strict**. Some metadata problems make
136
+ a document **degraded**: it remains searchable, with diagnostics explaining
137
+ what needs repair. Fatal problems, such as missing required `type` metadata,
138
+ prevent indexing.
139
+
140
+ Constructors and `ingest` validate automatically. To inspect diagnostics before
141
+ indexing, use `validateOkfDocument`:
142
+
143
+ ```js
144
+ import { validateOkfDocument } from "okf-search-native";
145
+
146
+ const input = {
147
+ path: "runbooks/draft.md",
148
+ markdown: "---\ntype: runbook\nstatus: not-a-status\n---\nDraft deployment instructions.\n",
149
+ };
150
+ const validation = validateOkfDocument(input);
151
+
152
+ for (const { path, field, message } of validation.errors) {
153
+ console.warn(path, field, message);
154
+ }
155
+
156
+ if (validation.isIndexable) {
157
+ index.ingest(input); // Degraded documents can still be indexed.
158
+ }
133
159
  ```
134
160
 
135
- ### Build output
161
+ Validation returns expected document problems as diagnostics. Indexing rejects
162
+ fatal document problems with `OkfError`; `openOkf` also rejects unreadable
163
+ files. Invalid search options throw `TypeError`. An `ERR_OKF_INDEX_UNUSABLE`
164
+ error means the handle must be rebuilt, not retried.
165
+ See [validation outcomes and error handling](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/API.md#validation-and-failures).
166
+
167
+ To inspect an existing collection:
136
168
 
137
- `napi build` generates `native.cjs`, `native.d.cts`, and the host `.node`
138
- artifact. The package facade build writes `dist/index.cjs`, `dist/index.mjs`,
139
- `dist/index.d.cts`, `dist/index.d.mts`, and `dist/index.d.ts`. Generated native
140
- loader names are internal and are not package-root exports.
169
+ ```js
170
+ console.log(index.indexStats().logical.documents.total);
171
+ console.log(index.listTypes());
172
+ console.log(index.listDegradedDocuments());
173
+ ```
141
174
 
142
- ### Release artifacts
175
+ ## Reference and development
143
176
 
144
- For multi-target candidate assembly, copy the four tested `.node` files into
145
- the package root, then run `pnpm run verify:release-artifacts`. The verifier
146
- derives the required artifact names from the checked-in target list and
147
- rejects missing or extra native files. CI also uses its `glibc <artifact>` mode
148
- to reject Linux addons that import symbols newer than `GLIBC_2.17`.
177
+ - [API reference](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/API.md): options, return values, errors, and index statistics.
178
+ - [Prepared API](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/API.md#advanced-prepared-api): for applications that already produce prepared documents.
179
+ - [Backend differences](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/API.md#backend-differences): Tantivy ranking differs from `okf-minisearch`; `autoSuggest` is unsupported.
180
+ - [Development](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/DEVELOPMENT.md): local builds, tests, and release artifacts.
149
181
 
150
182
  ## License
151
183
 
152
- [MIT](../../LICENSE)
184
+ [MIT](https://github.com/robhowley/okf-search/blob/main/packages/okf-search-native/LICENSE)