@xylex-group/athena 1.0.2 → 1.0.4

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
@@ -243,7 +243,7 @@ export function UsersPanel() {
243
243
 
244
244
  The hook returns `fetchGateway`, `insertGateway`, `updateGateway`, `deleteGateway`, `isLoading`, `error`, `lastRequest`, `lastResponse`, and `baseUrl`.
245
245
 
246
- Hook config options mirror the client options: `baseUrl`, `apiKey`, `stripNulls`, `headers`, `userId`, `companyId`, `organizationId`, `supabaseUrl`, `supabaseKey`, `publishEvent`.
246
+ Hook config options mirror the client options: `baseUrl`, `apiKey`, `headers`, `userId`, `organizationId`, `publishEvent`.
247
247
 
248
248
  ## User context headers
249
249
 
@@ -251,13 +251,14 @@ Pass user and tenant context to every request without repeating it on each call:
251
251
 
252
252
  ```ts
253
253
  const athena = createClient("https://athena-db.com", process.env.ATHENA_API_KEY, {
254
- userId: currentUser.id,
255
- companyId: currentUser.companyId,
256
- organizationId: currentUser.organizationId,
254
+ headers: {
255
+ "X-User-Id": currentUser.id,
256
+ "X-Organization-Id": currentUser.organizationId ?? "",
257
+ },
257
258
  });
258
259
  ```
259
260
 
260
- These are sent as `X-User-Id`, `X-Company-Id`, and `X-Organization-Id` request headers. You can override them per-call by passing the same options to `.select()` or any mutation method.
261
+ Or pass per-call via options. The Athena server interprets `url` and `key` based on the backend type (Supabase, PostgREST, etc.).
261
262
 
262
263
  ## Custom headers
263
264
 
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AthenaGatewayCallOptions, a as AthenaConditionValue, b as AthenaConditionArrayValue, c as AthenaConditionOperator } from './types-DzCf3v76.mjs';
2
- export { d as AthenaDeletePayload, e as AthenaFetchPayload, f as AthenaGatewayBaseOptions, g as AthenaGatewayCallLog, h as AthenaGatewayCondition, i as AthenaGatewayEndpointPath, j as AthenaGatewayHookConfig, k as AthenaGatewayHookResult, l as AthenaGatewayMethod, m as AthenaGatewayResponse, n as AthenaGatewayResponseLog, o as AthenaInsertPayload, p as AthenaUpdatePayload } from './types-DzCf3v76.mjs';
1
+ import { B as BackendConfig, a as BackendType, A as AthenaConditionValue, b as AthenaConditionArrayValue, c as AthenaConditionOperator, d as AthenaGatewayCallOptions } from './types-D0uYdUea.mjs';
2
+ export { e as Backend } from './types-D0uYdUea.mjs';
3
3
 
