@zepdb/zeppelin-embed 0.1.0 → 0.2.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
@@ -26,6 +26,31 @@ Applications supply document and query vectors. Document IDs are unsigned
26
26
  native finalizer also closes an open handle if the JavaScript object is
27
27
  collected.
28
28
 
29
+ Namespaces add typed records without changing the existing vector API:
30
+
31
+ ```js
32
+ const { openNamespace, listNamespaces } = require('@zepdb/zeppelin-embed');
33
+
34
+ const store = openNamespace('my-database', 'documents', {
35
+ attributes: [{ id: 1, name: 'category', type: 'dictionaryString' }],
36
+ vectorSpace: { dimensions: 2 },
37
+ });
38
+ store.upsert([{
39
+ id: 1n,
40
+ vector: new Float32Array([0.9, 0.1]),
41
+ text: 'stored text',
42
+ attributes: [{ id: 1, type: 'string', value: 'example' }],
43
+ }]);
44
+ console.log(store.get([1n]));
45
+ console.log(store.scan({ limit: 100 }));
46
+ console.log(listNamespaces('my-database'));
47
+ store.close();
48
+ ```
49
+
50
+ Omit `vectorSpace` for a record-only namespace. Scan cursors are opaque and
51
+ must be passed back unchanged; a cursor invalidated by a write throws
52
+ `ZE_ERR_SCAN_STALE`.
53
+
29
54
  The initial package supports Node.js 18 or newer on macOS arm64. Unsupported
30
55
  platforms fail during installation and report a clear error if the package is
31
56
  loaded directly.
package/index.d.ts CHANGED
@@ -19,12 +19,146 @@ export interface MutationReport {
19
19
  readonly generation: bigint;
20
20
  }
21
21
 
22
+ export type DocumentId = bigint;
23
+
24
+ export type AttributeType =
25
+ | 'u64'
26
+ | 'i64'
27
+ | 'f64'
28
+ | 'bool'
29
+ | 'dictionaryString'
30
+ | 'rawString';
31
+
32
+ export interface AttributeDefinition {
33
+ readonly id: number;
34
+ readonly name: string;
35
+ readonly type: AttributeType;
36
+ readonly nullable?: boolean;
37
+ }
38
+
39
+ export type AttributeValue =
40
+ | { readonly id: number; readonly type: 'null'; readonly value: null }
41
+ | { readonly id: number; readonly type: 'u64'; readonly value: bigint }
42
+ | { readonly id: number; readonly type: 'i64'; readonly value: bigint }
43
+ | { readonly id: number; readonly type: 'f64'; readonly value: number }
44
+ | { readonly id: number; readonly type: 'bool'; readonly value: boolean }
45
+ | { readonly id: number; readonly type: 'string'; readonly value: string };
46
+
47
+ export interface VectorSpace {
48
+ readonly dimensions: number;
49
+ readonly normalization?: 'none' | 'unitL2';
50
+ }
51
+
52
+ export interface NamespaceSpec {
53
+ readonly attributes?: readonly AttributeDefinition[];
54
+ readonly vectorSpace?: VectorSpace;
55
+ }
56
+
57
+ export interface UpsertDocument {
58
+ readonly id: DocumentId;
59
+ readonly revision?: bigint;
60
+ readonly timestamp?: bigint;
61
+ readonly vector?: Float32Array;
62
+ readonly text?: string;
63
+ readonly metadata?: Uint8Array;
64
+ readonly attributes?: readonly AttributeValue[];
65
+ }
66
+
67
+ export interface DocumentFields {
68
+ readonly vector?: boolean;
69
+ readonly text?: boolean;
70
+ readonly metadata?: boolean;
71
+ readonly attributes?: boolean;
72
+ }
73
+
74
+ export interface StoredDocument {
75
+ readonly id: DocumentId;
76
+ readonly revision: bigint;
77
+ readonly timestamp: bigint;
78
+ readonly vector?: Float32Array;
79
+ readonly text?: string;
80
+ readonly metadata?: Uint8Array;
81
+ readonly attributes?: AttributeValue[];
82
+ }
83
+
84
+ export interface GetResult {
85
+ readonly documents: Array<StoredDocument | null>;
86
+ readonly missingCount: number;
87
+ readonly generation: bigint;
88
+ }
89
+
90
+ declare const scanCursorBrand: unique symbol;
91
+
92
+ export interface ScanCursor {
93
+ readonly [scanCursorBrand]: never;
94
+ }
95
+
96
+ export type Filter =
97
+ | {
98
+ readonly op: 'eq' | 'notEq' | 'in' | 'notIn';
99
+ readonly attributeId: number;
100
+ readonly values: readonly AttributeValue[];
101
+ }
102
+ | {
103
+ readonly op: 'range';
104
+ readonly attributeId: number;
105
+ readonly lower?: AttributeValue;
106
+ readonly lowerInclusive?: boolean;
107
+ readonly upper?: AttributeValue;
108
+ readonly upperInclusive?: boolean;
109
+ }
110
+ | { readonly op: 'exists' | 'isNull'; readonly attributeId: number }
111
+ | { readonly op: 'and' | 'or'; readonly children: readonly Filter[] }
112
+ | { readonly op: 'not'; readonly children: readonly [Filter] };
113
+
114
+ export interface TimestampRange {
115
+ readonly start: bigint;
116
+ readonly end: bigint;
117
+ }
118
+
119
+ export interface ScanRequest {
120
+ readonly cursor?: ScanCursor;
121
+ readonly limit?: number;
122
+ readonly order?: 'storage' | 'timestampAscending' | 'timestampDescending';
123
+ readonly fields?: DocumentFields;
124
+ readonly timestampRange?: TimestampRange;
125
+ readonly filter?: Filter;
126
+ }
127
+
128
+ export interface ScanPage {
129
+ readonly documents: StoredDocument[];
130
+ readonly generation: bigint;
131
+ readonly cursor: ScanCursor | null;
132
+ }
133
+
134
+ export interface CountRequest {
135
+ readonly filter?: Filter;
136
+ readonly timestampRange?: TimestampRange;
137
+ }
138
+
139
+ export interface CountResult {
140
+ readonly count: bigint;
141
+ readonly generation: bigint;
142
+ }
143
+
144
+ export interface SearchOptions {
145
+ readonly k?: number;
146
+ readonly threadBudget?: number;
147
+ readonly tier?: 'auto' | 'exact' | 'scan' | 'graph';
148
+ readonly graphProfile?: 'sift' | 'angular';
149
+ readonly graphEf?: number;
150
+ readonly graphSeed?: bigint;
151
+ readonly deadlineNs?: bigint;
152
+ }
153
+
22
154
  export interface SearchHit {
23
155
  readonly id: bigint;
24
156
  readonly revision: bigint;
25
157
  readonly score: number;
26
158
  }
