okf-search-native 0.3.4 → 0.4.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
@@ -41,6 +41,7 @@ const document = {
41
41
  const validation = validateOkfDocument(document);
42
42
  const index = createOkfSearch([document]);
43
43
  const hits = index.search("memory", { limit: 10, fields: ["body"] });
44
+ const stats = index.indexStats();
44
45
 
45
46
  const directoryIndex = await openOkf("./knowledge");
46
47
  directoryIndex.ingest({
@@ -66,6 +67,48 @@ highest-ranked matching section and includes the document path, heading path,
66
67
  line range, matched fields, and snippet. The handle also provides `listTypes()`
67
68
  and `listDegradedDocuments()` for inspecting the current collection.
68
69
 
70
+ ### Index statistics
71
+
72
+ `indexStats()` returns a detached, recursively frozen snapshot:
73
+
74
+ ```ts
75
+ {
76
+ logical: {
77
+ documents: {
78
+ total: number;
79
+ strict: number;
80
+ degraded: number;
81
+ };
82
+ types: readonly {
83
+ type: string;
84
+ documentCount: number;
85
+ }[];
86
+ statuses: {
87
+ draft: number;
88
+ stable: number;
89
+ deprecated: number;
90
+ unclassified: number;
91
+ };
92
+ trustTiers: {
93
+ unverified: number;
94
+ machineConfirmed: number;
95
+ humanReviewed: number;
96
+ unclassified: number;
97
+ };
98
+ };
99
+ storage: {
100
+ kind: "in-memory-index-files";
101
+ sizeInBytes: number;
102
+ };
103
+ }
104
+ ```
105
+
106
+ Logical values count documents, not sections, and change only after a successful
107
+ `ingest` or `remove`. `types` preserves case and is sorted by type. Missing
108
+ effective status or trust-tier metadata counts as `unclassified`.
109
+ `sizeInBytes` samples the handle's Tantivy `RamDirectory`; it excludes other
110
+ process memory and can change without a logical change.
111
+
69
112
  ### Validation
70
113
 
71
114
  `validateOkfDocument` checks one Markdown document without changing an index.
@@ -95,6 +138,7 @@ import { NativeOkfSearch } from "okf-search-native/prepared";
95
138
 
96
139
  const index = NativeOkfSearch.fromPrepared(preparedDocuments);
97
140
  const hits = index.search("memory", { limit: 10, fields: ["body"] });
141
+ const stats = index.indexStats();
98
142
  index.ingestPrepared(preparedDocument);
99
143
  index.removeDocument("docs/old");
100
144
  ```
@@ -104,7 +148,8 @@ replaces every indexed section owned by one document, and `removeDocument`
104
148
  removes them together. `PreparedDocument` contains document-wide metadata once;
105
149
  each `PreparedSection` contains only its ID, heading path, text, and line
106
150
  bounds. The DTO declarations are exported from `okf-search-native/prepared`,
107
- not from the package root.
151
+ not from the package root. Its `indexStats()` result has the shape above but is
152
+ a mutable N-API DTO; the package-root adapter returns the frozen copy.
108
153
 
109
154
  ## Requirements and tested platforms
110
155
 
package/dist/index.cjs CHANGED
@@ -15541,6 +15541,10 @@ function createOkfSearch(documents) {
15541
15541
  }
15542
15542
  };
15543
15543
  return {
15544
+ indexStats() {
15545
+ assertUsable();
15546
+ return copyIndexStats(callNative("<index>", () => native.indexStats()));
15547
+ },
15544
15548
  ingest(input) {
15545
15549
  assertUsable();
15546
15550
  let result;
@@ -15639,6 +15643,36 @@ function copyNonEmptyDiagnostics(diagnostics) {
15639
15643
  }
15640
15644
  return [first, ...rest];
15641
15645
  }
15646
+ function copyIndexStats(stats) {
15647
+ const types = Object.freeze(
15648
+ stats.logical.types.map(({ type, documentCount }) => Object.freeze({ type, documentCount })).sort((left, right) => compare(left.type, right.type))
15649
+ );
15650
+ const logical = Object.freeze({
15651
+ documents: Object.freeze({
15652
+ total: stats.logical.documents.total,
15653
+ strict: stats.logical.documents.strict,
15654
+ degraded: stats.logical.documents.degraded
15655
+ }),
15656
+ types,
15657
+ statuses: Object.freeze({
15658
+ draft: stats.logical.statuses.draft,
15659
+ stable: stats.logical.statuses.stable,
15660
+ deprecated: stats.logical.statuses.deprecated,
15661
+ unclassified: stats.logical.statuses.unclassified
15662
+ }),
15663
+ trustTiers: Object.freeze({
15664
+ unverified: stats.logical.trustTiers.unverified,
15665
+ machineConfirmed: stats.logical.trustTiers.machineConfirmed,
15666
+ humanReviewed: stats.logical.trustTiers.humanReviewed,
15667
+ unclassified: stats.logical.trustTiers.unclassified
15668
+ })
15669
+ });
15670
+ const storage = Object.freeze({
15671
+ kind: "in-memory-index-files",
15672
+ sizeInBytes: stats.storage.sizeInBytes
15673
+ });
15674
+ return Object.freeze({ logical, storage });
15675
+ }
15642
15676
  function copySearchHit(hit) {
15643
15677
  return {
15644
15678
  documentId: hit.documentId,
package/dist/index.d.cts CHANGED
@@ -89,6 +89,41 @@ interface OkfDegradedDocument {
89
89
  readonly path: string;
90
90
  readonly diagnostics: readonly [OkfDiagnostic, ...OkfDiagnostic[]];
91
91
  }
92
+ interface OkfLogicalIndexStats {
93
+ readonly documents: {
94
+ readonly total: number;
95
+ readonly strict: number;
96
+ readonly degraded: number;
97
+ };
98
+ readonly types: readonly {
99
+ readonly type: string;
100
+ readonly documentCount: number;
101
+ }[];
102
+ readonly statuses: {
103
+ readonly draft: number;
104
+ readonly stable: number;
105
+ readonly deprecated: number;
106
+ readonly unclassified: number;
107
+ };
108
+ readonly trustTiers: {
109
+ readonly unverified: number;
110
+ readonly machineConfirmed: number;
111
+ readonly humanReviewed: number;
112
+ readonly unclassified: number;
113
+ };
114
+ }
115
+ type OkfIndexStorageStats = {
116
+ readonly kind: "in-memory-index-files";
117
+ readonly sizeInBytes: number;
118
+ } | {
119
+ readonly kind: "serialized-index";
120
+ readonly format: "minisearch-json-utf8";
121
+ readonly sizeInBytes: number;
122
+ };
123
+ interface OkfIndexStats {
124
+ readonly logical: OkfLogicalIndexStats;
125
+ readonly storage: OkfIndexStorageStats;
126
+ }
92
127
  type OkfConformance = "strict" | "degraded";
93
128
  type OkfIngestResult = {
94
129
  readonly conformance: "strict";
@@ -127,6 +162,7 @@ interface OkfSearchHit {
127
162
  snippet: string;
128
163
  }
129
164
  interface OkfSearch {
165
+ indexStats(): OkfIndexStats;
130
166
  ingest(input: OkfDocumentInput): OkfIngestResult;
131
167
  listDegradedDocuments(): readonly OkfDegradedDocument[];
132
168
  listTypes(): readonly string[];
@@ -153,4 +189,4 @@ declare function openOkf(root: string): Promise<OkfSearch>;
153
189
  declare function validateOkfDocument(input: OkfDocumentInput): OkfValidationResult;
154
190
 
155
191
  export { OkfError, createOkfSearch, openOkf, validateOkfDocument };
156
- export type { IsoDateTime, OkfAttester, OkfConformance, OkfDegradedDocument, OkfDiagnostic, OkfDiagnosticCode, OkfDocument, OkfDocumentInput, OkfErrorCode, OkfExecutor, OkfGeneration, OkfIngestResult, OkfParameter, OkfSearch, OkfSearchField, OkfSearchHit, OkfSearchOptions, OkfSource, OkfStatus, OkfTimeWindow, OkfTrustTier, OkfValidationResult, OkfVerification };
192
+ export type { IsoDateTime, OkfAttester, OkfConformance, OkfDegradedDocument, OkfDiagnostic, OkfDiagnosticCode, OkfDocument, OkfDocumentInput, OkfErrorCode, OkfExecutor, OkfGeneration, OkfIndexStats, OkfIndexStorageStats, OkfIngestResult, OkfLogicalIndexStats, OkfParameter, OkfSearch, OkfSearchField, OkfSearchHit, OkfSearchOptions, OkfSource, OkfStatus, OkfTimeWindow, OkfTrustTier, OkfValidationResult, OkfVerification };
package/dist/index.d.mts CHANGED
@@ -89,6 +89,41 @@ interface OkfDegradedDocument {
89
89
  readonly path: string;
90
90
  readonly diagnostics: readonly [OkfDiagnostic, ...OkfDiagnostic[]];
91
91
  }
92
+ interface OkfLogicalIndexStats {
93
+ readonly documents: {
94
+ readonly total: number;
95
+ readonly strict: number;
96
+ readonly degraded: number;
97
+ };
98
+ readonly types: readonly {
99
+ readonly type: string;
100
+ readonly documentCount: number;
101
+ }[];
102
+ readonly statuses: {
103
+ readonly draft: number;
104
+ readonly stable: number;
105
+ readonly deprecated: number;
106
+ readonly unclassified: number;
107
+ };
108
+ readonly trustTiers: {
109
+ readonly unverified: number;
110
+ readonly machineConfirmed: number;
111
+ readonly humanReviewed: number;
112
+ readonly unclassified: number;
113
+ };
114
+ }
115
+ type OkfIndexStorageStats = {
116
+ readonly kind: "in-memory-index-files";
117
+ readonly sizeInBytes: number;
118
+ } | {
119
+ readonly kind: "serialized-index";
120
+ readonly format: "minisearch-json-utf8";
121
+ readonly sizeInBytes: number;
122
+ };
123
+ interface OkfIndexStats {
124
+ readonly logical: OkfLogicalIndexStats;
125
+ readonly storage: OkfIndexStorageStats;
126
+ }
92
127
  type OkfConformance = "strict" | "degraded";
93
128
  type OkfIngestResult = {
94
129
  readonly conformance: "strict";
@@ -127,6 +162,7 @@ interface OkfSearchHit {
127
162
  snippet: string;
128
163
  }
129
164
  interface OkfSearch {
165
+ indexStats(): OkfIndexStats;
130
166
  ingest(input: OkfDocumentInput): OkfIngestResult;
131
167
  listDegradedDocuments(): readonly OkfDegradedDocument[];
132
168
  listTypes(): readonly string[];
@@ -153,4 +189,4 @@ declare function openOkf(root: string): Promise<OkfSearch>;
153
189
  declare function validateOkfDocument(input: OkfDocumentInput): OkfValidationResult;
154
190
 
155
191
  export { OkfError, createOkfSearch, openOkf, validateOkfDocument };
156
- export type { IsoDateTime, OkfAttester, OkfConformance, OkfDegradedDocument, OkfDiagnostic, OkfDiagnosticCode, OkfDocument, OkfDocumentInput, OkfErrorCode, OkfExecutor, OkfGeneration, OkfIngestResult, OkfParameter, OkfSearch, OkfSearchField, OkfSearchHit, OkfSearchOptions, OkfSource, OkfStatus, OkfTimeWindow, OkfTrustTier, OkfValidationResult, OkfVerification };
192
+ export type { IsoDateTime, OkfAttester, OkfConformance, OkfDegradedDocument, OkfDiagnostic, OkfDiagnosticCode, OkfDocument, OkfDocumentInput, OkfErrorCode, OkfExecutor, OkfGeneration, OkfIndexStats, OkfIndexStorageStats, OkfIngestResult, OkfLogicalIndexStats, OkfParameter, OkfSearch, OkfSearchField, OkfSearchHit, OkfSearchOptions, OkfSource, OkfStatus, OkfTimeWindow, OkfTrustTier, OkfValidationResult, OkfVerification };
package/dist/index.d.ts CHANGED
@@ -89,6 +89,41 @@ interface OkfDegradedDocument {
89
89
  readonly path: string;
90
90
  readonly diagnostics: readonly [OkfDiagnostic, ...OkfDiagnostic[]];
91
91
  }
92
+ interface OkfLogicalIndexStats {
93
+ readonly documents: {
94
+ readonly total: number;
95
+ readonly strict: number;
96
+ readonly degraded: number;
97
+ };
98
+ readonly types: readonly {
99
+ readonly type: string;
100
+ readonly documentCount: number;
101
+ }[];
102
+ readonly statuses: {
103
+ readonly draft: number;
104
+ readonly stable: number;
105
+ readonly deprecated: number;
106
+ readonly unclassified: number;
107
+ };
108
+ readonly trustTiers: {
109
+ readonly unverified: number;
110
+ readonly machineConfirmed: number;
111
+ readonly humanReviewed: number;
112
+ readonly unclassified: number;
113
+ };
114
+ }
115
+ type OkfIndexStorageStats = {
116
+ readonly kind: "in-memory-index-files";
117
+ readonly sizeInBytes: number;
118
+ } | {
119
+ readonly kind: "serialized-index";
120
+ readonly format: "minisearch-json-utf8";
121
+ readonly sizeInBytes: number;
122
+ };
123
+ interface OkfIndexStats {
124
+ readonly logical: OkfLogicalIndexStats;
125
+ readonly storage: OkfIndexStorageStats;
126
+ }
92
127
  type OkfConformance = "strict" | "degraded";
93
128
  type OkfIngestResult = {
94
129
  readonly conformance: "strict";
@@ -127,6 +162,7 @@ interface OkfSearchHit {
127
162
  snippet: string;
128
163
  }
129
164
  interface OkfSearch {
165
+ indexStats(): OkfIndexStats;
130
166
  ingest(input: OkfDocumentInput): OkfIngestResult;
131
167
  listDegradedDocuments(): readonly OkfDegradedDocument[];
132
168
  listTypes(): readonly string[];
@@ -153,4 +189,4 @@ declare function openOkf(root: string): Promise<OkfSearch>;
153
189
  declare function validateOkfDocument(input: OkfDocumentInput): OkfValidationResult;
154
190
 
155
191
  export { OkfError, createOkfSearch, openOkf, validateOkfDocument };
156
- export type { IsoDateTime, OkfAttester, OkfConformance, OkfDegradedDocument, OkfDiagnostic, OkfDiagnosticCode, OkfDocument, OkfDocumentInput, OkfErrorCode, OkfExecutor, OkfGeneration, OkfIngestResult, OkfParameter, OkfSearch, OkfSearchField, OkfSearchHit, OkfSearchOptions, OkfSource, OkfStatus, OkfTimeWindow, OkfTrustTier, OkfValidationResult, OkfVerification };
192
+ export type { IsoDateTime, OkfAttester, OkfConformance, OkfDegradedDocument, OkfDiagnostic, OkfDiagnosticCode, OkfDocument, OkfDocumentInput, OkfErrorCode, OkfExecutor, OkfGeneration, OkfIndexStats, OkfIndexStorageStats, OkfIngestResult, OkfLogicalIndexStats, OkfParameter, OkfSearch, OkfSearchField, OkfSearchHit, OkfSearchOptions, OkfSource, OkfStatus, OkfTimeWindow, OkfTrustTier, OkfValidationResult, OkfVerification };
package/dist/index.mjs CHANGED
@@ -15537,6 +15537,10 @@ function createOkfSearch(documents) {
15537
15537
  }
15538
15538
  };
15539
15539
  return {
15540
+ indexStats() {
15541
+ assertUsable();
15542
+ return copyIndexStats(callNative("<index>", () => native.indexStats()));
15543
+ },
15540
15544
  ingest(input) {
15541
15545
  assertUsable();
15542
15546
  let result;
@@ -15635,6 +15639,36 @@ function copyNonEmptyDiagnostics(diagnostics) {
15635
15639
  }
15636
15640
  return [first, ...rest];
15637
15641
  }
15642
+ function copyIndexStats(stats) {
15643
+ const types = Object.freeze(
15644
+ stats.logical.types.map(({ type, documentCount }) => Object.freeze({ type, documentCount })).sort((left, right) => compare(left.type, right.type))
15645
+ );
15646
+ const logical = Object.freeze({
15647
+ documents: Object.freeze({
15648
+ total: stats.logical.documents.total,
15649
+ strict: stats.logical.documents.strict,
15650
+ degraded: stats.logical.documents.degraded
15651
+ }),
15652
+ types,
15653
+ statuses: Object.freeze({
15654
+ draft: stats.logical.statuses.draft,
15655
+ stable: stats.logical.statuses.stable,
15656
+ deprecated: stats.logical.statuses.deprecated,
15657
+ unclassified: stats.logical.statuses.unclassified
15658
+ }),
15659
+ trustTiers: Object.freeze({
15660
+ unverified: stats.logical.trustTiers.unverified,
15661
+ machineConfirmed: stats.logical.trustTiers.machineConfirmed,
15662
+ humanReviewed: stats.logical.trustTiers.humanReviewed,
15663
+ unclassified: stats.logical.trustTiers.unclassified
15664
+ })
15665
+ });
15666
+ const storage = Object.freeze({
15667
+ kind: "in-memory-index-files",
15668
+ sizeInBytes: stats.storage.sizeInBytes
15669
+ });
15670
+ return Object.freeze({ logical, storage });
15671
+ }
15638
15672
  function copySearchHit(hit) {
15639
15673
  return {
15640
15674
  documentId: hit.documentId,
package/native.d.cts CHANGED
@@ -10,6 +10,7 @@ export declare class NativeOkfSearch {
10
10
  ingestPrepared(document: PreparedDocument): void
11
11
  removeDocument(documentId: string): boolean
12
12
  search(query: string, options?: SearchOptions | undefined | null): Array<SearchHit>
13
+ indexStats(): IndexStats
13
14
  listTypes(): Array<string>
14
15
  listDegradedDocuments(): Array<DegradedDocument>
15
16
  /**
@@ -34,6 +35,48 @@ export interface Diagnostic {
34
35
  path: string
35
36
  }
36
37
 
38
+ export interface IndexDocumentStats {
39
+ total: number
40
+ strict: number
41
+ degraded: number
42
+ }
43
+
44
+ export interface IndexStats {
45
+ logical: LogicalIndexStats
46
+ storage: IndexStorageStats
47
+ }
48
+
49
+ export interface IndexStatusStats {
50
+ draft: number
51
+ stable: number
52
+ deprecated: number
53
+ unclassified: number
54
+ }
55
+
56
+ export interface IndexStorageStats {
57
+ kind: "in-memory-index-files"
58
+ sizeInBytes: number
59
+ }
60
+
61
+ export interface IndexTrustTierStats {
62
+ unverified: number
63
+ machineConfirmed: number
64
+ humanReviewed: number
65
+ unclassified: number
66
+ }
67
+
68
+ export interface IndexTypeStats {
69
+ type: string
70
+ documentCount: number
71
+ }
72
+
73
+ export interface LogicalIndexStats {
74
+ documents: IndexDocumentStats
75
+ types: Array<IndexTypeStats>
76
+ statuses: IndexStatusStats
77
+ trustTiers: IndexTrustTierStats
78
+ }
79
+
37
80
  export interface PreparedDocument {
38
81
  documentId: string
39
82
  path: string
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okf-search-native",
3
- "version": "0.3.4",
3
+ "version": "0.4.0",
4
4
  "description": "Search Open Knowledge Format collections at native speed with a lean Rust and Tantivy engine.",
5
5
  "keywords": [
6
6
  "open-knowledge-format",
@@ -51,9 +51,10 @@
51
51
  "license": "MIT",
52
52
  "repository": {
53
53
  "type": "git",
54
- "url": "git+https://github.com/robhowley/okf-minisearch.git",
54
+ "url": "git+https://github.com/robhowley/okf-search.git",
55
55
  "directory": "packages/okf-search-native"
56
56
  },
57
+ "homepage": "https://github.com/robhowley/okf-search/tree/main/packages/okf-search-native#readme",
57
58
  "publishConfig": {
58
59
  "access": "public"
59
60
  },