4
4
  interface SupabaseResult<T> {
5
5
  data: T | null;
@@ -17,35 +17,46 @@ interface MutationQuery<Result> extends PromiseLike<SupabaseResult<Result>> {
17
17
  catch<TResult = never>(onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | undefined | null): Promise<SupabaseResult<Result> | TResult>;
18
18
  finally(onfinally?: (() => void) | undefined | null): Promise<SupabaseResult<Result>>;
19
19
  }
20
- interface TableQueryBuilder<Row> {
21
- select<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T>>;
20
+ /** Shared filter chain - supports eq, limit, etc. in any order relative to select/update */
21
+ interface FilterChain<Self> {
22
+ eq(column: string, value: AthenaConditionValue): Self;
23
+ match(filters: Record<string, AthenaConditionValue>): Self;
24
+ range(from: number, to: number): Self;
25
+ limit(count: number): Self;
26
+ offset(count: number): Self;
27
+ gt(column: string, value: AthenaConditionValue): Self;
28
+ gte(column: string, value: AthenaConditionValue): Self;
29
+ lt(column: string, value: AthenaConditionValue): Self;
30
+ lte(column: string, value: AthenaConditionValue): Self;
31
+ neq(column: string, value: AthenaConditionValue): Self;
32
+ like(column: string, value: AthenaConditionValue): Self;
33
+ ilike(column: string, value: AthenaConditionValue): Self;
34
+ is(column: string, value: AthenaConditionValue): Self;
35
+ in(column: string, values: AthenaConditionArrayValue): Self;
36
+ contains(column: string, values: AthenaConditionArrayValue): Self;
37
+ containedBy(column: string, values: AthenaConditionArrayValue): Self;
38
+ not(columnOrExpression: string, operator?: AthenaConditionOperator, value?: AthenaConditionValue): Self;
39
+ or(expression: string): Self;
40
+ }
41
+ /** Chain returned by select() - supports filters and single/maybeSingle before execution */
42
+ interface SelectChain<Row> extends FilterChain<SelectChain<Row>>, PromiseLike<SupabaseResult<Row[]>> {
43
+ single<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T | null>>;
44
+ maybeSingle<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T | null>>;
45
+ }
46
+ /** Chain returned by update() - supports filters before execution, plus select/returning */
47
+ interface UpdateChain<Row> extends FilterChain<UpdateChain<Row>>, MutationQuery<Row[]> {
48
+ }
49
+ interface TableQueryBuilder<Row> extends FilterChain<TableQueryBuilder<Row>> {
50
+ select<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): SelectChain<T>;
22
51
  insert(values: Row | Row[], options?: AthenaGatewayCallOptions): MutationQuery<Row | Row[]>;
23
52
  upsert(values: Row | Row[], options?: AthenaGatewayCallOptions & {
24
53
  updateBody?: Partial<Row>;
25
54
  onConflict?: string | string[];
26
55
  }): MutationQuery<Row | Row[]>;
27
- update(values: Partial<Row>, options?: AthenaGatewayCallOptions): MutationQuery<Row[]>;
56
+ update(values: Partial<Row>, options?: AthenaGatewayCallOptions): UpdateChain<Row>;
28
57
  delete(options?: AthenaGatewayCallOptions & {
29
58
  resourceId?: string;
30
59
  }): MutationQuery<Row | null>;
31
- eq(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
32
- match(filters: Record<string, AthenaConditionValue>): TableQueryBuilder<Row>;
33
- range(from: number, to: number): TableQueryBuilder<Row>;
34
- limit(count: number): TableQueryBuilder<Row>;
35
- offset(count: number): TableQueryBuilder<Row>;
36
- gt(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
37
- gte(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
38
- lt(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
39
- lte(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
40
- neq(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
41
- like(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
42
- ilike(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
43
- is(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
44
- in(column: string, values: AthenaConditionArrayValue): TableQueryBuilder<Row>;
45
- contains(column: string, values: AthenaConditionArrayValue): TableQueryBuilder<Row>;
46
- containedBy(column: string, values: AthenaConditionArrayValue): TableQueryBuilder<Row>;
47
- not(columnOrExpression: string, operator?: AthenaConditionOperator, value?: AthenaConditionValue): TableQueryBuilder<Row>;
48
- or(expression: string): TableQueryBuilder<Row>;
49
60
  single<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T | null>>;
50
61
  maybeSingle<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T | null>>;
51
62
  reset(): TableQueryBuilder<Row>;
@@ -53,6 +64,21 @@ interface TableQueryBuilder<Row> {
53
64
  interface SupabaseClient {
54
65
  from<Row = unknown>(table: string): TableQueryBuilder<Row>;
55
66
  }
56
- declare function createClient(url: string, apiKey: string, options?: AthenaGatewayCallOptions): SupabaseClient;
67
+ interface AthenaClientBuilder {
68
+ url(url: string): AthenaClientBuilder;
69
+ key(apiKey: string): AthenaClientBuilder;
70
+ backend(backend: BackendConfig | BackendType): AthenaClientBuilder;
71
+ client(clientName: string): AthenaClientBuilder;
72
+ headers(headers: Record<string, string>): AthenaClientBuilder;
73
+ healthTracking(enabled: boolean): AthenaClientBuilder;
74
+ build(): SupabaseClient;
75
+ }
76
+ declare const AthenaClient: {
77
+ builder(): AthenaClientBuilder;
78
+ /** Build client from env: ATHENA_SUPABASE_URL, ATHENA_SUPABASE_KEY (or SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY) */
79
+ fromSupabaseEnv(): SupabaseClient;
80
+ };
81
+ /** Create client (convenience wrapper; use AthenaClient.builder() for full control) */
82
+ declare function createClient(url: string, apiKey: string, options?: Pick<AthenaGatewayCallOptions, 'client' | 'headers' | 'backend'>): SupabaseClient;
57
83
 
58
- export { AthenaGatewayCallOptions, type SupabaseClient, type SupabaseResult, type TableQueryBuilder, createClient };
84
+ export { AthenaClient, AthenaGatewayCallOptions, BackendConfig, BackendType, type SupabaseClient, type SupabaseResult, type TableQueryBuilder, createClient };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AthenaGatewayCallOptions, a as AthenaConditionValue, b as AthenaConditionArrayValue, c as AthenaConditionOperator } from './types-DzCf3v76.js';
2
- export { d as AthenaDeletePayload, e as AthenaFetchPayload, f as AthenaGatewayBaseOptions, g as AthenaGatewayCallLog, h as AthenaGatewayCondition, i as AthenaGatewayEndpointPath, j as AthenaGatewayHookConfig, k as AthenaGatewayHookResult, l as AthenaGatewayMethod, m as AthenaGatewayResponse, n as AthenaGatewayResponseLog, o as AthenaInsertPayload, p as AthenaUpdatePayload } from './types-DzCf3v76.js';
1
+ import { B as BackendConfig, a as BackendType, A as AthenaConditionValue, b as AthenaConditionArrayValue, c as AthenaConditionOperator, d as AthenaGatewayCallOptions } from './types-D0uYdUea.js';
2
+ export { e as Backend } from './types-D0uYdUea.js';
3
3
 
4
4
  interface SupabaseResult<T> {
5
5
  data: T | null;
@@ -17,35 +17,46 @@ interface MutationQuery<Result> extends PromiseLike<SupabaseResult<Result>> {
17
17
  catch<TResult = never>(onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | undefined | null): Promise<SupabaseResult<Result> | TResult>;
18
18
  finally(onfinally?: (() => void) | undefined | null): Promise<SupabaseResult<Result>>;
19
19
  }
20
- interface TableQueryBuilder<Row> {
21
- select<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T>>;
20
+ /** Shared filter chain - supports eq, limit, etc. in any order relative to select/update */
21
+ interface FilterChain<Self> {
22
+ eq(column: string, value: AthenaConditionValue): Self;
23
+ match(filters: Record<string, AthenaConditionValue>): Self;
24
+ range(from: number, to: number): Self;
25
+ limit(count: number): Self;
26
+ offset(count: number): Self;
27
+ gt(column: string, value: AthenaConditionValue): Self;
28
+ gte(column: string, value: AthenaConditionValue): Self;
29
+ lt(column: string, value: AthenaConditionValue): Self;
30
+ lte(column: string, value: AthenaConditionValue): Self;
31
+ neq(column: string, value: AthenaConditionValue): Self;
32
+ like(column: string, value: AthenaConditionValue): Self;
33
+ ilike(column: string, value: AthenaConditionValue): Self;
34
+ is(column: string, value: AthenaConditionValue): Self;
35
+ in(column: string, values: AthenaConditionArrayValue): Self;
36
+ contains(column: string, values: AthenaConditionArrayValue): Self;
37
+ containedBy(column: string, values: AthenaConditionArrayValue): Self;
38
+ not(columnOrExpression: string, operator?: AthenaConditionOperator, value?: AthenaConditionValue): Self;
39
+ or(expression: string): Self;
40
+ }
41
+ /** Chain returned by select() - supports filters and single/maybeSingle before execution */
42
+ interface SelectChain<Row> extends FilterChain<SelectChain<Row>>, PromiseLike<SupabaseResult<Row[]>> {
43
+ single<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T | null>>;
44
+ maybeSingle<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T | null>>;
45
+ }
46
+ /** Chain returned by update() - supports filters before execution, plus select/returning */
47
+ interface UpdateChain<Row> extends FilterChain<UpdateChain<Row>>, MutationQuery<Row[]> {
48
+ }
49
+ interface TableQueryBuilder<Row> extends FilterChain<TableQueryBuilder<Row>> {
50
+ select<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): SelectChain<T>;
22
51
  insert(values: Row | Row[], options?: AthenaGatewayCallOptions): MutationQuery<Row | Row[]>;
23
52
  upsert(values: Row | Row[], options?: AthenaGatewayCallOptions & {
24
53
  updateBody?: Partial<Row>;
25
54
  onConflict?: string | string[];
26
55
  }): MutationQuery<Row | Row[]>;
27
- update(values: Partial<Row>, options?: AthenaGatewayCallOptions): MutationQuery<Row[]>;
56
+ update(values: Partial<Row>, options?: AthenaGatewayCallOptions): UpdateChain<Row>;
28
57
  delete(options?: AthenaGatewayCallOptions & {
29
58
  resourceId?: string;
30
59
  }): MutationQuery<Row | null>;
31
- eq(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
32
- match(filters: Record<string, AthenaConditionValue>): TableQueryBuilder<Row>;
33
- range(from: number, to: number): TableQueryBuilder<Row>;
34
- limit(count: number): TableQueryBuilder<Row>;
35
- offset(count: number): TableQueryBuilder<Row>;
36
- gt(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
37
- gte(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
38
- lt(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
39
- lte(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
40
- neq(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
41
- like(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
42
- ilike(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
43
- is(column: string, value: AthenaConditionValue): TableQueryBuilder<Row>;
44
- in(column: string, values: AthenaConditionArrayValue): TableQueryBuilder<Row>;
45
- contains(column: string, values: AthenaConditionArrayValue): TableQueryBuilder<Row>;
46
- containedBy(column: string, values: AthenaConditionArrayValue): TableQueryBuilder<Row>;
47
- not(columnOrExpression: string, operator?: AthenaConditionOperator, value?: AthenaConditionValue): TableQueryBuilder<Row>;
48
- or(expression: string): TableQueryBuilder<Row>;
49
60
  single<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T | null>>;
50
61
  maybeSingle<T = Row>(columns?: string | string[], options?: AthenaGatewayCallOptions): Promise<SupabaseResult<T | null>>;
51
62
  reset(): TableQueryBuilder<Row>;
@@ -53,6 +64,21 @@ interface TableQueryBuilder<Row> {
53
64
  interface SupabaseClient {
54
65
  from<Row = unknown>(table: string): TableQueryBuilder<Row>;
55
66
  }
56
- declare function createClient(url: string, apiKey: string, options?: AthenaGatewayCallOptions): SupabaseClient;
67
+ interface AthenaClientBuilder {
68
+ url(url: string): AthenaClientBuilder;
69
+ key(apiKey: string): AthenaClientBuilder;
70
+ backend(backend: BackendConfig | BackendType): AthenaClientBuilder;
71
+ client(clientName: string): AthenaClientBuilder;
72
+ headers(headers: Record<string, string>): AthenaClientBuilder;
73
+ healthTracking(enabled: boolean): AthenaClientBuilder;
74
+ build(): SupabaseClient;
75
+ }
76
+ declare const AthenaClient: {
77
+ builder(): AthenaClientBuilder;
78
+ /** Build client from env: ATHENA_SUPABASE_URL, ATHENA_SUPABASE_KEY (or SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY) */
79
+ fromSupabaseEnv(): SupabaseClient;
80
+ };
81
+ /** Create client (convenience wrapper; use AthenaClient.builder() for full control) */
82
+ declare function createClient(url: string, apiKey: string, options?: Pick<AthenaGatewayCallOptions, 'client' | 'headers' | 'backend'>): SupabaseClient;
57
83
 
58
- export { AthenaGatewayCallOptions, type SupabaseClient, type SupabaseResult, type TableQueryBuilder, createClient };
84
+ export { AthenaClient, AthenaGatewayCallOptions, BackendConfig, BackendType, type SupabaseClient, type SupabaseResult, type TableQueryBuilder, createClient };
package/dist/index.js CHANGED
@@ -15,31 +15,32 @@ function normalizeHeaderValue(value) {
15
15
  return value ? value : void 0;
16
16
  }
17
17
  function buildHeaders(config, options) {
18
- const mergedStripNulls = options?.stripNulls ?? config.stripNulls ?? true;
19
- const finalClient = options?.client ?? config.client ?? DEFAULT_CLIENT;
20
- const finalApiKey = options?.apiKey ?? config.apiKey;
21
- const finalSupabaseUrl = options?.supabaseUrl ?? config.supabaseUrl;
22
- const finalSupabaseKey = options?.supabaseKey ?? config.supabaseKey;
23
- const finalPublishEvent = options?.publishEvent ?? config.publishEvent;
18
+ const mergedStripNulls = options?.stripNulls ?? true;
24
19
  const extraHeaders = {
25
20
  ...config.headers ?? {},
26
21
  ...options?.headers ?? {}
27
22
  };
23
+ const headerClient = extraHeaders["x-athena-client"] ?? extraHeaders["X-Athena-Client"];
24
+ const finalClient = options?.client ?? config.client ?? (typeof headerClient === "string" ? headerClient : void 0) ?? DEFAULT_CLIENT;
25
+ const finalApiKey = options?.apiKey ?? config.apiKey;
26
+ const finalPublishEvent = options?.publishEvent ?? config.publishEvent;
28
27
  const headers = {
29
28
  "Content-Type": "application/json"
30
29
  };
31
30
  if (options?.userId ?? config.userId) {
32
31
  headers["X-User-Id"] = options?.userId ?? config.userId ?? "";
33
32
  }
34
- if (options?.companyId ?? config.companyId) {
35
- headers["X-Company-Id"] = options?.companyId ?? config.companyId ?? "";
36
- }
37
33
  if (options?.organizationId ?? config.organizationId) {
38
34
  headers["X-Organization-Id"] = options?.organizationId ?? config.organizationId ?? "";
39
35
  }
40
36
  if (finalClient) {
41
37
  headers["X-Athena-Client"] = finalClient;
42
38
  }
39
+ const finalBackend = options?.backend ?? config.backend;
40
+ if (finalBackend) {
41
+ const type = typeof finalBackend === "string" ? finalBackend : finalBackend.type;
42
+ if (type) headers["X-Backend-Type"] = type;
43
+ }
43
44
  if (typeof mergedStripNulls === "boolean") {
44
45
  headers["X-Strip-Nulls"] = mergedStripNulls ? "true" : "false";
45
46
  }
@@ -50,13 +51,9 @@ function buildHeaders(config, options) {
50
51
  headers["apikey"] = finalApiKey;
51
52
  headers["x-api-key"] = headers["x-api-key"] ?? finalApiKey;
52
53
  }
53
- if (finalSupabaseUrl) {
54
- headers["x-supabase-url"] = finalSupabaseUrl;
55
- }
56
- if (finalSupabaseKey) {
57
- headers["x-supabase-key"] = finalSupabaseKey;
58
- }
54
+ const athenaClientKeys = ["x-athena-client", "X-Athena-Client"];
59
55
  Object.entries(extraHeaders).forEach(([key, value]) => {
56
+ if (athenaClientKeys.includes(key)) return;
60
57
  const normalized = normalizeHeaderValue(value);
61
58
  if (normalized) {
62
59
  headers[key] = normalized;
@@ -196,115 +193,145 @@ function stringifyFilterValue(value) {
196
193
  }
197
194
  return String(value);
198
195
  }
199
- function createTableBuilder(tableName, client) {
200
- const state = {
201
- conditions: []
202
- };
203
- const addCondition = (operator, column, value) => {
204
- const condition = { operator };
205
- if (column) condition.column = column;
206
- if (value !== void 0) condition.value = value;
207
- state.conditions.push(condition);
208
- };
209
- const builder = {
210
- reset() {
211
- state.conditions = [];
212
- state.limit = void 0;
213
- state.offset = void 0;
214
- return builder;
196
+ function createFilterMethods(state, addCondition, self) {
197
+ return {
198
+ eq(column, value) {
199
+ addCondition("eq", column, value);
200
+ return self;
201
+ },
202
+ match(filters) {
203
+ Object.entries(filters).forEach(([column, value]) => addCondition("eq", column, value));
204
+ return self;
215
205
  },
216
206
  range(from, to) {
217
207
  state.offset = from;
218
208
  state.limit = to - from + 1;
219
- return builder;
209
+ return self;
220
210
  },
221
211
  limit(count) {
222
212
  state.limit = count;
223
- return builder;
213
+ return self;
224
214
  },
225
215
  offset(count) {
226
216
  state.offset = count;
227
- return builder;
228
- },
229
- match(filters) {
230
- Object.entries(filters).forEach(([column, value]) => {
231
- addCondition("eq", column, value);
232
- });
233
- return builder;
234
- },
235
- eq(column, value) {
236
- addCondition("eq", column, value);
237
- return builder;
217
+ return self;
238
218
  },
239
219
  gt(column, value) {
240
220
  addCondition("gt", column, value);
241
- return builder;
221
+ return self;
242
222
  },
243
223
  gte(column, value) {
244
224
  addCondition("gte", column, value);
245
- return builder;
225
+ return self;
246
226
  },
247
227
  lt(column, value) {
248
228
  addCondition("lt", column, value);
249
- return builder;
229
+ return self;
250
230
  },
251
231
  lte(column, value) {
252
232
  addCondition("lte", column, value);
253
- return builder;
233
+ return self;
254
234
  },
255
235
  neq(column, value) {
256
236
  addCondition("neq", column, value);
257
- return builder;
237
+ return self;
258
238
  },
259
239
  like(column, value) {
260
240
  addCondition("like", column, value);
261
- return builder;
241
+ return self;
262
242
  },
263
243
  ilike(column, value) {
264
244
  addCondition("ilike", column, value);
265
- return builder;
245
+ return self;
266
246
  },
267
247
  is(column, value) {
268
248
  addCondition("is", column, value);
269
- return builder;
249
+ return self;
270
250
  },
271
251
  in(column, values) {
272
252
  addCondition("in", column, values);
273
- return builder;
253
+ return self;
274
254
  },
275
255
  contains(column, values) {
276
256
  addCondition("contains", column, values);
277
- return builder;
257
+ return self;
278
258
  },
279
259
  containedBy(column, values) {
280
260
  addCondition("containedBy", column, values);
281
- return builder;
261
+ return self;
282
262
  },
283
263
  not(columnOrExpression, operator, value) {
284
- if (operator && value !== void 0) {
264
+ if (operator != null && value !== void 0) {
285
265
  addCondition("not", void 0, `${columnOrExpression}.${operator}.${stringifyFilterValue(value)}`);
286
266
  } else {
287
267
  addCondition("not", void 0, columnOrExpression);
288
268
  }
289
- return builder;
269
+ return self;
290
270
  },
291
271
  or(expression) {
292
272
  addCondition("or", void 0, expression);
273
+ return self;
274
+ }
275
+ };
276
+ }
277
+ function createTableBuilder(tableName, client) {
278
+ const state = {
279
+ conditions: []
280
+ };
281
+ const addCondition = (operator, column, value) => {
282
+ const condition = { operator };
283
+ if (column) condition.column = column;
284
+ if (value !== void 0) condition.value = value;
285
+ state.conditions.push(condition);
286
+ };
287
+ const builder = {};
288
+ const filterMethods = createFilterMethods(state, addCondition, builder);
289
+ const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
290
+ const payload = {
291
+ table_name: tableName,
292
+ columns,
293
+ conditions: state.conditions.length ? [...state.conditions] : void 0,
294
+ limit: state.limit,
295
+ offset: state.offset,
296
+ strip_nulls: options?.stripNulls ?? true,
297
+ count: options?.count,
298
+ head: options?.head
299
+ };
300
+ const response = await client.fetchGateway(payload, options);
301
+ return formatResult(response);
302
+ };
303
+ const createSelectChain = (columns, options) => {
304
+ const chain = {};
305
+ const filterMethods2 = createFilterMethods(state, addCondition, chain);
306
+ Object.assign(chain, filterMethods2, {
307
+ async single(cols, opts) {
308
+ const r = await runSelect(cols ?? columns, opts ?? options);
309
+ return toSingleResult(r);
310
+ },
311
+ maybeSingle(cols, opts) {
312
+ return chain.single(cols, opts);
313
+ },
314
+ then(onfulfilled, onrejected) {
315
+ return runSelect(columns, options).then(onfulfilled, onrejected);
316
+ },
317
+ catch(onrejected) {
318
+ return runSelect(columns, options).catch(onrejected);
319
+ },
320
+ finally(onfinally) {
321
+ return runSelect(columns, options).finally(onfinally);
322
+ }
323
+ });
324
+ return chain;
325
+ };
326
+ Object.assign(builder, filterMethods, {
327
+ reset() {
328
+ state.conditions = [];
329
+ state.limit = void 0;
330
+ state.offset = void 0;
293
331
  return builder;
294
332
  },
295
- async select(columns = DEFAULT_COLUMNS, options) {
296
- const payload = {
297
- table_name: tableName,
298
- columns,
299
- conditions: state.conditions.length ? [...state.conditions] : void 0,
300
- limit: state.limit,
301
- offset: state.offset,
302
- strip_nulls: options?.stripNulls ?? true,
303
- count: options?.count,
304
- head: options?.head
305
- };
306
- const response = await client.fetchGateway(payload, options);
307
- return formatResult(response);
333
+ select(columns = DEFAULT_COLUMNS, options) {
334
+ return createSelectChain(columns, options);
308
335
  },
309
336
  insert(values, options) {
310
337
  const executeInsert = async (columns, selectOptions) => {
@@ -345,8 +372,8 @@ function createTableBuilder(tableName, client) {
345
372
  return createMutationQuery(executeUpsert);
346
373
  },
347
374
  update(values, options) {
348
- const filters = state.conditions.length ? [...state.conditions] : void 0;
349
375
  const executeUpdate = async (columns, selectOptions) => {
376
+ const filters = state.conditions.length ? [...state.conditions] : void 0;
350
377
  const mergedOptions = mergeOptions(options, selectOptions);
351
378
  const payload = {
352
379
  table_name: tableName,
@@ -358,7 +385,11 @@ function createTableBuilder(tableName, client) {
358
385
  const response = await client.updateGateway(payload, mergedOptions);
359
386
  return formatResult(response);
360
387
  };
361
- return createMutationQuery(executeUpdate);
388
+ const mutation = createMutationQuery(executeUpdate);
389
+ const updateChain = {};
390
+ const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
391
+ Object.assign(updateChain, filterMethods2, mutation);
392
+ return updateChain;
362
393
  },
363
394
  delete(options) {
364
395
  const filters = state.conditions.length ? [...state.conditions] : void 0;
@@ -386,23 +417,103 @@ function createTableBuilder(tableName, client) {
386
417
  async maybeSingle(columns, options) {
387
418
  return builder.single(columns, options);
388
419
  }
389
- };
420
+ });
390
421
  return builder;
391
422
  }
392
- function createClient(url, apiKey, options) {
393
- const { baseUrl: optBaseUrl, apiKey: optApiKey, ...restOptions } = options ?? {};
394
- const client = createAthenaGatewayClient({
395
- baseUrl: optBaseUrl ?? url,
396
- apiKey: optApiKey ?? apiKey,
397
- ...restOptions
423
+ function createClientFromConfig(config) {
424
+ const gateway = createAthenaGatewayClient({
425
+ baseUrl: config.baseUrl,
426
+ apiKey: config.apiKey,
427
+ client: config.client,
428
+ backend: config.backend,
429
+ headers: config.headers
398
430
  });
399
431
  return {
400
432
  from(table) {
401
- return createTableBuilder(table, client);
433
+ return createTableBuilder(table, gateway);
402
434
  }
403
435
  };
404
436
  }
437
+ var DEFAULT_BACKEND = { type: "athena" };
438
+ function toBackendConfig(b) {
439
+ if (!b) return DEFAULT_BACKEND;
440
+ return typeof b === "string" ? { type: b } : b;
441
+ }
442
+ var AthenaClient = {
443
+ builder() {
444
+ let url;
445
+ let key;
446
+ let backend = DEFAULT_BACKEND;
447
+ let clientName;
448
+ let headers;
449
+ const builder = {
450
+ url(u) {
451
+ url = u;
452
+ return builder;
453
+ },
454
+ key(k) {
455
+ key = k;
456
+ return builder;
457
+ },
458
+ backend(b) {
459
+ backend = toBackendConfig(b);
460
+ return builder;
461
+ },
462
+ client(c) {
463
+ clientName = c;
464
+ return builder;
465
+ },
466
+ headers(h) {
467
+ headers = h;
468
+ return builder;
469
+ },
470
+ healthTracking(enabled) {
471
+ return builder;
472
+ },
473
+ build() {
474
+ if (!url || !key) {
475
+ throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
476
+ }
477
+ return createClientFromConfig({
478
+ baseUrl: url,
479
+ apiKey: key,
480
+ client: clientName,
481
+ backend,
482
+ headers});
483
+ }
484
+ };
485
+ return builder;
486
+ },
487
+ /** Build client from env: ATHENA_SUPABASE_URL, ATHENA_SUPABASE_KEY (or SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY) */
488
+ fromSupabaseEnv() {
489
+ const url = process.env.ATHENA_SUPABASE_URL ?? process.env.SUPABASE_URL;
490
+ const key = process.env.ATHENA_SUPABASE_KEY ?? process.env.SUPABASE_SERVICE_ROLE_KEY;
491
+ if (!url || !key) {
492
+ throw new Error(
493
+ "ATHENA_SUPABASE_URL and ATHENA_SUPABASE_KEY (or SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY) are required"
494
+ );
495
+ }
496
+ return AthenaClient.builder().backend({ type: "supabase" }).url(url).key(key).build();
497
+ }
498
+ };
499
+ function createClient(url, apiKey, options) {
500
+ const b = AthenaClient.builder().url(url).key(apiKey).backend(toBackendConfig(options?.backend));
501
+ if (options?.client) b.client(options.client);
502
+ if (options?.headers && Object.keys(options.headers).length > 0) b.headers(options.headers);
503
+ return b.build();
504
+ }
505
+
506
+ // src/gateway/types.ts
507
+ var Backend = {
508
+ Athena: { type: "athena" },
509
+ Supabase: { type: "supabase" },
510
+ Postgrest: { type: "postgrest" },
511
+ PostgreSQL: { type: "postgresql" },
512
+ ScyllaDB: { type: "scylladb" }
513
+ };
405
514
 
515
+ exports.AthenaClient = AthenaClient;
516
+ exports.Backend = Backend;
406
517
  exports.createClient = createClient;
407
518
  //# sourceMappingURL=index.js.map
408
519
  //# sourceMappingURL=index.js.map