27
159
 
160
+ export type SearchResult = SearchHit[];
161
+
28
162
  export declare class ZeppelinError extends Error {
29
163
  constructor(message: string, code: string, errorCode: number);
30
164
  readonly code: string;
@@ -39,8 +173,27 @@ export declare class UnsupportedPlatformError extends Error {
39
173
  export declare class Store {
40
174
  constructor(path: string, options?: OpenOptions);
41
175
  ingest(documents: readonly Document[], dimension: number): MutationReport;
176
+ upsert(documents: readonly UpsertDocument[]): MutationReport;
177
+ get(ids: readonly DocumentId[], fields?: DocumentFields): GetResult;
178
+ delete(ids: readonly DocumentId[]): MutationReport;
179
+ scan(request?: ScanRequest): ScanPage;
180
+ count(request?: CountRequest): CountResult;
181
+ searchFiltered(
182
+ vector: Float32Array,
183
+ filter: Filter,
184
+ options?: SearchOptions,
185
+ ): SearchResult;
42
186
  search(vector: Float32Array, k: number): SearchHit[];
43
187
  close(): void;
44
188
  }
45
189
 
46
190
  export declare const ABI_VERSION: number;
191
+
192
+ export declare function openNamespace(
193
+ root: string,
194
+ name: string,
195
+ spec: NamespaceSpec,
196
+ options?: OpenOptions,
197
+ ): Store;
198
+
199
+ export declare function listNamespaces(root: string): string[];
package/index.js CHANGED
@@ -58,6 +58,30 @@ class Store {
58
58
  return callNative(() => this._native.ingest(documents, dimension));
59
59
  }
60
60
 
61
+ upsert(documents) {
62
+ return callNative(() => this._native.upsert(documents));
63
+ }
64
+
65
+ get(ids, fields) {
66
+ return callNative(() => this._native.get(ids, fields));
67
+ }
68
+
69
+ delete(ids) {
70
+ return callNative(() => this._native.delete(ids));
71
+ }
72
+
73
+ scan(request) {
74
+ return callNative(() => this._native.scan(request));
75
+ }
76
+
77
+ count(request) {
78
+ return callNative(() => this._native.count(request));
79
+ }
80
+
81
+ searchFiltered(vector, filter, options) {
82
+ return callNative(() => this._native.searchFiltered(vector, filter, options));
83
+ }
84
+
61
85
  search(vector, k) {
62
86
  return callNative(() => this._native.search(vector, k));
63
87
  }
@@ -67,9 +91,23 @@ class Store {
67
91
  }
68
92
  }
69
93
 
94
+ function openNamespace(root, name, spec, options = {}) {
95
+ return callNative(() => {
96
+ const store = Object.create(Store.prototype);
97
+ store._native = new binding.NativeStore(root, options, name, spec);
98
+ return store;
99
+ });
100
+ }
101
+
102
+ function listNamespaces(root) {
103
+ return callNative(() => binding.listNamespaces(root));
104
+ }
105
+
70
106
  module.exports = {
71
107
  ABI_VERSION: binding.abiVersion,
72
108
  Store,
73
109
  UnsupportedPlatformError,
74
110
  ZeppelinError,
111
+ listNamespaces,
112
+ openNamespace,
75
113
  };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@zepdb/zeppelin-embed",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "In-process vector search for macOS and Apple silicon",
5
5
  "license": "GPL-3.0-only",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/zepdb/zeppelin-embed.git",
9
- "directory": "node"
9
+ "directory": "bindings/node"
10
10
  },
11
11
  "homepage": "https://github.com/zepdb/zeppelin-embed#readme",
12
12
  "bugs": "https://github.com/zepdb/zeppelin-embed/issues",