@xylex-group/athena 2.1.2 → 2.4.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.
Files changed (42) hide show
  1. package/README.md +306 -117
  2. package/dist/browser.cjs +2151 -194
  3. package/dist/browser.cjs.map +1 -1
  4. package/dist/browser.d.cts +14 -14
  5. package/dist/browser.d.ts +14 -14
  6. package/dist/browser.js +2146 -194
  7. package/dist/browser.js.map +1 -1
  8. package/dist/cli/index.cjs +2035 -172
  9. package/dist/cli/index.cjs.map +1 -1
  10. package/dist/cli/index.d.cts +3 -3
  11. package/dist/cli/index.d.ts +3 -3
  12. package/dist/cli/index.js +2036 -173
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.cjs +2166 -190
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +7 -7
  17. package/dist/index.d.ts +7 -7
  18. package/dist/index.js +2162 -191
  19. package/dist/index.js.map +1 -1
  20. package/dist/{model-form-2hqmoOUX.d.ts → model-form-C0FAbOaf.d.ts} +97 -2
  21. package/dist/{model-form-Cy-zaO0u.d.cts → model-form-GzTqhEzM.d.cts} +97 -2
  22. package/dist/{pipeline-BOPszLsL.d.ts → pipeline-CR4V15jF.d.ts} +1 -1
  23. package/dist/{pipeline-E3FDbs4W.d.cts → pipeline-DZeExYMA.d.cts} +1 -1
  24. package/dist/{client-BX0NQqOn.d.ts → react-email-BuApZuyG.d.ts} +362 -174
  25. package/dist/{client-dpAp-NZK.d.cts → react-email-CQJq92zQ.d.cts} +362 -174
  26. package/dist/react.cjs +279 -21
  27. package/dist/react.cjs.map +1 -1
  28. package/dist/react.d.cts +4 -4
  29. package/dist/react.d.ts +4 -4
  30. package/dist/react.js +279 -21
  31. package/dist/react.js.map +1 -1
  32. package/dist/{types-BaBzjwXr.d.cts → types-09Q4D86N.d.cts} +24 -2
  33. package/dist/{types-BaBzjwXr.d.ts → types-09Q4D86N.d.ts} +24 -2
  34. package/dist/{types-CpqL-pZx.d.cts → types-D1JvL21V.d.cts} +1 -1
  35. package/dist/{types-CeBPrnGj.d.ts → types-DU3gNdFv.d.ts} +1 -1
  36. package/dist/utils.cjs +153 -0
  37. package/dist/utils.cjs.map +1 -0
  38. package/dist/utils.d.cts +23 -0
  39. package/dist/utils.d.ts +23 -0
  40. package/dist/utils.js +146 -0
  41. package/dist/utils.js.map +1 -0
  42. package/package.json +74 -16
package/dist/react.cjs CHANGED
@@ -65,8 +65,74 @@ function isAthenaGatewayError(error) {
65
65
  return error instanceof AthenaGatewayError;
66
66
  }
67
67
 
68
+ // src/gateway/url.ts
69
+ var ATHENA_DEFAULT_BASE_URL = "https://athena-db.com";
70
+ function describeReceivedValue(value) {
71
+ if (value === void 0) return "undefined";
72
+ if (value === null) return "null";
73
+ if (typeof value === "string") {
74
+ return value.trim().length > 0 ? JSON.stringify(value) : "an empty string";
75
+ }
76
+ return `${typeof value} ${JSON.stringify(value)}`;
77
+ }
78
+ function invalidBaseUrlError(message, hint) {
79
+ return new AthenaGatewayError({
80
+ code: "INVALID_URL",
81
+ message,
82
+ status: 0,
83
+ hint
84
+ });
85
+ }
86
+ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
87
+ const label = options.label ?? "Athena gateway base URL";
88
+ const candidate = input ?? options.defaultBaseUrl;
89
+ if (candidate === void 0 || candidate === null) {
90
+ throw invalidBaseUrlError(
91
+ `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(input)}.`,
92
+ 'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
93
+ );
94
+ }
95
+ const trimmed = candidate.trim();
96
+ if (!trimmed) {
97
+ throw invalidBaseUrlError(
98
+ `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
99
+ 'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
100
+ );
101
+ }
102
+ let parsed;
103
+ try {
104
+ parsed = new URL(trimmed);
105
+ } catch {
106
+ throw invalidBaseUrlError(
107
+ `${label} must be a valid absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
108
+ 'Use a full URL including the protocol, for example "https://mirror3.athena-db.com".'
109
+ );
110
+ }
111
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
112
+ throw invalidBaseUrlError(
113
+ `${label} must use http or https. Received ${JSON.stringify(trimmed)}.`,
114
+ 'Use an Athena gateway URL such as "https://mirror3.athena-db.com".'
115
+ );
116
+ }
117
+ if (parsed.search || parsed.hash) {
118
+ throw invalidBaseUrlError(
119
+ `${label} must not include query parameters or hash fragments. Received ${JSON.stringify(trimmed)}.`,
120
+ 'Pass only the base URL. Endpoint paths such as "/gateway/fetch" are appended by the SDK.'
121
+ );
122
+ }
123
+ return parsed.toString().replace(/\/+$/, "");
124
+ }
125
+ function buildAthenaGatewayUrl(baseUrl, path) {
126
+ if (!path.startsWith("/")) {
127
+ throw invalidBaseUrlError(
128
+ `Athena gateway path must start with "/". Received ${JSON.stringify(path)}.`,
129
+ 'Use a leading slash such as "/gateway/fetch" or "/".'
130
+ );
131
+ }
132
+ return `${baseUrl}${path}`;
133
+ }
134
+
68
135
  // src/gateway/client.ts
