@luxdb/sdk 1.4.1 → 1.4.3

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/esm/table.js CHANGED
@@ -56,9 +56,10 @@ export class TableSubscription {
56
56
  try {
57
57
  const initial = await this.fetchMatches();
58
58
  for (const row of initial) {
59
- if (row.id == null)
59
+ const id = row.id;
60
+ if (id == null)
60
61
  continue;
61
- this.knownRows.set(String(row.id), row);
62
+ this.knownRows.set(String(id), row);
62
63
  }
63
64
  const pattern = `_t:${this.table}:row:*`;
64
65
  this.unsubscribeFn = await this.client._subscribePattern(pattern, (raw) => {
@@ -108,7 +109,9 @@ export class TableSubscription {
108
109
  if (!previous || !next)
109
110
  return;
110
111
  this.knownRows.set(pk, next);
111
- const changed = Object.keys(next).filter((key) => previous[key] !== next[key]);
112
+ const previousRow = previous;
113
+ const nextRow = next;
114
+ const changed = Object.keys(nextRow).filter((key) => previousRow[key] !== nextRow[key]);
112
115
  this.emitChange({
113
116
  type: 'update',
114
117
  table: this.table,
@@ -128,6 +131,8 @@ export class TableSubscription {
128
131
  export class TableQueryBuilder {
129
132
  constructor(client, name, options) {
130
133
  this.conditions = [];
134
+ this.groupFields = [];
135
+ this.havingConditions = [];
131
136
  this.selectClause = '*';
132
137
  this.expectSingle = false;
133
138
  this.client = client;
@@ -153,7 +158,7 @@ export class TableQueryBuilder {
153
158
  const args = [this.selectClause, 'FROM', this.name];
154
159
  const allConditions = extra ? [...this.conditions, ...extra] : this.conditions;
155
160
  if (this.joinClause) {
156
- args.push('JOIN', this.joinClause.table, this.joinClause.alias, 'ON', this.joinClause.onLeft, '=', this.joinClause.onRight);
161
+ args.push(...(this.joinClause.type === 'LEFT' ? ['LEFT', 'JOIN'] : ['JOIN']), this.joinClause.table, this.joinClause.alias, 'ON', this.joinClause.onLeft, '=', this.joinClause.onRight);
157
162
  }
158
163
  if (allConditions.length) {
159
164
  args.push('WHERE');
@@ -165,6 +170,25 @@ export class TableQueryBuilder {
165
170
  }
166
171
  }
167
172
  }
173
+ if (this.groupFields.length) {
174
+ args.push('GROUP', 'BY', ...this.groupFields);
175
+ }
176
+ if (this.havingConditions.length) {
177
+ args.push('HAVING');
178
+ for (let i = 0; i < this.havingConditions.length; i++) {
179
+ const cond = this.havingConditions[i];
180
+ args.push(cond.field, cond.op, String(cond.value));
181
+ if (i < this.havingConditions.length - 1) {
182
+ args.push('AND');
183
+ }
184
+ }
185
+ }
186
+ if (this.similarityClause) {
187
+ args.push('NEAR', this.similarityClause.field, `[${this.similarityClause.vector.join(',')}]`, 'K', String(this.similarityClause.k));
188
+ if (this.similarityClause.threshold != null) {
189
+ args.push('THRESHOLD', String(this.similarityClause.threshold));
190
+ }
191
+ }
168
192
  if (this.orderField) {
169
193
  args.push('ORDER', 'BY', this.orderField, this.orderDir || 'ASC');
170
194
  }
@@ -226,68 +250,41 @@ export class TableQueryBuilder {
226
250
  return this;
227
251
  }
228
252
  join(table, alias, onLeft, onRight) {
229
- this.joinClause = { table, alias, onLeft, onRight };
253
+ this.joinClause = { type: 'INNER', table, alias, onLeft, onRight };
254
+ return this;
255
+ }
256
+ leftJoin(table, alias, onLeft, onRight) {
257
+ this.joinClause = { type: 'LEFT', table, alias, onLeft, onRight };
258
+ return this;
259
+ }
260
+ group(fields) {
261
+ this.groupFields = Array.isArray(fields)
262
+ ? fields
263
+ : fields.split(',').map((field) => field.trim()).filter(Boolean);
264
+ return this;
265
+ }
266
+ groupBy(fields) {
267
+ return this.group(fields);
268
+ }
269
+ having(field, op, value) {
270
+ this.havingConditions.push({ field, op, value });
230
271
  return this;
231
272
  }
232
- similar(field, vector, options) {
273
+ near(field, vector, options = {}) {
233
274
  this.similarityClause = {
234
275
  field,
235
276
  vector,
236
- k: options.k,
237
- filter: options.filter,
277
+ k: options.k ?? 10,
278
+ threshold: options.threshold,
238
279
  };
239
280
  return this;
240
281
  }
241
- parseSimilarityPk(result, field) {
242
- const metadata = result.metadata;
243
- if (metadata && typeof metadata === 'object') {
244
- for (const key of ['id', 'pk', 'row_id']) {
245
- const value = metadata[key];
246
- if (value != null)
247
- return String(value);
248
- }
249
- }
250
- const expectedPrefix = `${this.name}:${field}:`;
251
- if (result.key.startsWith(expectedPrefix)) {
252
- return result.key.slice(expectedPrefix.length);
253
- }
254
- const segments = result.key.split(':');
255
- if (segments.length > 0) {
256
- return segments[segments.length - 1] || null;
257
- }
258
- return null;
282
+ similar(field, vector, options = {}) {
283
+ return this.near(field, vector, options);
259
284
  }
260
285
  async run() {
261
286
  try {
262
- let rows = [];
263
- if (this.similarityClause) {
264
- if (this.joinClause) {
265
- return err('SIMILAR_JOIN_UNSUPPORTED', 'similar(...) cannot be combined with join(...) yet');
266
- }
267
- const similarResults = await this.client.vsearch(this.similarityClause.vector, {
268
- k: this.similarityClause.k,
269
- filter: this.similarityClause.filter,
270
- meta: true,
271
- });
272
- for (const match of similarResults) {
273
- const pk = this.parseSimilarityPk(match, this.similarityClause.field);
274
- if (!pk)
275
- continue;
276
- const args = this.buildSelectArgs([{ field: 'id', op: '=', value: pk }]);
277
- const one = await this.client._tselect(args);
278
- if (one.length === 0)
279
- continue;
280
- rows.push({ ...one[0], _similarity: match.similarity });
281
- }
282
- if (this.offsetCount != null || this.limitCount != null) {
283
- const start = this.offsetCount ?? 0;
284
- const end = this.limitCount != null ? start + this.limitCount : undefined;
285
- rows = rows.slice(start, end);
286
- }
287
- }
288
- else {
289
- rows = await this.client._tselect(this.buildSelectArgs());
290
- }
287
+ const rows = await this.client._tselect(this.buildSelectArgs());
291
288
  const validated = rows.map((row) => this.validateRow(row));
292
289
  if (this.expectSingle) {
293
290
  if (validated.length === 0) {
@@ -380,12 +377,6 @@ export class TableQueryBuilder {
380
377
  }
381
378
  }
382
379
  subscribe() {
383
- if (this.similarityClause) {
384
- return new TableSubscription(this.client, this.name, (extra) => this.buildSelectArgs(extra), {
385
- code: 'SIMILAR_SUBSCRIBE_UNSUPPORTED',
386
- message: 'subscribe() is not supported on similar(...) queries yet',
387
- });
388
- }
389
380
  return new TableSubscription(this.client, this.name, (extra) => this.buildSelectArgs(extra));
390
381
  }
391
382
  }
@@ -11,6 +11,90 @@ export interface LuxAuthUser {
11
11
  user_metadata?: Record<string, unknown>;
12
12
  app_metadata?: Record<string, unknown>;
13
13
  }
14
+ export type LuxUser = LuxAuthUser;
15
+ export interface LuxAuthUserRow {
16
+ id: string;
17
+ email?: string;
18
+ phone?: string;
19
+ encrypted_password?: string;
20
+ email_confirmed_at?: number | null;
21
+ phone_confirmed_at?: number | null;
22
+ raw_user_meta_data?: string;
23
+ raw_app_meta_data?: string;
24
+ created_at?: number | null;
25
+ updated_at?: number | null;
26
+ last_sign_in_at?: number | null;
27
+ banned_until?: number | null;
28
+ deleted_at?: number | null;
29
+ }
30
+ export interface LuxAuthIdentityRow {
31
+ id: string;
32
+ user_id: string;
33
+ provider: string;
34
+ provider_id: string;
35
+ identity_data?: string;
36
+ created_at?: number | null;
37
+ updated_at?: number | null;
38
+ }
39
+ export interface LuxAuthSessionRow {
40
+ id: string;
41
+ user_id: string;
42
+ refresh_token_hash: string;
43
+ refresh_token_family?: string;
44
+ user_agent?: string;
45
+ ip?: string;
46
+ expires_at?: number | null;
47
+ revoked_at?: number | null;
48
+ created_at?: number | null;
49
+ updated_at?: number | null;
50
+ }
51
+ export interface LuxAuthKeyRow {
52
+ id: string;
53
+ name?: string;
54
+ kind: 'publishable' | 'secret' | string;
55
+ prefix: string;
56
+ key_hash: string;
57
+ scopes?: string;
58
+ created_at?: number | null;
59
+ revoked_at?: number | null;
60
+ last_used_at?: number | null;
61
+ }
62
+ export interface LuxAuthSigningKeyRow {
63
+ id: string;
64
+ kid: string;
65
+ algorithm: string;
66
+ public_jwk?: string;
67
+ private_key_encrypted?: string;
68
+ active: boolean;
69
+ created_at?: number | null;
70
+ rotated_at?: number | null;
71
+ }
72
+ export interface LuxAuthGrantRow {
73
+ id: string;
74
+ user_id: string;
75
+ capability: string;
76
+ created_at?: number | null;
77
+ revoked_at?: number | null;
78
+ }
79
+ export interface LuxAuthProviderRow {
80
+ provider: LuxOAuthProvider | string;
81
+ enabled: boolean;
82
+ client_id?: string;
83
+ client_secret?: string;
84
+ redirect_uri?: string;
85
+ scopes?: string;
86
+ created_at?: number | null;
87
+ updated_at?: number | null;
88
+ }
89
+ export interface LuxAuthTables {
90
+ 'auth.users': LuxAuthUserRow;
91
+ 'auth.identities': LuxAuthIdentityRow;
92
+ 'auth.sessions': LuxAuthSessionRow;
93
+ 'auth.keys': LuxAuthKeyRow;
94
+ 'auth.signing_keys': LuxAuthSigningKeyRow;
95
+ 'auth.grants': LuxAuthGrantRow;
96
+ 'auth.providers': LuxAuthProviderRow;
97
+ }
14
98
  export interface LuxAuthSession {
15
99
  access_token: string;
16
100
  token_type: 'bearer';
@@ -3,15 +3,15 @@ import { LuxAuthClient, type LuxAuthOptions } from './auth';
3
3
  import { createProjectClient, LuxProjectClient, type LuxProjectOptions } from './project';
4
4
  import { TimeSeriesNamespace, VectorNamespace } from './namespaces';
5
5
  import { TableQueryBuilder, type TableQueryBuilderOptions } from './table';
6
- import type { KSubEvent, TableRow, TSAddOptions, TSMRangeResult, TSRangeOptions, TSSample, VSearchResult } from './types';
7
- export type { LuxAuthKey, LuxAuthChangeEvent, LuxAuthOptions, LuxAuthSession, LuxAuthStateChangeCallback, LuxAuthStorage, LuxAuthSubscription, LuxAuthUser, LuxOAuthProvider, LuxOAuthUrl, LuxSignInWithOAuthOptions, LuxCreateApiKeyOptions, LuxSignInOptions, LuxSignUpOptions, } from './auth';
6
+ import type { KSubEvent, LuxTypedRow, TableRow, TSAddOptions, TSMRangeResult, TSRangeOptions, TSSample, VSearchResult } from './types';
7
+ export type { LuxAuthKey, LuxAuthGrantRow, LuxAuthIdentityRow, LuxAuthChangeEvent, LuxAuthOptions, LuxAuthKeyRow, LuxAuthProviderRow, LuxAuthSession, LuxAuthSessionRow, LuxAuthSigningKeyRow, LuxAuthStateChangeCallback, LuxAuthStorage, LuxAuthSubscription, LuxAuthTables, LuxAuthUserRow, LuxAuthUser, LuxUser, LuxOAuthProvider, LuxOAuthUrl, LuxSignInWithOAuthOptions, LuxCreateApiKeyOptions, LuxSignInOptions, LuxSignUpOptions, } from './auth';
8
8
  export { createProjectClient, LuxProjectClient, };
9
9
  export { createBrowserClient } from './browser';
10
10
  export type { LuxBrowserClientOptions } from './browser';
11
11
  export { createServerClient } from './ssr';
12
12
  export type { LuxCookieMethods, LuxCookieOptions, LuxServerClientOptions } from './ssr';
13
- export type { LuxProjectOptions, LuxTableColumn, LuxVectorSearchOptions, } from './project';
14
- export type { KSubEvent, LuxError, LuxResult, TableChangeEvent, TableChangeType, TableErrorEvent, TableRow, TableSchema, TSAddOptions, TSMRangeResult, TSRangeOptions, TSSample, VSearchResult, } from './types';
13
+ export type { LuxProjectLiveEvent, LuxProjectLiveEventType, LuxProjectOptions, LuxTableColumn, LuxVectorSearchOptions, } from './project';
14
+ export type { KSubEvent, LuxAggregateRow, LuxAggregateValue, LuxError, LuxInferRow, LuxNearRow, LuxResult, LuxSimilarity, LuxTypedRow, TableChangeEvent, TableChangeType, TableErrorEvent, TableRow, TableSchema, TSAddOptions, TSMRangeResult, TSRangeOptions, TSSample, VSearchResult, } from './types';
15
15
  export { TableQueryBuilder, TableSubscription } from './table';
16
16
  export type { TableQueryBuilderOptions } from './table';
17
17
  export type LuxClientOptions = RedisOptions & LuxAuthOptions;
@@ -23,7 +23,7 @@ export declare class Lux extends Redis {
23
23
  authApi: LuxAuthClient;
24
24
  private realtimeManager?;
25
25
  constructor(options?: LuxClientOptions | RedisOptions | string);
26
- table<T extends TableRow = TableRow>(name: string, options?: TableQueryBuilderOptions<T>): TableQueryBuilder<T>;
26
+ table<T extends object | readonly object[] = TableRow>(name: string, options?: TableQueryBuilderOptions<LuxTypedRow<T>>): TableQueryBuilder<LuxTypedRow<T>>;
27
27
  _subscribePattern(pattern: string, handler: (event: KSubEvent) => void): Promise<() => void>;
28
28
  _tselect(args: string[]): Promise<TableRow[]>;
29
29
  vset(key: string, vector: number[], options?: {
@@ -1,14 +1,15 @@
1
1
  import { LuxAuthClient, type LuxAuthOptions } from './auth';
2
- import type { LuxResult } from './types';
2
+ import type { LuxResult, LuxTypedRow } from './types';
3
3
  export interface LuxProjectOptions {
4
4
  url: string;
5
5
  key: string;
6
6
  fetch?: typeof fetch;
7
+ websocket?: typeof WebSocket;
7
8
  auth?: Omit<LuxAuthOptions, 'httpUrl' | 'apiKey' | 'fetch'>;
8
9
  }
9
10
  export interface LuxTableColumn {
10
11
  name: string;
11
- type: 'STR' | 'INT' | 'FLOAT' | 'BOOL' | 'TIMESTAMP' | 'UUID';
12
+ type: 'STR' | 'INT' | 'FLOAT' | 'BOOL' | 'TIMESTAMP' | 'UUID' | `VECTOR(${number})`;
12
13
  primaryKey?: boolean;
13
14
  unique?: boolean;
14
15
  notNull?: boolean;
@@ -21,8 +22,10 @@ export interface LuxVectorSearchOptions {
21
22
  filter?: string;
22
23
  filter_value?: string;
23
24
  }
24
- type QueryValue = string | number | boolean | null;
25
+ type QueryValue = string | number | boolean | number[] | null;
25
26
  type FilterOperator = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'is';
27
+ type ProjectRowInput<T extends object> = Partial<T> & Record<string, QueryValue>;
28
+ type ProjectSelectSingle<TResult> = TResult extends readonly (infer Row)[] ? Row : TResult;
26
29
  interface QueryFilter {
27
30
  column: string;
28
31
  operator: FilterOperator;
@@ -32,13 +35,51 @@ interface QueryOrder {
32
35
  column: string;
33
36
  ascending: boolean;
34
37
  }
38
+ interface QueryJoin {
39
+ type: 'inner' | 'left';
40
+ table: string;
41
+ alias: string;
42
+ onLeft: string;
43
+ onRight: string;
44
+ }
45
+ interface QueryHaving {
46
+ column: string;
47
+ operator: FilterOperator;
48
+ value: QueryValue;
49
+ }
50
+ interface QueryNear {
51
+ field: string;
52
+ vector: number[];
53
+ k: number;
54
+ threshold?: number;
55
+ }
56
+ export type LuxProjectLiveEventType = 'snapshot' | 'insert' | 'update' | 'delete' | 'error';
57
+ export interface LuxProjectLiveEvent<T extends object = Record<string, unknown>> {
58
+ type: LuxProjectLiveEventType;
59
+ table: string;
60
+ pk?: string;
61
+ new: T | null;
62
+ old: T | null;
63
+ rows?: T[];
64
+ changed?: string[];
65
+ raw?: unknown;
66
+ error?: {
67
+ code?: string;
68
+ message?: string;
69
+ };
70
+ }
71
+ type LiveEventHandler<T extends object> = (event: LuxProjectLiveEvent<T>) => void;
35
72
  export declare class LuxProjectClient {
36
73
  readonly url: string;
37
74
  readonly key: string;
38
75
  readonly auth: LuxAuthClient;
39
76
  private fetchImpl;
77
+ private WebSocketImpl?;
78
+ private liveSocket;
79
+ private liveSubscriptions;
80
+ private livePending;
40
81
  constructor(options: LuxProjectOptions);
41
- table<T extends Record<string, unknown> = Record<string, unknown>>(name: string): LuxProjectTable<T>;
82
+ table<T extends object | readonly object[] = Record<string, unknown>>(name: string): LuxProjectTable<LuxTypedRow<T>>;
42
83
  ping(): Promise<LuxResult<unknown>>;
43
84
  createTable(name: string, columns: Array<string | LuxTableColumn>): Promise<LuxResult<unknown>>;
44
85
  exec(command: string | string[]): Promise<LuxResult<unknown>>;
@@ -55,15 +96,33 @@ export declare class LuxProjectClient {
55
96
  count?: number;
56
97
  }): Promise<LuxResult<unknown>>;
57
98
  request<T = unknown>(method: string, path: string, body?: unknown): Promise<LuxResult<T>>;
99
+ _subscribeLive(spec: Record<string, unknown>, handler: (event: unknown) => void, error: (error: {
100
+ code?: string;
101
+ message?: string;
102
+ }) => void): Promise<() => void>;
103
+ private ensureLiveSocket;
104
+ private sendLive;
58
105
  }
59
- export declare class LuxProjectTable<T extends Record<string, unknown>> {
106
+ export declare class LuxProjectTable<T extends object> {
60
107
  private client;
61
108
  private name;
62
109
  constructor(client: LuxProjectClient, name: string);
63
- select(columns?: string): LuxProjectSelectBuilder<T, T[]>;
64
- insert(row: Partial<T> & Record<string, QueryValue>): LuxProjectInsertBuilder<unknown>;
65
- insert(rows: Array<Partial<T> & Record<string, QueryValue>>): LuxProjectInsertBuilder<unknown[]>;
66
- update(patch: Partial<T> & Record<string, QueryValue>): LuxProjectMutationBuilder<unknown>;
110
+ select<TResult extends object = T>(columns?: string): LuxProjectSelectBuilder<T, TResult[]>;
111
+ eq(column: string, value: QueryValue): LuxProjectSelectBuilder<T, T[]>;
112
+ neq(column: string, value: QueryValue): LuxProjectSelectBuilder<T, T[]>;
113
+ gt(column: string, value: QueryValue): LuxProjectSelectBuilder<T, T[]>;
114
+ gte(column: string, value: QueryValue): LuxProjectSelectBuilder<T, T[]>;
115
+ lt(column: string, value: QueryValue): LuxProjectSelectBuilder<T, T[]>;
116
+ lte(column: string, value: QueryValue): LuxProjectSelectBuilder<T, T[]>;
117
+ near(column: string, vector: number[], options?: {
118
+ k?: number;
119
+ threshold?: number;
120
+ }): LuxProjectSelectBuilder<T, T[]>;
121
+ is(column: string, value: QueryValue): LuxProjectSelectBuilder<T, T[]>;
122
+ live(): LuxProjectLiveSubscription<T>;
123
+ insert(row: ProjectRowInput<T>): LuxProjectInsertBuilder<unknown>;
124
+ insert(rows: Array<ProjectRowInput<T>>): LuxProjectInsertBuilder<unknown[]>;
125
+ update(patch: ProjectRowInput<T>): LuxProjectMutationBuilder<unknown>;
67
126
  delete(): LuxProjectMutationBuilder<unknown>;
68
127
  count(): Promise<LuxResult<number>>;
69
128
  }
@@ -78,6 +137,10 @@ declare abstract class LuxProjectFilterBuilder<TResult, TSelf> extends LuxProjec
78
137
  protected tableName: string;
79
138
  protected filters: QueryFilter[];
80
139
  protected orderBy?: QueryOrder;
140
+ protected joins: QueryJoin[];
141
+ protected groupColumns: string[];
142
+ protected havingFilters: QueryHaving[];
143
+ protected nearQuery?: QueryNear;
81
144
  protected limitCount?: number;
82
145
  protected offsetCount?: number;
83
146
  protected constructor(client: LuxProjectClient, tableName: string);
@@ -88,20 +151,48 @@ declare abstract class LuxProjectFilterBuilder<TResult, TSelf> extends LuxProjec
88
151
  lt(column: string, value: QueryValue): TSelf;
89
152
  lte(column: string, value: QueryValue): TSelf;
90
153
  is(column: string, value: QueryValue): TSelf;
154
+ join(table: string, alias: string, onLeft: string, onRight: string): TSelf;
155
+ leftJoin(table: string, alias: string, onLeft: string, onRight: string): TSelf;
156
+ group(columns: string | string[]): TSelf;
157
+ having(column: string, operator: FilterOperator, value: QueryValue): TSelf;
91
158
  protected addFilter(column: string, operator: FilterOperator, value: QueryValue): TSelf;
92
159
  protected filteredQueryParams(): URLSearchParams;
93
160
  }
94
- export declare class LuxProjectSelectBuilder<T extends Record<string, unknown>, TResult> extends LuxProjectFilterBuilder<TResult, LuxProjectSelectBuilder<T, TResult>> {
161
+ export declare class LuxProjectSelectBuilder<T extends object, TResult> extends LuxProjectFilterBuilder<TResult, LuxProjectSelectBuilder<T, TResult>> {
95
162
  private columns;
96
163
  private expectSingle;
97
164
  constructor(client: LuxProjectClient, tableName: string, columns: string);
98
165
  order(column: string, options?: {
99
166
  ascending?: boolean;
100
167
  }): this;
168
+ near(column: string, vector: number[], options?: {
169
+ k?: number;
170
+ threshold?: number;
171
+ }): this;
101
172
  limit(count: number): this;
102
173
  range(from: number, to: number): this;
103
- single(): LuxProjectSelectBuilder<T, T>;
174
+ single(): LuxProjectSelectBuilder<T, ProjectSelectSingle<TResult>>;
104
175
  execute(): Promise<LuxResult<TResult>>;
176
+ live(): LuxProjectLiveSubscription<LuxTypedRow<TResult>>;
177
+ }
178
+ export declare class LuxProjectLiveSubscription<T extends object> {
179
+ private client;
180
+ private table;
181
+ private columns;
182
+ private filters;
183
+ private nearQuery?;
184
+ private orderBy?;
185
+ private limitCount?;
186
+ private offsetCount?;
187
+ private handlers;
188
+ private unsubscribeFn;
189
+ constructor(client: LuxProjectClient, table: string, columns: string, filters: QueryFilter[], nearQuery?: QueryNear | undefined, orderBy?: QueryOrder | undefined, limitCount?: number | undefined, offsetCount?: number | undefined);
190
+ on(type: LuxProjectLiveEventType | 'change', handler: LiveEventHandler<T>): this;
191
+ unsubscribe(): Promise<void>;
192
+ private start;
193
+ private spec;
194
+ private handleEvent;
195
+ private emit;
105
196
  }
106
197
  export declare class LuxProjectInsertBuilder<TResult> extends LuxProjectThenable<TResult> {
107
198
  private client;
@@ -1,4 +1,4 @@
1
- import type { KSubEvent, LuxError, LuxResult, TableChangeEvent, TableErrorEvent, TableRow, TableSchema, VSearchResult } from './types';
1
+ import type { KSubEvent, LuxError, LuxResult, TableChangeEvent, TableErrorEvent, TableRow, TableSchema } from './types';
2
2
  type TableWhereOp = '=' | '!=' | '>' | '<' | '>=' | '<=';
3
3
  type TableWhereValue = string | number | boolean;
4
4
  interface TableWhereCondition {
@@ -10,19 +10,11 @@ interface TableClient {
10
10
  call(command: string, ...args: Array<string | number>): Promise<unknown>;
11
11
  _tselect(args: string[]): Promise<TableRow[]>;
12
12
  _subscribePattern(pattern: string, handler: (event: KSubEvent) => void): Promise<() => void>;
13
- vsearch(query: number[], options: {
14
- k: number;
15
- filter?: {
16
- key: string;
17
- value: string;
18
- };
19
- meta?: boolean;
20
- }): Promise<VSearchResult[]>;
21
13
  }
22
- export interface TableQueryBuilderOptions<T extends TableRow> {
14
+ export interface TableQueryBuilderOptions<T extends object> {
23
15
  schema?: TableSchema<T>;
24
16
  }
25
- export declare class TableSubscription<T extends TableRow> {
17
+ export declare class TableSubscription<T extends object> {
26
18
  private client;
27
19
  private table;
28
20
  private selectArgsBuilder;
@@ -41,7 +33,7 @@ export declare class TableSubscription<T extends TableRow> {
41
33
  private start;
42
34
  private handleRawChange;
43
35
  }
44
- export declare class TableQueryBuilder<T extends TableRow = TableRow> {
36
+ export declare class TableQueryBuilder<T extends object = TableRow> {
45
37
  private client;
46
38
  private name;
47
39
  private conditions;
@@ -51,6 +43,8 @@ export declare class TableQueryBuilder<T extends TableRow = TableRow> {
51
43
  private offsetCount?;
52
44
  private joinClause?;
53
45
  private similarityClause?;
46
+ private groupFields;
47
+ private havingConditions;
54
48
  private selectClause;
55
49
  private expectSingle;
56
50
  private schema?;
@@ -73,14 +67,18 @@ export declare class TableQueryBuilder<T extends TableRow = TableRow> {
73
67
  limit(n: number): this;
74
68
  offset(n: number): this;
75
69
  join(table: string, alias: string, onLeft: string, onRight: string): this;
76
- similar(field: string, vector: number[], options: {
77
- k: number;
78
- filter?: {
79
- key: string;
80
- value: string;
81
- };
70
+ leftJoin(table: string, alias: string, onLeft: string, onRight: string): this;
71
+ group(fields: string | string[]): this;
72
+ groupBy(fields: string | string[]): this;
73
+ having(field: string, op: TableWhereOp, value: TableWhereValue): this;
74
+ near(field: string, vector: number[], options?: {
75
+ k?: number;
76
+ threshold?: number;
77
+ }): this;
78
+ similar(field: string, vector: number[], options?: {
79
+ k?: number;
80
+ threshold?: number;
82
81
  }): this;
83
- private parseSimilarityPk;
84
82
  run(): Promise<LuxResult<T[] | T>>;
85
83
  then<TFulfilled = LuxResult<T[] | T>, TRejected = never>(onfulfilled?: ((value: LuxResult<T[] | T>) => TFulfilled | PromiseLike<TFulfilled>) | null, onrejected?: ((reason: unknown) => TRejected | PromiseLike<TRejected>) | null): Promise<TFulfilled | TRejected>;
86
84
  insert(data: Record<string, unknown>): Promise<LuxResult<number>>;
@@ -31,6 +31,14 @@ export interface TableRow {
31
31
  id?: number | string;
32
32
  [field: string]: unknown;
33
33
  }
34
+ export type LuxInferRow<T> = T extends readonly (infer Row)[] ? Row : T;
35
+ export type LuxTypedRow<T> = LuxInferRow<T> extends object ? LuxInferRow<T> : TableRow;
36
+ export type LuxAggregateValue = number | string;
37
+ export type LuxAggregateRow<Aliases extends string = string> = Record<Aliases, LuxAggregateValue>;
38
+ export interface LuxSimilarity {
39
+ _similarity: number | string;
40
+ }
41
+ export type LuxNearRow<T extends object = Record<string, unknown>> = T & LuxSimilarity;
34
42
  export interface LuxError {
35
43
  code: string;
36
44
  message: string;
@@ -52,7 +60,7 @@ export interface TableSchema<T> {
52
60
  safeParse?: (input: unknown) => SchemaSafeParse<T>;
53
61
  }
54
62
  export type TableChangeType = 'insert' | 'update' | 'delete' | 'change' | 'error';
55
- export interface TableChangeEvent<T extends TableRow> {
63
+ export interface TableChangeEvent<T extends object = TableRow> {
56
64
  type: Exclude<TableChangeType, 'error'>;
57
65
  table: string;
58
66
  pk: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@luxdb/sdk",
3
- "version": "1.4.1",
4
- "description": "Lux SDK - ioredis extended with vector search, time series, and realtime key subscriptions",
3
+ "version": "1.4.3",
4
+ "description": "Official Lux TypeScript SDK for app data, auth, tables, vectors, realtime, and Redis-compatible direct access",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
7
7
  "types": "./dist/types/index.d.ts",
@@ -59,5 +59,5 @@
59
59
  "url": "https://github.com/lux-db/lux",
60
60
  "directory": "sdk"
61
61
  },
62
- "keywords": ["lux", "redis", "vector", "search", "database", "ioredis", "similarity", "timeseries", "realtime", "subscriptions"]
62
+ "keywords": ["lux", "database", "application-database", "auth", "tables", "vectors", "realtime", "redis", "cache", "queues", "timeseries"]
63
63
  }