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