69
- var DEFAULT_BASE_URL = "https://athena-db.com";
70
136
  var DEFAULT_CLIENT = "railway_direct";
71
137
  var FALLBACK_SDK_VERSION = "1.3.0";
72
138
  var SDK_NAME = "xylex-group/athena";
@@ -93,23 +159,39 @@ function normalizeHeaderValue(value) {
93
159
  function isRecord(value) {
94
160
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
95
161
  }
162
+ function nonEmptyString(value) {
163
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
164
+ }
165
+ function resolveStructuredErrorPayload(payload) {
166
+ if (!isRecord(payload)) return null;
167
+ return isRecord(payload.error) ? payload.error : payload;
168
+ }
96
169
  function resolveRequestId(headers) {
97
170
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
98
171
  }
99
172
  function resolveErrorMessage(payload, fallback) {
100
- if (isRecord(payload)) {
101
- const messageCandidates = [payload.error, payload.message, payload.details];
173
+ const structuredPayload = resolveStructuredErrorPayload(payload);
174
+ if (structuredPayload) {
175
+ const messageCandidates = [structuredPayload.message, structuredPayload.error, structuredPayload.details];
102
176
  for (const candidate of messageCandidates) {
103
- if (typeof candidate === "string" && candidate.trim().length > 0) {
104
- return candidate.trim();
105
- }
177
+ const resolved = nonEmptyString(candidate);
178
+ if (resolved) return resolved;
106
179
  }
107
180
  }
108
- if (typeof payload === "string" && payload.trim().length > 0) {
109
- return payload.trim();
110
- }
181
+ const rawMessage = nonEmptyString(payload);
182
+ if (rawMessage) return rawMessage;
111
183
  return fallback;
112
184
  }
185
+ function resolveErrorHint(payload) {
186
+ const structuredPayload = resolveStructuredErrorPayload(payload);
187
+ return structuredPayload ? nonEmptyString(structuredPayload.hint) : void 0;
188
+ }
189
+ function resolveStatusText(response, payload) {
190
+ const rawStatusText = nonEmptyString(response.statusText);
191
+ if (rawStatusText) return rawStatusText;
192
+ const payloadRecord = isRecord(payload) ? payload : null;
193
+ return payloadRecord ? nonEmptyString(payloadRecord.statusText) ?? null : null;
194
+ }
113
195
  function detailsFromError(error) {
114
196
  return error.toDetails();
115
197
  }
@@ -247,9 +329,168 @@ function buildHeaders(config, options) {
247
329
  });
248
330
  return headers;
249
331
  }
