@xylex-group/athena 1.1.2 → 1.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 +53 -17
- package/dist/{types-DorEXMAz.d.cts → errors-DKNcLa5O.d.cts} +74 -7
- package/dist/{types-DorEXMAz.d.ts → errors-DKNcLa5O.d.ts} +74 -7
- package/dist/index.cjs +477 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -25
- package/dist/index.d.ts +62 -25
- package/dist/index.js +476 -72
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +290 -22
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +289 -23
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,19 +1,195 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/gateway/errors.ts
|
|
4
|
+
var AthenaGatewayError = class _AthenaGatewayError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
status;
|
|
7
|
+
endpoint;
|
|
8
|
+
method;
|
|
9
|
+
requestId;
|
|
10
|
+
hint;
|
|
11
|
+
causeDetail;
|
|
12
|
+
constructor(input) {
|
|
13
|
+
super(input.message);
|
|
14
|
+
this.name = "AthenaGatewayError";
|
|
15
|
+
this.code = input.code;
|
|
16
|
+
this.status = input.status ?? 0;
|
|
17
|
+
this.endpoint = input.endpoint;
|
|
18
|
+
this.method = input.method;
|
|
19
|
+
this.requestId = input.requestId;
|
|
20
|
+
this.hint = input.hint;
|
|
21
|
+
this.causeDetail = input.cause;
|
|
22
|
+
}
|
|
23
|
+
toDetails() {
|
|
24
|
+
return {
|
|
25
|
+
code: this.code,
|
|
26
|
+
message: this.message,
|
|
27
|
+
status: this.status,
|
|
28
|
+
endpoint: this.endpoint,
|
|
29
|
+
method: this.method,
|
|
30
|
+
requestId: this.requestId,
|
|
31
|
+
hint: this.hint,
|
|
32
|
+
cause: this.causeDetail
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
static fromResponse(response, fallback) {
|
|
36
|
+
const details = response.errorDetails;
|
|
37
|
+
if (details) {
|
|
38
|
+
return new _AthenaGatewayError({
|
|
39
|
+
code: details.code,
|
|
40
|
+
message: details.message,
|
|
41
|
+
status: details.status,
|
|
42
|
+
endpoint: details.endpoint ?? fallback.endpoint,
|
|
43
|
+
method: details.method ?? fallback.method,
|
|
44
|
+
requestId: details.requestId ?? fallback.requestId,
|
|
45
|
+
hint: details.hint,
|
|
46
|
+
cause: details.cause
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return new _AthenaGatewayError({
|
|
50
|
+
code: "HTTP_ERROR",
|
|
51
|
+
message: response.error ?? "Gateway request failed",
|
|
52
|
+
status: response.status,
|
|
53
|
+
endpoint: fallback.endpoint,
|
|
54
|
+
method: fallback.method,
|
|
55
|
+
requestId: fallback.requestId
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
function isAthenaGatewayError(error) {
|
|
60
|
+
return error instanceof AthenaGatewayError;
|
|
61
|
+
}
|
|
62
|
+
|
|
3
63
|
// src/gateway/client.ts
|
|
4
64
|
var DEFAULT_BASE_URL = "https://athena-db.com";
|
|
5
65
|
var DEFAULT_CLIENT = "railway_direct";
|
|
6
|
-
function
|
|
7
|
-
if (!
|
|
66
|
+
function parseResponseBody(rawText, contentType) {
|
|
67
|
+
if (!rawText) {
|
|
68
|
+
return { parsed: null, parseFailed: false };
|
|
69
|
+
}
|
|
70
|
+
const contentTypeSuggestsJson = contentType?.toLowerCase().includes("application/json") ?? false;
|
|
71
|
+
const looksJson = contentTypeSuggestsJson || rawText.startsWith("{") || rawText.startsWith("[");
|
|
72
|
+
if (!looksJson) {
|
|
73
|
+
return { parsed: rawText, parseFailed: false };
|
|
74
|
+
}
|
|
8
75
|
try {
|
|
9
|
-
return JSON.parse(
|
|
76
|
+
return { parsed: JSON.parse(rawText), parseFailed: false };
|
|
10
77
|
} catch {
|
|
11
|
-
return
|
|
78
|
+
return { parsed: rawText, parseFailed: true };
|
|
12
79
|
}
|
|
13
80
|
}
|
|
14
81
|
function normalizeHeaderValue(value) {
|
|
15
82
|
return value ? value : void 0;
|
|
16
83
|
}
|
|
84
|
+
function isRecord(value) {
|
|
85
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
86
|
+
}
|
|
87
|
+
function resolveRequestId(headers) {
|
|
88
|
+
return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
|
|
89
|
+
}
|
|
90
|
+
function resolveErrorMessage(payload, fallback) {
|
|
91
|
+
if (isRecord(payload)) {
|
|
92
|
+
const messageCandidates = [payload.error, payload.message, payload.details];
|
|
93
|
+
for (const candidate of messageCandidates) {
|
|
94
|
+
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
95
|
+
return candidate.trim();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (typeof payload === "string" && payload.trim().length > 0) {
|
|
100
|
+
return payload.trim();
|
|
101
|
+
}
|
|
102
|
+
return fallback;
|
|
103
|
+
}
|
|
104
|
+
function detailsFromError(error) {
|
|
105
|
+
return error.toDetails();
|
|
106
|
+
}
|
|
107
|
+
function toQueryScalar(value) {
|
|
108
|
+
if (value === null || value === void 0) return "null";
|
|
109
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
110
|
+
if (typeof value === "number") return Number.isFinite(value) ? String(value) : "null";
|
|
111
|
+
return String(value);
|
|
112
|
+
}
|
|
113
|
+
function toQueryArray(values) {
|
|
114
|
+
return `{${values.map(toQueryScalar).join(",")}}`;
|
|
115
|
+
}
|
|
116
|
+
function toRpcArgumentQueryValue(value) {
|
|
117
|
+
if (Array.isArray(value)) return toQueryArray(value);
|
|
118
|
+
if (value && typeof value === "object") return JSON.stringify(value);
|
|
119
|
+
return toQueryScalar(value);
|
|
120
|
+
}
|
|
121
|
+
function toRpcFilterQueryValue(filter) {
|
|
122
|
+
const value = filter.value;
|
|
123
|
+
switch (filter.operator) {
|
|
124
|
+
case "in": {
|
|
125
|
+
if (!Array.isArray(value)) {
|
|
126
|
+
throw new AthenaGatewayError({
|
|
127
|
+
code: "UNKNOWN_ERROR",
|
|
128
|
+
message: `RPC filter "${filter.column}" with operator "in" requires an array value`,
|
|
129
|
+
status: 0
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return `in.${toQueryArray(value)}`;
|
|
133
|
+
}
|
|
134
|
+
case "is":
|
|
135
|
+
return `is.${toQueryScalar(value)}`;
|
|
136
|
+
case "eq":
|
|
137
|
+
case "neq":
|
|
138
|
+
case "gt":
|
|
139
|
+
case "gte":
|
|
140
|
+
case "lt":
|
|
141
|
+
case "lte":
|
|
142
|
+
case "like":
|
|
143
|
+
case "ilike":
|
|
144
|
+
return `${filter.operator}.${toQueryScalar(value)}`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function buildRpcGetEndpoint(payload) {
|
|
148
|
+
const functionName = (payload.function_name ?? payload.function).trim();
|
|
149
|
+
if (!functionName) {
|
|
150
|
+
throw new AthenaGatewayError({
|
|
151
|
+
code: "UNKNOWN_ERROR",
|
|
152
|
+
message: "rpc requires a function name",
|
|
153
|
+
status: 0,
|
|
154
|
+
endpoint: "/gateway/rpc",
|
|
155
|
+
method: "GET"
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const query = new URLSearchParams();
|
|
159
|
+
if (payload.schema) query.set("schema", payload.schema);
|
|
160
|
+
if (payload.select) query.set("select", payload.select);
|
|
161
|
+
if (payload.count) query.set("count", payload.count);
|
|
162
|
+
if (payload.head) query.set("head", "true");
|
|
163
|
+
if (typeof payload.limit === "number") query.set("limit", String(payload.limit));
|
|
164
|
+
if (typeof payload.offset === "number") query.set("offset", String(payload.offset));
|
|
165
|
+
if (payload.order?.column) {
|
|
166
|
+
query.set(
|
|
167
|
+
"order",
|
|
168
|
+
payload.order.ascending === false ? `${payload.order.column}.desc` : payload.order.column
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
if (payload.args) {
|
|
172
|
+
for (const [key, value] of Object.entries(payload.args)) {
|
|
173
|
+
query.set(key, toRpcArgumentQueryValue(value));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (payload.filters?.length) {
|
|
177
|
+
for (const filter of payload.filters) {
|
|
178
|
+
if (payload.args && Object.prototype.hasOwnProperty.call(payload.args, filter.column)) {
|
|
179
|
+
throw new AthenaGatewayError({
|
|
180
|
+
code: "UNKNOWN_ERROR",
|
|
181
|
+
message: `RPC filter "${filter.column}" conflicts with RPC argument "${filter.column}" in GET mode`,
|
|
182
|
+
status: 0
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
query.set(filter.column, toRpcFilterQueryValue(filter));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const endpoint = `/rpc/${encodeURIComponent(functionName)}`;
|
|
189
|
+
const queryText = query.toString();
|
|
190
|
+
const withQuery = queryText ? `${endpoint}?${queryText}` : endpoint;
|
|
191
|
+
return withQuery;
|
|
192
|
+
}
|
|
17
193
|
function buildHeaders(config, options) {
|
|
18
194
|
const mergedStripNulls = options?.stripNulls ?? true;
|
|
19
195
|
const extraHeaders = {
|
|
@@ -66,31 +242,90 @@ async function callAthena(config, endpoint, method, payload, options) {
|
|
|
66
242
|
const url = `${baseUrl}${endpoint}`;
|
|
67
243
|
const headers = buildHeaders(config, options);
|
|
68
244
|
try {
|
|
69
|
-
const
|
|
245
|
+
const requestInit = {
|
|
70
246
|
method,
|
|
71
|
-
headers
|
|
72
|
-
|
|
73
|
-
|
|
247
|
+
headers
|
|
248
|
+
};
|
|
249
|
+
if (method !== "GET") {
|
|
250
|
+
requestInit.body = JSON.stringify(payload);
|
|
251
|
+
}
|
|
252
|
+
const response = await fetch(url, requestInit);
|
|
74
253
|
const rawText = await response.text();
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
254
|
+
const requestId = resolveRequestId(response.headers);
|
|
255
|
+
const parsedBody = parseResponseBody(
|
|
256
|
+
rawText ?? "",
|
|
257
|
+
response.headers.get("content-type")
|
|
258
|
+
);
|
|
259
|
+
if (parsedBody.parseFailed) {
|
|
260
|
+
const invalidJsonError = new AthenaGatewayError({
|
|
261
|
+
code: "INVALID_JSON",
|
|
262
|
+
message: "Gateway returned malformed JSON",
|
|
263
|
+
status: response.status,
|
|
264
|
+
endpoint,
|
|
265
|
+
method,
|
|
266
|
+
requestId,
|
|
267
|
+
hint: "Verify the gateway response body is valid JSON.",
|
|
268
|
+
cause: rawText.slice(0, 300)
|
|
269
|
+
});
|
|
270
|
+
return {
|
|
271
|
+
ok: false,
|
|
272
|
+
status: response.status,
|
|
273
|
+
data: null,
|
|
274
|
+
error: invalidJsonError.message,
|
|
275
|
+
errorDetails: detailsFromError(invalidJsonError),
|
|
276
|
+
raw: parsedBody.parsed
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
const parsed = parsedBody.parsed;
|
|
280
|
+
const parsedPayload = isRecord(parsed) ? parsed : null;
|
|
281
|
+
if (!response.ok) {
|
|
282
|
+
const httpError = new AthenaGatewayError({
|
|
283
|
+
code: "HTTP_ERROR",
|
|
284
|
+
message: resolveErrorMessage(
|
|
285
|
+
parsed,
|
|
286
|
+
`Athena gateway ${method} ${endpoint} failed with status ${response.status}`
|
|
287
|
+
),
|
|
288
|
+
status: response.status,
|
|
289
|
+
endpoint,
|
|
290
|
+
method,
|
|
291
|
+
requestId
|
|
292
|
+
});
|
|
293
|
+
return {
|
|
294
|
+
ok: false,
|
|
295
|
+
status: response.status,
|
|
296
|
+
data: null,
|
|
297
|
+
error: httpError.message,
|
|
298
|
+
errorDetails: detailsFromError(httpError),
|
|
299
|
+
raw: parsed
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const payloadData = parsedPayload && "data" in parsedPayload ? parsedPayload.data : parsed;
|
|
303
|
+
const payloadCount = parsedPayload && "count" in parsedPayload ? typeof parsedPayload.count === "number" || parsedPayload.count === null ? parsedPayload.count : void 0 : void 0;
|
|
80
304
|
return {
|
|
81
|
-
ok:
|
|
305
|
+
ok: true,
|
|
82
306
|
status: response.status,
|
|
83
307
|
data: payloadData ?? null,
|
|
84
|
-
|
|
308
|
+
count: payloadCount,
|
|
309
|
+
error: void 0,
|
|
310
|
+
errorDetails: null,
|
|
85
311
|
raw: parsed
|
|
86
312
|
};
|
|
87
313
|
} catch (callError) {
|
|
88
314
|
const message = callError instanceof Error ? callError.message : String(callError);
|
|
315
|
+
const networkError = new AthenaGatewayError({
|
|
316
|
+
code: "NETWORK_ERROR",
|
|
317
|
+
message: `Network error while calling ${method} ${endpoint}: ${message}`,
|
|
318
|
+
endpoint,
|
|
319
|
+
method,
|
|
320
|
+
cause: message,
|
|
321
|
+
hint: "Check gateway URL, DNS, and network reachability."
|
|
322
|
+
});
|
|
89
323
|
return {
|
|
90
324
|
ok: false,
|
|
91
325
|
status: 0,
|
|
92
326
|
data: null,
|
|
93
|
-
error: message,
|
|
327
|
+
error: networkError.message,
|
|
328
|
+
errorDetails: detailsFromError(networkError),
|
|
94
329
|
raw: null
|
|
95
330
|
};
|
|
96
331
|
}
|
|
@@ -112,19 +347,34 @@ function createAthenaGatewayClient(config = {}) {
|
|
|
112
347
|
},
|
|
113
348
|
deleteGateway(payload, options) {
|
|
114
349
|
return callAthena(config, "/gateway/delete", "DELETE", payload, options);
|
|
350
|
+
},
|
|
351
|
+
rpcGateway(payload, options) {
|
|
352
|
+
if (options?.get) {
|
|
353
|
+
const endpoint = buildRpcGetEndpoint(payload);
|
|
354
|
+
return callAthena(config, endpoint, "GET", null, options);
|
|
355
|
+
}
|
|
356
|
+
return callAthena(config, "/gateway/rpc", "POST", payload, options);
|
|
357
|
+
},
|
|
358
|
+
queryGateway(payload, options) {
|
|
359
|
+
return callAthena(config, "/gateway/query", "POST", payload, options);
|
|
115
360
|
}
|
|
116
361
|
};
|
|
117
362
|
}
|
|
118
363
|
|
|
119
|
-
// src/
|
|
364
|
+
// src/client.ts
|
|
120
365
|
var DEFAULT_COLUMNS = "*";
|
|
121
366
|
function formatResult(response) {
|
|
122
|
-
|
|
367
|
+
const result = {
|
|
123
368
|
data: response.data ?? null,
|
|
124
369
|
error: response.error ?? null,
|
|
370
|
+
errorDetails: response.errorDetails ?? null,
|
|
125
371
|
status: response.status,
|
|
126
372
|
raw: response.raw
|
|
127
373
|
};
|
|
374
|
+
if (response.count !== void 0) {
|
|
375
|
+
result.count = response.count;
|
|
376
|
+
}
|
|
377
|
+
return result;
|
|
128
378
|
}
|
|
129
379
|
function toSingleResult(response) {
|
|
130
380
|
const payload = response.data;
|
|
@@ -274,6 +524,133 @@ function createFilterMethods(state, addCondition, self) {
|
|
|
274
524
|
}
|
|
275
525
|
};
|
|
276
526
|
}
|
|
527
|
+
function toRpcSelect(columns) {
|
|
528
|
+
if (!columns) return void 0;
|
|
529
|
+
return Array.isArray(columns) ? columns.join(",") : columns;
|
|
530
|
+
}
|
|
531
|
+
function createRpcFilterMethods(filters, self) {
|
|
532
|
+
const addFilter = (operator, column, value) => {
|
|
533
|
+
filters.push({ column, operator, value });
|
|
534
|
+
};
|
|
535
|
+
return {
|
|
536
|
+
eq(column, value) {
|
|
537
|
+
addFilter("eq", column, value);
|
|
538
|
+
return self;
|
|
539
|
+
},
|
|
540
|
+
neq(column, value) {
|
|
541
|
+
addFilter("neq", column, value);
|
|
542
|
+
return self;
|
|
543
|
+
},
|
|
544
|
+
gt(column, value) {
|
|
545
|
+
addFilter("gt", column, value);
|
|
546
|
+
return self;
|
|
547
|
+
},
|
|
548
|
+
gte(column, value) {
|
|
549
|
+
addFilter("gte", column, value);
|
|
550
|
+
return self;
|
|
551
|
+
},
|
|
552
|
+
lt(column, value) {
|
|
553
|
+
addFilter("lt", column, value);
|
|
554
|
+
return self;
|
|
555
|
+
},
|
|
556
|
+
lte(column, value) {
|
|
557
|
+
addFilter("lte", column, value);
|
|
558
|
+
return self;
|
|
559
|
+
},
|
|
560
|
+
like(column, value) {
|
|
561
|
+
addFilter("like", column, value);
|
|
562
|
+
return self;
|
|
563
|
+
},
|
|
564
|
+
ilike(column, value) {
|
|
565
|
+
addFilter("ilike", column, value);
|
|
566
|
+
return self;
|
|
567
|
+
},
|
|
568
|
+
is(column, value) {
|
|
569
|
+
addFilter("is", column, value);
|
|
570
|
+
return self;
|
|
571
|
+
},
|
|
572
|
+
in(column, values) {
|
|
573
|
+
addFilter("in", column, values);
|
|
574
|
+
return self;
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function createRpcBuilder(functionName, args, baseOptions, client) {
|
|
579
|
+
const state = {
|
|
580
|
+
filters: []
|
|
581
|
+
};
|
|
582
|
+
let selectedColumns;
|
|
583
|
+
let selectedOptions;
|
|
584
|
+
let promise = null;
|
|
585
|
+
const executeRpc = async (columns, options) => {
|
|
586
|
+
const mergedOptions = mergeOptions(baseOptions, options);
|
|
587
|
+
const payload = {
|
|
588
|
+
function: functionName,
|
|
589
|
+
args,
|
|
590
|
+
schema: mergedOptions?.schema,
|
|
591
|
+
select: toRpcSelect(columns),
|
|
592
|
+
filters: state.filters.length ? [...state.filters] : void 0,
|
|
593
|
+
count: mergedOptions?.count,
|
|
594
|
+
head: mergedOptions?.head,
|
|
595
|
+
limit: state.limit,
|
|
596
|
+
offset: state.offset,
|
|
597
|
+
order: state.order
|
|
598
|
+
};
|
|
599
|
+
const response = await client.rpcGateway(payload, mergedOptions);
|
|
600
|
+
return formatResult(response);
|
|
601
|
+
};
|
|
602
|
+
const run = (columns, options) => {
|
|
603
|
+
const payloadColumns = columns ?? selectedColumns;
|
|
604
|
+
const payloadOptions = options ?? selectedOptions;
|
|
605
|
+
if (!promise) {
|
|
606
|
+
promise = executeRpc(payloadColumns, payloadOptions);
|
|
607
|
+
}
|
|
608
|
+
return promise;
|
|
609
|
+
};
|
|
610
|
+
const builder = {};
|
|
611
|
+
const filterMethods = createRpcFilterMethods(state.filters, builder);
|
|
612
|
+
Object.assign(builder, filterMethods, {
|
|
613
|
+
select(columns = selectedColumns, options) {
|
|
614
|
+
selectedColumns = columns;
|
|
615
|
+
selectedOptions = options ?? selectedOptions;
|
|
616
|
+
return run(columns, options);
|
|
617
|
+
},
|
|
618
|
+
async single(columns, options) {
|
|
619
|
+
const result = await run(columns, options);
|
|
620
|
+
return toSingleResult(result);
|
|
621
|
+
},
|
|
622
|
+
maybeSingle(columns, options) {
|
|
623
|
+
return builder.single(columns, options);
|
|
624
|
+
},
|
|
625
|
+
order(column, options) {
|
|
626
|
+
state.order = { column, ascending: options?.ascending ?? true };
|
|
627
|
+
return builder;
|
|
628
|
+
},
|
|
629
|
+
limit(count) {
|
|
630
|
+
state.limit = count;
|
|
631
|
+
return builder;
|
|
632
|
+
},
|
|
633
|
+
offset(count) {
|
|
634
|
+
state.offset = count;
|
|
635
|
+
return builder;
|
|
636
|
+
},
|
|
637
|
+
range(from, to) {
|
|
638
|
+
state.offset = from;
|
|
639
|
+
state.limit = to - from + 1;
|
|
640
|
+
return builder;
|
|
641
|
+
},
|
|
642
|
+
then(onfulfilled, onrejected) {
|
|
643
|
+
return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
|
|
644
|
+
},
|
|
645
|
+
catch(onrejected) {
|
|
646
|
+
return run(selectedColumns, selectedOptions).catch(onrejected);
|
|
647
|
+
},
|
|
648
|
+
finally(onfinally) {
|
|
649
|
+
return run(selectedColumns, selectedOptions).finally(onfinally);
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
return builder;
|
|
653
|
+
}
|
|
277
654
|
function createTableBuilder(tableName, client) {
|
|
278
655
|
const state = {
|
|
279
656
|
conditions: []
|
|
@@ -468,6 +845,16 @@ function createTableBuilder(tableName, client) {
|
|
|
468
845
|
});
|
|
469
846
|
return builder;
|
|
470
847
|
}
|
|
848
|
+
function createQueryBuilder(client) {
|
|
849
|
+
return async function query(query, options) {
|
|
850
|
+
const normalizedQuery = query.trim();
|
|
851
|
+
if (!normalizedQuery) {
|
|
852
|
+
throw new Error("query requires a non-empty string");
|
|
853
|
+
}
|
|
854
|
+
const response = await client.queryGateway({ query: normalizedQuery }, options);
|
|
855
|
+
return formatResult(response);
|
|
856
|
+
};
|
|
857
|
+
}
|
|
471
858
|
function createClientFromConfig(config) {
|
|
472
859
|
const gateway = createAthenaGatewayClient({
|
|
473
860
|
baseUrl: config.baseUrl,
|
|
@@ -479,7 +866,20 @@ function createClientFromConfig(config) {
|
|
|
479
866
|
return {
|
|
480
867
|
from(table) {
|
|
481
868
|
return createTableBuilder(table, gateway);
|
|
482
|
-
}
|
|
869
|
+
},
|
|
870
|
+
rpc(fn, args, options) {
|
|
871
|
+
const normalizedFn = fn.trim();
|
|
872
|
+
if (!normalizedFn) {
|
|
873
|
+
throw new Error("rpc requires a function name");
|
|
874
|
+
}
|
|
875
|
+
return createRpcBuilder(
|
|
876
|
+
normalizedFn,
|
|
877
|
+
args,
|
|
878
|
+
options,
|
|
879
|
+
gateway
|
|
880
|
+
);
|
|
881
|
+
},
|
|
882
|
+
query: createQueryBuilder(gateway)
|
|
483
883
|
};
|
|
484
884
|
}
|
|
485
885
|
var DEFAULT_BACKEND = { type: "athena" };
|
|
@@ -487,61 +887,66 @@ function toBackendConfig(b) {
|
|
|
487
887
|
if (!b) return DEFAULT_BACKEND;
|
|
488
888
|
return typeof b === "string" ? { type: b } : b;
|
|
489
889
|
}
|
|
490
|
-
var
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
};
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
890
|
+
var AthenaClientBuilderImpl = class {
|
|
891
|
+
baseUrl;
|
|
892
|
+
apiKey;
|
|
893
|
+
backendConfig = DEFAULT_BACKEND;
|
|
894
|
+
clientName;
|
|
895
|
+
defaultHeaders;
|
|
896
|
+
isHealthTrackingEnabled = false;
|
|
897
|
+
url(url) {
|
|
898
|
+
this.baseUrl = url;
|
|
899
|
+
return this;
|
|
900
|
+
}
|
|
901
|
+
key(apiKey) {
|
|
902
|
+
this.apiKey = apiKey;
|
|
903
|
+
return this;
|
|
904
|
+
}
|
|
905
|
+
backend(backend) {
|
|
906
|
+
this.backendConfig = toBackendConfig(backend);
|
|
907
|
+
return this;
|
|
908
|
+
}
|
|
909
|
+
client(clientName) {
|
|
910
|
+
this.clientName = clientName;
|
|
911
|
+
return this;
|
|
912
|
+
}
|
|
913
|
+
headers(headers) {
|
|
914
|
+
this.defaultHeaders = headers;
|
|
915
|
+
return this;
|
|
916
|
+
}
|
|
917
|
+
healthTracking(enabled) {
|
|
918
|
+
this.isHealthTrackingEnabled = enabled;
|
|
919
|
+
return this;
|
|
920
|
+
}
|
|
921
|
+
build() {
|
|
922
|
+
if (!this.baseUrl || !this.apiKey) {
|
|
923
|
+
throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
|
|
924
|
+
}
|
|
925
|
+
return createClientFromConfig({
|
|
926
|
+
baseUrl: this.baseUrl,
|
|
927
|
+
apiKey: this.apiKey,
|
|
928
|
+
client: this.clientName,
|
|
929
|
+
backend: this.backendConfig,
|
|
930
|
+
headers: this.defaultHeaders,
|
|
931
|
+
healthTracking: this.isHealthTrackingEnabled
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
var AthenaClient = class _AthenaClient {
|
|
936
|
+
/** Create a fluent builder for a strongly-typed Athena SDK client. */
|
|
937
|
+
static builder() {
|
|
938
|
+
return new AthenaClientBuilderImpl();
|
|
939
|
+
}
|
|
940
|
+
/** Build a client from process environment variables. */
|
|
941
|
+
static fromEnvironment() {
|
|
942
|
+
const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
|
|
943
|
+
const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
|
|
539
944
|
if (!url || !key) {
|
|
540
945
|
throw new Error(
|
|
541
|
-
"
|
|
946
|
+
"ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
|
|
542
947
|
);
|
|
543
948
|
}
|
|
544
|
-
return
|
|
949
|
+
return _AthenaClient.builder().url(url).key(key).build();
|
|
545
950
|
}
|
|
546
951
|
};
|
|
547
952
|
function createClient(url, apiKey, options) {
|
|
@@ -554,14 +959,15 @@ function createClient(url, apiKey, options) {
|
|
|
554
959
|
// src/gateway/types.ts
|
|
555
960
|
var Backend = {
|
|
556
961
|
Athena: { type: "athena" },
|
|
557
|
-
Supabase: { type: "supabase" },
|
|
558
962
|
Postgrest: { type: "postgrest" },
|
|
559
963
|
PostgreSQL: { type: "postgresql" },
|
|
560
964
|
ScyllaDB: { type: "scylladb" }
|
|
561
965
|
};
|
|
562
966
|
|
|
563
967
|
exports.AthenaClient = AthenaClient;
|
|
968
|
+
exports.AthenaGatewayError = AthenaGatewayError;
|
|
564
969
|
exports.Backend = Backend;
|
|
565
970
|
exports.createClient = createClient;
|
|
971
|
+
exports.isAthenaGatewayError = isAthenaGatewayError;
|
|
566
972
|
//# sourceMappingURL=index.cjs.map
|
|
567
973
|
//# sourceMappingURL=index.cjs.map
|