@luxdb/sdk 1.0.0 → 1.1.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/dist/index.d.ts +34 -0
- package/dist/index.js +121 -0
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,30 @@ export interface VSearchOptions {
|
|
|
12
12
|
};
|
|
13
13
|
meta?: boolean;
|
|
14
14
|
}
|
|
15
|
+
export interface TSSample {
|
|
16
|
+
timestamp: number;
|
|
17
|
+
value: number;
|
|
18
|
+
}
|
|
19
|
+
export interface TSAddOptions {
|
|
20
|
+
retention?: number;
|
|
21
|
+
labels?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
export interface TSRangeOptions {
|
|
24
|
+
aggregation?: {
|
|
25
|
+
type: 'avg' | 'sum' | 'min' | 'max' | 'count' | 'first' | 'last' | 'range' | 'std.p' | 'std.s' | 'var.p' | 'var.s';
|
|
26
|
+
bucketSize: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface TSMRangeResult {
|
|
30
|
+
key: string;
|
|
31
|
+
labels: Record<string, string>;
|
|
32
|
+
samples: TSSample[];
|
|
33
|
+
}
|
|
34
|
+
export interface KSubEvent {
|
|
35
|
+
pattern: string;
|
|
36
|
+
key: string;
|
|
37
|
+
operation: string;
|
|
38
|
+
}
|
|
15
39
|
export declare class Lux extends Redis {
|
|
16
40
|
constructor(options?: RedisOptions | string);
|
|
17
41
|
vset(key: string, vector: number[], options?: {
|
|
@@ -26,5 +50,15 @@ export declare class Lux extends Redis {
|
|
|
26
50
|
} | null>;
|
|
27
51
|
vsearch(query: number[], options: VSearchOptions): Promise<VSearchResult[]>;
|
|
28
52
|
vcard(): Promise<number>;
|
|
53
|
+
tsadd(key: string, timestamp: number | '*', value: number, options?: TSAddOptions): Promise<number>;
|
|
54
|
+
tsmadd(...entries: [string, number | '*', number][]): Promise<string>;
|
|
55
|
+
tsget(key: string): Promise<TSSample | null>;
|
|
56
|
+
tsrange(key: string, from: number | '-', to: number | '+', options?: TSRangeOptions): Promise<TSSample[]>;
|
|
57
|
+
tsmrange(from: number | '-', to: number | '+', filter: string, options?: TSRangeOptions): Promise<TSMRangeResult[]>;
|
|
58
|
+
tsinfo(key: string): Promise<Record<string, unknown>>;
|
|
59
|
+
ksub(patterns: string[], handler: (event: KSubEvent) => void): {
|
|
60
|
+
unsubscribe: () => void;
|
|
61
|
+
connection: Redis;
|
|
62
|
+
};
|
|
29
63
|
}
|
|
30
64
|
export default Lux;
|
package/dist/index.js
CHANGED
|
@@ -75,6 +75,127 @@ class Lux extends ioredis_1.default {
|
|
|
75
75
|
async vcard() {
|
|
76
76
|
return this.call('VCARD');
|
|
77
77
|
}
|
|
78
|
+
async tsadd(key, timestamp, value, options) {
|
|
79
|
+
const args = [key, timestamp === '*' ? '*' : timestamp, value];
|
|
80
|
+
if (options?.retention != null) {
|
|
81
|
+
args.push('RETENTION', options.retention);
|
|
82
|
+
}
|
|
83
|
+
if (options?.labels) {
|
|
84
|
+
args.push('LABELS');
|
|
85
|
+
for (const [k, v] of Object.entries(options.labels)) {
|
|
86
|
+
args.push(k, v);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return this.call('TSADD', ...args);
|
|
90
|
+
}
|
|
91
|
+
async tsmadd(...entries) {
|
|
92
|
+
const args = [];
|
|
93
|
+
for (const [key, ts, val] of entries) {
|
|
94
|
+
args.push(key, ts === '*' ? '*' : ts, val);
|
|
95
|
+
}
|
|
96
|
+
return this.call('TSMADD', ...args);
|
|
97
|
+
}
|
|
98
|
+
async tsget(key) {
|
|
99
|
+
const result = (await this.call('TSGET', key));
|
|
100
|
+
if (!result || !Array.isArray(result) || result.length < 2)
|
|
101
|
+
return null;
|
|
102
|
+
return { timestamp: parseInt(result[0], 10), value: parseFloat(result[1]) };
|
|
103
|
+
}
|
|
104
|
+
async tsrange(key, from, to, options) {
|
|
105
|
+
const args = [key, from === '-' ? '-' : from, to === '+' ? '+' : to];
|
|
106
|
+
if (options?.aggregation) {
|
|
107
|
+
args.push('AGGREGATION', options.aggregation.type, options.aggregation.bucketSize);
|
|
108
|
+
}
|
|
109
|
+
const result = (await this.call('TSRANGE', ...args));
|
|
110
|
+
if (!result || !Array.isArray(result))
|
|
111
|
+
return [];
|
|
112
|
+
return result.map((pair) => ({
|
|
113
|
+
timestamp: parseInt(pair[0], 10),
|
|
114
|
+
value: parseFloat(pair[1]),
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
async tsmrange(from, to, filter, options) {
|
|
118
|
+
const args = [from === '-' ? '-' : from, to === '+' ? '+' : to];
|
|
119
|
+
if (options?.aggregation) {
|
|
120
|
+
args.push('AGGREGATION', options.aggregation.type, options.aggregation.bucketSize);
|
|
121
|
+
}
|
|
122
|
+
args.push('FILTER', filter);
|
|
123
|
+
const result = (await this.call('TSMRANGE', ...args));
|
|
124
|
+
if (!result || !Array.isArray(result))
|
|
125
|
+
return [];
|
|
126
|
+
return result.map((series) => {
|
|
127
|
+
const labels = {};
|
|
128
|
+
if (Array.isArray(series[1])) {
|
|
129
|
+
for (const pair of series[1]) {
|
|
130
|
+
if (Array.isArray(pair) && pair.length >= 2) {
|
|
131
|
+
labels[pair[0]] = pair[1];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const samples = Array.isArray(series[2])
|
|
136
|
+
? series[2].map((s) => ({ timestamp: parseInt(s[0], 10), value: parseFloat(s[1]) }))
|
|
137
|
+
: [];
|
|
138
|
+
return { key: series[0], labels, samples };
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async tsinfo(key) {
|
|
142
|
+
const result = (await this.call('TSINFO', key));
|
|
143
|
+
if (!result || !Array.isArray(result))
|
|
144
|
+
return {};
|
|
145
|
+
const info = {};
|
|
146
|
+
for (let i = 0; i < result.length - 1; i += 2) {
|
|
147
|
+
const k = result[i];
|
|
148
|
+
const v = result[i + 1];
|
|
149
|
+
if (k === 'labels' && Array.isArray(v)) {
|
|
150
|
+
const labels = {};
|
|
151
|
+
for (const pair of v) {
|
|
152
|
+
if (Array.isArray(pair) && pair.length >= 2)
|
|
153
|
+
labels[pair[0]] = pair[1];
|
|
154
|
+
}
|
|
155
|
+
info[k] = labels;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
info[k] = v;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return info;
|
|
162
|
+
}
|
|
163
|
+
ksub(patterns, handler) {
|
|
164
|
+
const sub = this.duplicate();
|
|
165
|
+
sub.on('error', () => { });
|
|
166
|
+
const origReturnReply = sub.returnReply?.bind(sub);
|
|
167
|
+
const dataHandler = sub._dataHandler || sub.dataHandler;
|
|
168
|
+
if (dataHandler && dataHandler.returnReply) {
|
|
169
|
+
const origReturn = dataHandler.returnReply.bind(dataHandler);
|
|
170
|
+
dataHandler.returnReply = (reply) => {
|
|
171
|
+
if (Array.isArray(reply) && reply.length === 4 && reply[0] === 'kmessage') {
|
|
172
|
+
handler({ pattern: reply[1], key: reply[2], operation: reply[3] });
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
return origReturn(reply);
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
const origEmit = sub.emit.bind(sub);
|
|
180
|
+
sub.emit = (event, ...args) => {
|
|
181
|
+
if (event === 'error' && args[0]?.message?.includes('Command queue state error')) {
|
|
182
|
+
const match = args[0].message.match(/Last reply: kmessage,([^,]+),([^,]+),(.+)/);
|
|
183
|
+
if (match) {
|
|
184
|
+
handler({ pattern: match[1], key: match[2], operation: match[3] });
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return origEmit(event, ...args);
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
sub.call('KSUB', ...patterns);
|
|
192
|
+
return {
|
|
193
|
+
connection: sub,
|
|
194
|
+
unsubscribe() {
|
|
195
|
+
sub.disconnect();
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
78
199
|
}
|
|
79
200
|
exports.Lux = Lux;
|
|
80
201
|
exports.default = Lux;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luxdb/sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Lux SDK - ioredis extended with
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Lux SDK - ioredis extended with vector search, time series, and realtime key subscriptions",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": ["dist"],
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"ioredis": "^5.0.0"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
+
"@types/node": "^25.5.0",
|
|
16
17
|
"typescript": "^5.9.0"
|
|
17
18
|
},
|
|
18
19
|
"peerDependencies": {
|
|
@@ -24,5 +25,5 @@
|
|
|
24
25
|
"url": "https://github.com/lux-db/lux",
|
|
25
26
|
"directory": "sdk"
|
|
26
27
|
},
|
|
27
|
-
"keywords": ["lux", "redis", "vector", "search", "database", "ioredis", "similarity"]
|
|
28
|
+
"keywords": ["lux", "redis", "vector", "search", "database", "ioredis", "similarity", "timeseries", "realtime", "subscriptions"]
|
|
28
29
|
}
|