@luxdb/sdk 1.2.1 → 1.4.1

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.
@@ -0,0 +1,84 @@
1
+ export class LuxRealtimeManager {
2
+ constructor(client) {
3
+ this.connection = null;
4
+ this.initPromise = null;
5
+ this.nextHandlerId = 1;
6
+ this.handlersByPattern = new Map();
7
+ this.client = client;
8
+ }
9
+ async ensureConnection() {
10
+ if (this.connection)
11
+ return;
12
+ if (this.initPromise)
13
+ return this.initPromise;
14
+ this.initPromise = (async () => {
15
+ const sub = this.client.duplicate();
16
+ sub.on('error', () => { });
17
+ const dispatch = (event) => {
18
+ const handlers = this.handlersByPattern.get(event.pattern);
19
+ if (!handlers)
20
+ return;
21
+ for (const handler of handlers.values()) {
22
+ handler(event);
23
+ }
24
+ };
25
+ const dataHandler = sub._dataHandler || sub.dataHandler;
26
+ if (dataHandler && dataHandler.returnReply) {
27
+ const origReturn = dataHandler.returnReply.bind(dataHandler);
28
+ dataHandler.returnReply = (reply) => {
29
+ if (Array.isArray(reply) && reply.length === 4 && reply[0] === 'kmessage') {
30
+ dispatch({ pattern: reply[1], key: reply[2], operation: reply[3] });
31
+ return;
32
+ }
33
+ return origReturn(reply);
34
+ };
35
+ }
36
+ else {
37
+ const origEmit = sub.emit.bind(sub);
38
+ sub.emit = (event, ...args) => {
39
+ if (event === 'error' && args[0]?.message?.includes('Command queue state error')) {
40
+ const match = args[0].message.match(/Last reply: kmessage,([^,]+),([^,]+),(.+)/);
41
+ if (match) {
42
+ dispatch({ pattern: match[1], key: match[2], operation: match[3] });
43
+ return true;
44
+ }
45
+ }
46
+ return origEmit(event, ...args);
47
+ };
48
+ }
49
+ this.connection = sub;
50
+ })();
51
+ try {
52
+ await this.initPromise;
53
+ }
54
+ finally {
55
+ this.initPromise = null;
56
+ }
57
+ }
58
+ async subscribe(pattern, handler) {
59
+ await this.ensureConnection();
60
+ const id = this.nextHandlerId++;
61
+ let handlers = this.handlersByPattern.get(pattern);
62
+ const firstForPattern = !handlers;
63
+ if (!handlers) {
64
+ handlers = new Map();
65
+ this.handlersByPattern.set(pattern, handlers);
66
+ }
67
+ handlers.set(id, handler);
68
+ if (firstForPattern && this.connection) {
69
+ await this.connection.call('KSUB', pattern);
70
+ }
71
+ return () => {
72
+ const map = this.handlersByPattern.get(pattern);
73
+ if (!map)
74
+ return;
75
+ map.delete(id);
76
+ if (map.size === 0) {
77
+ this.handlersByPattern.delete(pattern);
78
+ if (this.connection) {
79
+ this.connection.call('KUNSUB', pattern).catch(() => { });
80
+ }
81
+ }
82
+ };
83
+ }
84
+ }
@@ -0,0 +1,37 @@
1
+ import { createClient } from './project.js';
2
+ const DEFAULT_COOKIE = 'lux-auth-session';
3
+ export function createServerClient(url, key, options) {
4
+ const storageKey = options.auth?.storageKey ?? DEFAULT_COOKIE;
5
+ const cookieOptions = options.auth?.cookieOptions ?? {
6
+ path: '/',
7
+ sameSite: 'lax',
8
+ };
9
+ const { cookieOptions: _cookieOptions, ...authOptions } = options.auth ?? {};
10
+ return createClient(url, key, {
11
+ fetch: options.fetch,
12
+ auth: {
13
+ persistSession: true,
14
+ autoRefreshToken: false,
15
+ ...authOptions,
16
+ storageKey,
17
+ storage: cookieStorage(options.cookies, cookieOptions),
18
+ },
19
+ });
20
+ }
21
+ function cookieStorage(cookies, options) {
22
+ return {
23
+ async getItem(key) {
24
+ return await cookies.get(key) ?? null;
25
+ },
26
+ async setItem(key, value) {
27
+ if (!cookies.set)
28
+ return;
29
+ await cookies.set(key, value, options);
30
+ },
31
+ async removeItem(key) {
32
+ if (!cookies.remove)
33
+ return;
34
+ await cookies.remove(key, { ...options, maxAge: 0, expires: new Date(0) });
35
+ },
36
+ };
37
+ }
@@ -0,0 +1,391 @@
1
+ import { err, ok, toLuxError } from './utils.js';
2
+ export class TableSubscription {
3
+ constructor(client, table, selectArgsBuilder, initError = null) {
4
+ this.handlers = {
5
+ change: [],
6
+ insert: [],
7
+ update: [],
8
+ delete: [],
9
+ error: [],
10
+ };
11
+ this.knownRows = new Map();
12
+ this.unsubscribeFn = null;
13
+ this.client = client;
14
+ this.table = table;
15
+ this.selectArgsBuilder = selectArgsBuilder;
16
+ this.initError = initError;
17
+ void this.start();
18
+ }
19
+ on(event, handler) {
20
+ this.handlers[event].push(handler);
21
+ return this;
22
+ }
23
+ async unsubscribe() {
24
+ if (this.unsubscribeFn) {
25
+ this.unsubscribeFn();
26
+ this.unsubscribeFn = null;
27
+ }
28
+ }
29
+ emitError(error) {
30
+ for (const handler of this.handlers.error) {
31
+ handler({ type: 'error', table: this.table, error });
32
+ }
33
+ }
34
+ emitChange(event) {
35
+ for (const handler of this.handlers.change)
36
+ handler(event);
37
+ for (const handler of this.handlers[event.type])
38
+ handler(event);
39
+ }
40
+ extractPkFromKey(key) {
41
+ const prefix = `_t:${this.table}:row:`;
42
+ if (!key.startsWith(prefix))
43
+ return null;
44
+ return key.slice(prefix.length);
45
+ }
46
+ async fetchMatches(extra) {
47
+ const args = this.selectArgsBuilder(extra);
48
+ const rows = await this.client._tselect(args);
49
+ return rows;
50
+ }
51
+ async start() {
52
+ if (this.initError) {
53
+ this.emitError(this.initError);
54
+ return;
55
+ }
56
+ try {
57
+ const initial = await this.fetchMatches();
58
+ for (const row of initial) {
59
+ if (row.id == null)
60
+ continue;
61
+ this.knownRows.set(String(row.id), row);
62
+ }
63
+ const pattern = `_t:${this.table}:row:*`;
64
+ this.unsubscribeFn = await this.client._subscribePattern(pattern, (raw) => {
65
+ void this.handleRawChange(raw);
66
+ });
67
+ }
68
+ catch (error) {
69
+ this.emitError(toLuxError(error, 'LUX_SUBSCRIBE_INIT_ERROR'));
70
+ }
71
+ }
72
+ async handleRawChange(raw) {
73
+ const pk = this.extractPkFromKey(raw.key);
74
+ if (!pk)
75
+ return;
76
+ try {
77
+ const previous = this.knownRows.get(pk) ?? null;
78
+ const rows = await this.fetchMatches([{ field: 'id', op: '=', value: pk }]);
79
+ const next = rows[0] ?? null;
80
+ if (!previous && !next)
81
+ return;
82
+ if (!previous && next) {
83
+ this.knownRows.set(pk, next);
84
+ this.emitChange({
85
+ type: 'insert',
86
+ table: this.table,
87
+ pk,
88
+ operation: raw.operation,
89
+ new: next,
90
+ old: null,
91
+ raw,
92
+ });
93
+ return;
94
+ }
95
+ if (previous && !next) {
96
+ this.knownRows.delete(pk);
97
+ this.emitChange({
98
+ type: 'delete',
99
+ table: this.table,
100
+ pk,
101
+ operation: raw.operation,
102
+ new: null,
103
+ old: previous,
104
+ raw,
105
+ });
106
+ return;
107
+ }
108
+ if (!previous || !next)
109
+ return;
110
+ this.knownRows.set(pk, next);
111
+ const changed = Object.keys(next).filter((key) => previous[key] !== next[key]);
112
+ this.emitChange({
113
+ type: 'update',
114
+ table: this.table,
115
+ pk,
116
+ operation: raw.operation,
117
+ new: next,
118
+ old: previous,
119
+ changed,
120
+ raw,
121
+ });
122
+ }
123
+ catch (error) {
124
+ this.emitError(toLuxError(error, 'LUX_SUBSCRIBE_EVENT_ERROR'));
125
+ }
126
+ }
127
+ }
128
+ export class TableQueryBuilder {
129
+ constructor(client, name, options) {
130
+ this.conditions = [];
131
+ this.selectClause = '*';
132
+ this.expectSingle = false;
133
+ this.client = client;
134
+ this.name = name;
135
+ this.schema = options?.schema;
136
+ }
137
+ validateRow(row) {
138
+ if (!this.schema)
139
+ return row;
140
+ if (this.schema.safeParse) {
141
+ const parsed = this.schema.safeParse(row);
142
+ if (!parsed.success) {
143
+ throw new Error('row failed schema validation');
144
+ }
145
+ return parsed.data;
146
+ }
147
+ if (this.schema.parse) {
148
+ return this.schema.parse(row);
149
+ }
150
+ return row;
151
+ }
152
+ buildSelectArgs(extra) {
153
+ const args = [this.selectClause, 'FROM', this.name];
154
+ const allConditions = extra ? [...this.conditions, ...extra] : this.conditions;
155
+ if (this.joinClause) {
156
+ args.push('JOIN', this.joinClause.table, this.joinClause.alias, 'ON', this.joinClause.onLeft, '=', this.joinClause.onRight);
157
+ }
158
+ if (allConditions.length) {
159
+ args.push('WHERE');
160
+ for (let i = 0; i < allConditions.length; i++) {
161
+ const cond = allConditions[i];
162
+ args.push(cond.field, cond.op, String(cond.value));
163
+ if (i < allConditions.length - 1) {
164
+ args.push('AND');
165
+ }
166
+ }
167
+ }
168
+ if (this.orderField) {
169
+ args.push('ORDER', 'BY', this.orderField, this.orderDir || 'ASC');
170
+ }
171
+ if (this.limitCount != null) {
172
+ args.push('LIMIT', String(this.limitCount));
173
+ }
174
+ if (this.offsetCount != null) {
175
+ args.push('OFFSET', String(this.offsetCount));
176
+ }
177
+ return args;
178
+ }
179
+ select(columns = '*') {
180
+ this.selectClause = columns;
181
+ return this;
182
+ }
183
+ single() {
184
+ this.expectSingle = true;
185
+ if (this.limitCount == null) {
186
+ this.limitCount = 1;
187
+ }
188
+ return this;
189
+ }
190
+ where(field, op, value) {
191
+ this.conditions.push({ field, op, value });
192
+ return this;
193
+ }
194
+ eq(field, value) {
195
+ return this.where(field, '=', value);
196
+ }
197
+ neq(field, value) {
198
+ return this.where(field, '!=', value);
199
+ }
200
+ gt(field, value) {
201
+ return this.where(field, '>', value);
202
+ }
203
+ gte(field, value) {
204
+ return this.where(field, '>=', value);
205
+ }
206
+ lt(field, value) {
207
+ return this.where(field, '<', value);
208
+ }
209
+ lte(field, value) {
210
+ return this.where(field, '<=', value);
211
+ }
212
+ orderBy(field, dir = 'asc') {
213
+ this.orderField = field;
214
+ this.orderDir = dir.toUpperCase();
215
+ return this;
216
+ }
217
+ order(field, options = {}) {
218
+ return this.orderBy(field, options.ascending === false ? 'desc' : 'asc');
219
+ }
220
+ limit(n) {
221
+ this.limitCount = n;
222
+ return this;
223
+ }
224
+ offset(n) {
225
+ this.offsetCount = n;
226
+ return this;
227
+ }
228
+ join(table, alias, onLeft, onRight) {
229
+ this.joinClause = { table, alias, onLeft, onRight };
230
+ return this;
231
+ }
232
+ similar(field, vector, options) {
233
+ this.similarityClause = {
234
+ field,
235
+ vector,
236
+ k: options.k,
237
+ filter: options.filter,
238
+ };
239
+ return this;
240
+ }
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;
259
+ }
260
+ async run() {
261
+ 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
+ }
291
+ const validated = rows.map((row) => this.validateRow(row));
292
+ if (this.expectSingle) {
293
+ if (validated.length === 0) {
294
+ return err('NOT_FOUND', `No rows found in table '${this.name}'`);
295
+ }
296
+ return ok(validated[0]);
297
+ }
298
+ return ok(validated);
299
+ }
300
+ catch (error) {
301
+ return err('TSELECT_ERROR', `Failed to query table '${this.name}'`, toLuxError(error));
302
+ }
303
+ }
304
+ then(onfulfilled, onrejected) {
305
+ return this.run().then(onfulfilled, onrejected);
306
+ }
307
+ async insert(data) {
308
+ try {
309
+ if (this.schema) {
310
+ this.validateRow(data);
311
+ }
312
+ const args = [this.name];
313
+ for (const [k, v] of Object.entries(data)) {
314
+ args.push(k, String(v));
315
+ }
316
+ const result = await this.client.call('TINSERT', ...args);
317
+ return ok(parseInt(result, 10) || 0);
318
+ }
319
+ catch (error) {
320
+ return err('TINSERT_ERROR', `Failed to insert into '${this.name}'`, toLuxError(error));
321
+ }
322
+ }
323
+ async update(idOrData, data) {
324
+ try {
325
+ const hasExplicitId = data !== undefined;
326
+ const patch = hasExplicitId ? data : idOrData;
327
+ if (!hasExplicitId && this.conditions.length === 0) {
328
+ return err('MISSING_WHERE', 'update requires at least one filter');
329
+ }
330
+ const args = [this.name, 'SET'];
331
+ for (const [k, v] of Object.entries(patch)) {
332
+ args.push(k, String(v));
333
+ }
334
+ args.push('WHERE');
335
+ if (hasExplicitId) {
336
+ args.push('id', '=', String(idOrData));
337
+ }
338
+ else {
339
+ for (let i = 0; i < this.conditions.length; i++) {
340
+ const cond = this.conditions[i];
341
+ args.push(cond.field, cond.op, String(cond.value));
342
+ if (i < this.conditions.length - 1) {
343
+ args.push('AND');
344
+ }
345
+ }
346
+ }
347
+ const result = await this.client.call('TUPDATE', ...args);
348
+ return ok(Number(result) || 0);
349
+ }
350
+ catch (error) {
351
+ return err('TUPDATE_ERROR', `Failed to update '${this.name}'`, toLuxError(error));
352
+ }
353
+ }
354
+ async delete(...ids) {
355
+ try {
356
+ if (ids.length === 0) {
357
+ if (this.conditions.length === 0) {
358
+ return err('MISSING_WHERE', 'delete requires at least one filter');
359
+ }
360
+ const args = ['FROM', this.name, 'WHERE'];
361
+ for (let i = 0; i < this.conditions.length; i++) {
362
+ const cond = this.conditions[i];
363
+ args.push(cond.field, cond.op, String(cond.value));
364
+ if (i < this.conditions.length - 1) {
365
+ args.push('AND');
366
+ }
367
+ }
368
+ const result = await this.client.call('TDELETE', ...args);
369
+ return ok(Number(result) || 0);
370
+ }
371
+ let deleted = 0;
372
+ for (const id of ids) {
373
+ const result = await this.client.call('TDELETE', 'FROM', this.name, 'WHERE', 'id', '=', String(id));
374
+ deleted += Number(result) || 0;
375
+ }
376
+ return ok(deleted);
377
+ }
378
+ catch (error) {
379
+ return err('TDELETE_ERROR', `Failed to delete from '${this.name}'`, toLuxError(error));
380
+ }
381
+ }
382
+ 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
+ return new TableSubscription(this.client, this.name, (extra) => this.buildSelectArgs(extra));
390
+ }
391
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ export function ok(data) {
2
+ return { data, error: null };
3
+ }
4
+ export function err(code, message, details) {
5
+ return { data: null, error: { code, message, details } };
6
+ }
7
+ export function toLuxError(error, fallbackCode = 'LUX_SDK_ERROR') {
8
+ if (typeof error === 'object' && error && 'message' in error) {
9
+ return { code: fallbackCode, message: String(error.message), details: error };
10
+ }
11
+ return { code: fallbackCode, message: String(error) };
12
+ }
@@ -0,0 +1,163 @@
1
+ import type { LuxResult } from './types';
2
+ export interface LuxAuthUser {
3
+ id: string;
4
+ email: string;
5
+ phone?: string;
6
+ email_confirmed_at?: number | null;
7
+ phone_confirmed_at?: number | null;
8
+ last_sign_in_at?: number | null;
9
+ created_at?: number | null;
10
+ updated_at?: number | null;
11
+ user_metadata?: Record<string, unknown>;
12
+ app_metadata?: Record<string, unknown>;
13
+ }
14
+ export interface LuxAuthSession {
15
+ access_token: string;
16
+ token_type: 'bearer';
17
+ expires_in: number;
18
+ refresh_token: string;
19
+ user: LuxAuthUser;
20
+ expires_at?: number;
21
+ }
22
+ export interface LuxAuthSessionResult {
23
+ session: LuxAuthSession | null;
24
+ user: LuxAuthUser | null;
25
+ }
26
+ export interface LuxAuthKey {
27
+ id: string;
28
+ name: string;
29
+ kind: 'publishable' | 'secret';
30
+ prefix: string;
31
+ scopes: string[];
32
+ created_at?: number | null;
33
+ revoked_at?: number | null;
34
+ last_used_at?: number | null;
35
+ }
36
+ export interface LuxAuthOptions {
37
+ httpUrl?: string;
38
+ apiKey?: string;
39
+ authToken?: string;
40
+ fetch?: typeof fetch;
41
+ persistSession?: boolean;
42
+ autoRefreshToken?: boolean;
43
+ storage?: LuxAuthStorage | null;
44
+ storageKey?: string;
45
+ refreshMarginSeconds?: number;
46
+ }
47
+ export interface LuxSignUpOptions {
48
+ email: string;
49
+ password: string;
50
+ data?: Record<string, unknown>;
51
+ }
52
+ export interface LuxSignInOptions {
53
+ email: string;
54
+ password: string;
55
+ }
56
+ export type LuxOAuthProvider = 'google' | 'github';
57
+ export interface LuxSignInWithOAuthOptions {
58
+ provider: LuxOAuthProvider;
59
+ redirectTo?: string;
60
+ skipRedirect?: boolean;
61
+ }
62
+ export interface LuxOAuthUrl {
63
+ url: string;
64
+ }
65
+ export interface LuxCreateApiKeyOptions {
66
+ kind: 'publishable' | 'secret';
67
+ name?: string;
68
+ }
69
+ export interface LuxAuthProvider {
70
+ provider: LuxOAuthProvider;
71
+ enabled: boolean;
72
+ client_id: string;
73
+ redirect_uri: string;
74
+ scopes: string;
75
+ has_client_secret: boolean;
76
+ created_at?: number | null;
77
+ updated_at?: number | null;
78
+ }
79
+ export interface LuxUpsertProviderOptions {
80
+ provider: LuxOAuthProvider;
81
+ client_id: string;
82
+ client_secret?: string;
83
+ redirect_uri: string;
84
+ scopes?: string;
85
+ enabled?: boolean;
86
+ }
87
+ export type LuxAuthChangeEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'TOKEN_REFRESHED' | 'SIGNED_OUT' | 'SESSION_UPDATED';
88
+ export interface LuxAuthStorage {
89
+ getItem(key: string): string | null | Promise<string | null>;
90
+ setItem(key: string, value: string): void | Promise<void>;
91
+ removeItem(key: string): void | Promise<void>;
92
+ }
93
+ export type LuxAuthStateChangeCallback = (event: LuxAuthChangeEvent, session: LuxAuthSession | null) => void;
94
+ export interface LuxAuthSubscription {
95
+ unsubscribe(): void;
96
+ }
97
+ export declare class LuxAuthClient {
98
+ private httpUrl?;
99
+ private apiKey?;
100
+ private authToken?;
101
+ private fetchImpl;
102
+ private persistSession;
103
+ private autoRefreshToken;
104
+ private storage;
105
+ private storageKey;
106
+ private refreshMarginSeconds;
107
+ private currentSession;
108
+ private loadedSession;
109
+ private refreshTimer;
110
+ private listeners;
111
+ constructor(options?: LuxAuthOptions);
112
+ getSession(): Promise<LuxResult<{
113
+ session: LuxAuthSession | null;
114
+ }>>;
115
+ private getSessionValue;
116
+ getAccessToken(): Promise<string | undefined>;
117
+ setSession(session: LuxAuthSession | string | null): Promise<LuxResult<{
118
+ session: LuxAuthSession | null;
119
+ }>>;
120
+ private setSessionValue;
121
+ clearSession(): Promise<LuxResult<null>>;
122
+ private clearSessionValue;
123
+ onAuthStateChange(callback: LuxAuthStateChangeCallback): LuxAuthSubscription;
124
+ signUp(options: LuxSignUpOptions): Promise<LuxResult<LuxAuthSessionResult>>;
125
+ signInWithPassword(options: LuxSignInOptions): Promise<LuxResult<LuxAuthSessionResult>>;
126
+ signInWithOAuth(options: LuxSignInWithOAuthOptions): Promise<LuxResult<LuxOAuthUrl>>;
127
+ consumeOAuthRedirect(url?: string): Promise<LuxResult<LuxAuthSessionResult>>;
128
+ refreshSession(refreshToken: string): Promise<LuxResult<LuxAuthSessionResult>>;
129
+ getUser(session?: Pick<LuxAuthSession, 'access_token'> | string): Promise<LuxResult<{
130
+ user: LuxAuthUser | null;
131
+ }>>;
132
+ logout(sessionOrRefreshToken?: Pick<LuxAuthSession, 'access_token' | 'refresh_token'> | string): Promise<LuxResult<null>>;
133
+ signOut(): Promise<LuxResult<null>>;
134
+ listUsers(): Promise<LuxResult<LuxAuthUser[]>>;
135
+ grantCapability(userId: string, capability: string): Promise<LuxResult<{
136
+ id: string;
137
+ user_id: string;
138
+ capability: string;
139
+ created_at: string;
140
+ }>>;
141
+ listUserGrants(userId: string): Promise<LuxResult<string[]>>;
142
+ revokeGrant(grantId: string): Promise<LuxResult<null>>;
143
+ listApiKeys(): Promise<LuxResult<LuxAuthKey[]>>;
144
+ listProviders(): Promise<LuxResult<LuxAuthProvider[]>>;
145
+ upsertProvider(options: LuxUpsertProviderOptions): Promise<LuxResult<LuxAuthProvider>>;
146
+ createApiKey(options: LuxCreateApiKeyOptions): Promise<LuxResult<{
147
+ key: LuxAuthKey;
148
+ plain_key: string;
149
+ }>>;
150
+ revokeApiKey(keyId: string): Promise<LuxResult<null>>;
151
+ get<T = unknown>(path: string, session?: Pick<LuxAuthSession, 'access_token'> | string): Promise<LuxResult<T>>;
152
+ post<T = unknown>(path: string, body?: unknown, session?: Pick<LuxAuthSession, 'access_token'> | string): Promise<LuxResult<T>>;
153
+ put<T = unknown>(path: string, body?: unknown, session?: Pick<LuxAuthSession, 'access_token'> | string): Promise<LuxResult<T>>;
154
+ delete<T = unknown>(path: string, session?: Pick<LuxAuthSession, 'access_token'> | string): Promise<LuxResult<T>>;
155
+ private tokenFrom;
156
+ private loadStoredSession;
157
+ private saveSession;
158
+ private scheduleRefresh;
159
+ private clearRefreshTimer;
160
+ private emit;
161
+ private requestResult;
162
+ private requestRaw;
163
+ }
@@ -0,0 +1,4 @@
1
+ import { type LuxProjectOptions } from './project';
2
+ export interface LuxBrowserClientOptions extends Omit<LuxProjectOptions, 'url' | 'key'> {
3
+ }
4
+ export declare function createBrowserClient(url: string, key: string, options?: LuxBrowserClientOptions): import("./project").LuxProjectClient;