332
+ function toInvalidUrlResponse(error, endpoint, method) {
333
+ const message = error instanceof Error ? error.message : String(error);
334
+ const gatewayError = error instanceof AthenaGatewayError ? error : new AthenaGatewayError({
335
+ code: "INVALID_URL",
336
+ message,
337
+ status: 0,
338
+ endpoint,
339
+ method,
340
+ cause: message,
341
+ hint: "Set ATHENA_URL to a full http(s) URL before running queries."
342
+ });
343
+ return {
344
+ ok: false,
345
+ status: 0,
346
+ statusText: null,
347
+ data: null,
348
+ error: gatewayError.message,
349
+ errorDetails: detailsFromError(
350
+ new AthenaGatewayError({
351
+ code: gatewayError.code,
352
+ message: gatewayError.message,
353
+ status: gatewayError.status,
354
+ endpoint,
355
+ method,
356
+ requestId: gatewayError.requestId,
357
+ hint: gatewayError.hint,
358
+ cause: gatewayError.causeDetail
359
+ })
360
+ ),
361
+ raw: null
362
+ };
363
+ }
364
+ function resolveGatewayBaseUrl(input) {
365
+ return normalizeAthenaGatewayBaseUrl(input, {
366
+ defaultBaseUrl: ATHENA_DEFAULT_BASE_URL
367
+ });
368
+ }
369
+ function resolveProbePath(path) {
370
+ if (!path) return "/";
371
+ if (!path.startsWith("/")) {
372
+ throw new AthenaGatewayError({
373
+ code: "INVALID_URL",
374
+ message: `Athena gateway probe path must start with "/". Received ${JSON.stringify(path)}.`,
375
+ status: 0,
376
+ hint: 'Use a leading slash such as "/" or "/health".'
377
+ });
378
+ }
379
+ return path;
380
+ }
381
+ function mergeConnectionHeaders(baseHeaders, headers) {
382
+ const merged = {
383
+ ...baseHeaders,
384
+ ...headers ?? {}
385
+ };
386
+ if (!merged["X-Athena-Sdk"] && !merged["x-athena-sdk"]) {
387
+ merged["X-Athena-Sdk"] = SDK_HEADER_VALUE;
388
+ }
389
+ return merged;
390
+ }
391
+ async function performConnectionCheck(baseUrl, requestHeaders, options) {
392
+ const path = resolveProbePath(options?.path);
393
+ const url = buildAthenaGatewayUrl(baseUrl, path);
394
+ try {
395
+ const response = await fetch(url, {
396
+ method: "GET",
397
+ headers: mergeConnectionHeaders(requestHeaders, options?.headers),
398
+ signal: options?.signal
399
+ });
400
+ const rawText = await response.text();
401
+ const requestId = resolveRequestId(response.headers);
402
+ const parsedBody = parseResponseBody(
403
+ rawText ?? "",
404
+ response.headers.get("content-type")
405
+ );
406
+ if (parsedBody.parseFailed) {
407
+ const invalidJsonError = new AthenaGatewayError({
408
+ code: "INVALID_JSON",
409
+ message: "Gateway probe returned malformed JSON",
410
+ status: response.status,
411
+ method: "GET",
412
+ requestId,
413
+ hint: "Verify the gateway response body is valid JSON.",
414
+ cause: rawText.slice(0, 300)
415
+ });
416
+ return {
417
+ ok: false,
418
+ reachable: true,
419
+ status: response.status,
420
+ statusText: resolveStatusText(response, parsedBody.parsed),
421
+ baseUrl,
422
+ url,
423
+ error: invalidJsonError.message,
424
+ errorDetails: detailsFromError(invalidJsonError),
425
+ raw: parsedBody.parsed
426
+ };
427
+ }
428
+ const parsed = parsedBody.parsed;
429
+ if (!response.ok) {
430
+ const httpError = new AthenaGatewayError({
431
+ code: "HTTP_ERROR",
432
+ message: resolveErrorMessage(
433
+ parsed,
434
+ `Athena gateway GET ${path} failed with status ${response.status}`
435
+ ),
436
+ status: response.status,
437
+ method: "GET",
438
+ requestId,
439
+ hint: resolveErrorHint(parsed)
440
+ });
441
+ return {
442
+ ok: false,
443
+ reachable: true,
444
+ status: response.status,
445
+ statusText: resolveStatusText(response, parsed),
446
+ baseUrl,
447
+ url,
448
+ error: httpError.message,
449
+ errorDetails: detailsFromError(httpError),
450
+ raw: parsed
451
+ };
452
+ }
453
+ return {
454
+ ok: true,
455
+ reachable: true,
456
+ status: response.status,
457
+ statusText: resolveStatusText(response, parsed),
458
+ baseUrl,
459
+ url,
460
+ error: void 0,
461
+ errorDetails: null,
462
+ raw: parsed
463
+ };
464
+ } catch (callError) {
465
+ const message = callError instanceof Error ? callError.message : String(callError);
466
+ const networkError = new AthenaGatewayError({
467
+ code: "NETWORK_ERROR",
468
+ message: `Network error while probing Athena gateway ${url}: ${message}`,
469
+ method: "GET",
470
+ cause: message,
471
+ hint: "Check gateway URL, DNS, and network reachability."
472
+ });
473
+ return {
474
+ ok: false,
475
+ reachable: false,
476
+ status: 0,
477
+ statusText: null,
478
+ baseUrl,
479
+ url,
480
+ error: networkError.message,
481
+ errorDetails: detailsFromError(networkError),
482
+ raw: null
483
+ };
484
+ }
485
+ }
250
486
  async function callAthena(config, endpoint, method, payload, options) {
251
- const baseUrl = (options?.baseUrl ?? config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
252
- const url = `${baseUrl}${endpoint}`;
487
+ let baseUrl;
488
+ try {
489
+ baseUrl = resolveGatewayBaseUrl(options?.baseUrl ?? config.baseUrl);
490
+ } catch (error) {
491
+ return toInvalidUrlResponse(error, endpoint, method);
492
+ }
493
+ const url = buildAthenaGatewayUrl(baseUrl, endpoint);
253
494
  const headers = buildHeaders(config, options);
254
495
  try {
255
496
  const requestInit = {
@@ -280,6 +521,7 @@ async function callAthena(config, endpoint, method, payload, options) {
280
521
  return {
281
522
  ok: false,
282
523
  status: response.status,
524
+ statusText: resolveStatusText(response, parsedBody.parsed),
283
525
  data: null,
284
526
  error: invalidJsonError.message,
285
527
  errorDetails: detailsFromError(invalidJsonError),
@@ -298,11 +540,13 @@ async function callAthena(config, endpoint, method, payload, options) {
298
540
  status: response.status,
299
541
  endpoint,
300
542
  method,
301
- requestId
543
+ requestId,
544
+ hint: resolveErrorHint(parsed)
302
545
  });
303
546
  return {
304
547
  ok: false,
305
548
  status: response.status,
549
+ statusText: resolveStatusText(response, parsed),
306
550
  data: null,
307
551
  error: httpError.message,
308
552
  errorDetails: detailsFromError(httpError),
@@ -314,6 +558,7 @@ async function callAthena(config, endpoint, method, payload, options) {
314
558
  return {
315
559
  ok: true,
316
560
  status: response.status,
561
+ statusText: resolveStatusText(response, parsed),
317
562
  data: payloadData ?? null,
318
563
  count: payloadCount,
319
564
  error: void 0,
@@ -333,6 +578,7 @@ async function callAthena(config, endpoint, method, payload, options) {
333
578
  return {
334
579
  ok: false,
335
580
  status: 0,
581
+ statusText: null,
336
582
  data: null,
337
583
  error: networkError.message,
338
584
  errorDetails: detailsFromError(networkError),
@@ -341,32 +587,44 @@ async function callAthena(config, endpoint, method, payload, options) {
341
587
  }
342
588
  }
343
589
  function createAthenaGatewayClient(config = {}) {
590
+ const normalizedBaseUrl = resolveGatewayBaseUrl(config.baseUrl);
591
+ const normalizedConfig = {
592
+ ...config,
593
+ baseUrl: normalizedBaseUrl
594
+ };
344
595
  return {
345
- baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, ""),
596
+ baseUrl: normalizedBaseUrl,
346
597
  buildHeaders(options) {
347
- return buildHeaders(config, options);
598
+ return buildHeaders(normalizedConfig, options);
599
+ },
600
+ verifyConnection(options) {
601
+ return performConnectionCheck(
602
+ normalizedBaseUrl,
603
+ buildHeaders(normalizedConfig),
604
+ options
605
+ );
348
606
  },
349
607
  fetchGateway(payload, options) {
350
- return callAthena(config, "/gateway/fetch", "POST", payload, options);
608
+ return callAthena(normalizedConfig, "/gateway/fetch", "POST", payload, options);
351
609
  },
352
610
  insertGateway(payload, options) {
353
- return callAthena(config, "/gateway/insert", "PUT", payload, options);
611
+ return callAthena(normalizedConfig, "/gateway/insert", "PUT", payload, options);
354
612
  },
355
613
  updateGateway(payload, options) {
356
- return callAthena(config, "/gateway/update", "POST", payload, options);
614
+ return callAthena(normalizedConfig, "/gateway/update", "POST", payload, options);
357
615
  },
358
616
  deleteGateway(payload, options) {
359
- return callAthena(config, "/gateway/delete", "DELETE", payload, options);
617
+ return callAthena(normalizedConfig, "/gateway/delete", "DELETE", payload, options);
360
618
  },
361
619
  rpcGateway(payload, options) {
362
620
  if (options?.get) {
363
621
  const endpoint = buildRpcGetEndpoint(payload);
364
- return callAthena(config, endpoint, "GET", null, options);
622
+ return callAthena(normalizedConfig, endpoint, "GET", null, options);
365
623
  }
366
- return callAthena(config, "/gateway/rpc", "POST", payload, options);
624
+ return callAthena(normalizedConfig, "/gateway/rpc", "POST", payload, options);
367
625
  },
368
626
  queryGateway(payload, options) {
369
- return callAthena(config, "/gateway/query", "POST", payload, options);
627
+ return callAthena(normalizedConfig, "/gateway/query", "POST", payload, options);
370
628
  }
371
629
  };
372
630
  }