@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
@@ -7,6 +7,11 @@ var url = require('url');
7
7
 
8
8
  // src/generator/pipeline.ts
9
9
 
10
+ // src/utils/slugify.ts
11
+ function slugify(input) {
12
+ return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
13
+ }
14
+
10
15
  // src/generator/naming.ts
11
16
  var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
12
17
  var RESERVED_IDENTIFIERS = /* @__PURE__ */ new Set([
@@ -102,7 +107,7 @@ function applyNamingStyle(input, style) {
102
107
  case "snake":
103
108
  return words.map((word) => word.toLowerCase()).join("_");
104
109
  case "kebab":
105
- return words.map((word) => word.toLowerCase()).join("-");
110
+ return slugify(words.join("-"));
106
111
  default:
107
112
  return input;
108
113
  }
@@ -355,6 +360,19 @@ function isAthenaGatewayError(error) {
355
360
  return error instanceof AthenaGatewayError;
356
361
  }
357
362
 
363
+ // src/utils/parse-boolean-flag.ts
364
+ function parseBooleanFlag(rawValue, fallback) {
365
+ if (!rawValue) return fallback;
366
+ const normalized = rawValue.trim().toLowerCase();
367
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
368
+ return true;
369
+ }
370
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
371
+ return false;
372
+ }
373
+ return fallback;
374
+ }
375
+
358
376
  // src/auxiliaries.ts
359
377
  var AthenaErrorCode = {
360
378
  UniqueViolation: "UNIQUE_VIOLATION",
@@ -375,20 +393,41 @@ var AthenaErrorCategory = {
375
393
  Database: "database",
376
394
  Unknown: "unknown"
377
395
  };
378
- function parseBooleanFlag(rawValue, fallback) {
379
- if (!rawValue) return fallback;
380
- const normalized = rawValue.trim().toLowerCase();
381
- if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
382
- return true;
383
- }
384
- if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
385
- return false;
386
- }
387
- return fallback;
396
+ function parseBooleanFlag2(rawValue, fallback) {
397
+ return parseBooleanFlag(rawValue, fallback);
388
398
  }
389
399
  function isRecord(value) {
390
400
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
391
401
  }
402
+ function firstNonEmptyString(...values) {
403
+ for (const value of values) {
404
+ if (typeof value === "string" && value.trim().length > 0) {
405
+ return value.trim();
406
+ }
407
+ }
408
+ return void 0;
409
+ }
410
+ function messageFromUnknownError(error) {
411
+ if (typeof error === "string" && error.trim().length > 0) {
412
+ return error.trim();
413
+ }
414
+ if (error instanceof Error && error.message.trim().length > 0) {
415
+ return error.message.trim();
416
+ }
417
+ if (!isRecord(error)) {
418
+ return void 0;
419
+ }
420
+ return firstNonEmptyString(error.message, error.error, error.details);
421
+ }
422
+ function gatewayCodeFromUnknownError(error) {
423
+ if (!isRecord(error) || typeof error.gatewayCode !== "string") {
424
+ return void 0;
425
+ }
426
+ return error.gatewayCode;
427
+ }
428
+ function isAthenaResultErrorLike(value) {
429
+ return isRecord(value) && typeof value.message === "string" && (value.athenaCode === void 0 || isAthenaErrorCode(value.athenaCode)) && (value.kind === void 0 || isAthenaErrorKind(value.kind)) && (value.category === void 0 || isAthenaErrorCategory(value.category)) && (value.retryable === void 0 || typeof value.retryable === "boolean") && (value.status === void 0 || typeof value.status === "number");
430
+ }
392
431
  function isAthenaErrorKind(value) {
393
432
  return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
394
433
  }
@@ -460,6 +499,7 @@ function classifyKind(status, code, message) {
460
499
  if (status === 404 || hasNotFoundPattern) return "not_found";
461
500
  if (status === 401 || status === 403 || hasAuthPattern) return "auth";
462
501
  if (status === 429 || hasRateLimitPattern) return "rate_limit";
502
+ if (code === "INVALID_URL") return "validation";
463
503
  if (status === 400 || status === 422 || hasValidationPattern) return "validation";
464
504
  if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
465
505
  return "transient";
@@ -467,6 +507,9 @@ function classifyKind(status, code, message) {
467
507
  return "unknown";
468
508
  }
469
509
  function toAthenaErrorCode(kind, status, gatewayCode) {
510
+ if (gatewayCode === "INVALID_URL") {
511
+ return AthenaErrorCode.ValidationFailed;
512
+ }
470
513
  if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
471
514
  return AthenaErrorCode.NetworkUnavailable;
472
515
  }
@@ -510,13 +553,50 @@ function normalizeAthenaError(resultOrError, context) {
510
553
  return withContextOverrides(attached, context);
511
554
  }
512
555
  if (isAthenaResultLike(resultOrError)) {
556
+ if (isAthenaResultErrorLike(resultOrError.error)) {
557
+ return {
558
+ kind: resultOrError.error.kind ?? classifyKind(resultOrError.status, gatewayCodeFromUnknownError(resultOrError.error), resultOrError.error.message),
559
+ code: resultOrError.error.athenaCode ?? toAthenaErrorCode(
560
+ resultOrError.error.kind ?? classifyKind(
561
+ resultOrError.status,
562
+ gatewayCodeFromUnknownError(resultOrError.error),
563
+ resultOrError.error.message
564
+ ),
565
+ resultOrError.error.status ?? resultOrError.status,
566
+ gatewayCodeFromUnknownError(resultOrError.error)
567
+ ),
568
+ category: resultOrError.error.category ?? toAthenaErrorCategory(
569
+ resultOrError.error.kind ?? classifyKind(
570
+ resultOrError.status,
571
+ gatewayCodeFromUnknownError(resultOrError.error),
572
+ resultOrError.error.message
573
+ ),
574
+ resultOrError.error.status ?? resultOrError.status
575
+ ),
576
+ retryable: resultOrError.error.retryable ?? isRetryable(
577
+ resultOrError.error.kind ?? classifyKind(
578
+ resultOrError.status,
579
+ gatewayCodeFromUnknownError(resultOrError.error),
580
+ resultOrError.error.message
581
+ ),
582
+ resultOrError.error.status ?? resultOrError.status
583
+ ),
584
+ status: resultOrError.error.status ?? resultOrError.status,
585
+ constraint: resultOrError.error.constraint,
586
+ table: context?.table ?? resultOrError.error.table,
587
+ operation: context?.operation ?? resultOrError.error.operation,
588
+ message: resultOrError.error.message,
589
+ raw: resultOrError.error.raw ?? resultOrError.raw
590
+ };
591
+ }
513
592
  const details = resultOrError.errorDetails;
514
- const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
593
+ const message2 = messageFromUnknownError(resultOrError.error) ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
515
594
  const operation = context?.operation ?? operationFromDetails(details);
516
595
  const table = context?.table ?? extractTable(message2);
517
596
  const constraint = extractConstraint(message2);
518
- const kind2 = classifyKind(resultOrError.status, details?.code, message2);
519
- const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
597
+ const gatewayCode = details?.code ?? gatewayCodeFromUnknownError(resultOrError.error);
598
+ const kind2 = classifyKind(resultOrError.status, gatewayCode, message2);
599
+ const code = toAthenaErrorCode(kind2, resultOrError.status, gatewayCode);
520
600
  const category = toAthenaErrorCategory(kind2, resultOrError.status);
521
601
  return {
522
602
  kind: kind2,
@@ -794,7 +874,7 @@ function normalizeBooleanFlag(rawValue, fallback) {
794
874
  return rawValue;
795
875
  }
796
876
  if (typeof rawValue === "string") {
797
- return parseBooleanFlag(rawValue, fallback);
877
+ return parseBooleanFlag2(rawValue, fallback);
798
878
  }
799
879
  return fallback;
800
880
  }
@@ -1283,8 +1363,74 @@ function generateArtifactsFromSnapshot(snapshot, config) {
1283
1363
  return new ArtifactComposer(snapshot, normalizedConfig).compose();
1284
1364
  }
1285
1365
 
1366
+ // src/gateway/url.ts
1367
+ var ATHENA_DEFAULT_BASE_URL = "https://athena-db.com";
1368
+ function describeReceivedValue(value) {
1369
+ if (value === void 0) return "undefined";
1370
+ if (value === null) return "null";
1371
+ if (typeof value === "string") {
1372
+ return value.trim().length > 0 ? JSON.stringify(value) : "an empty string";
1373
+ }
1374
+ return `${typeof value} ${JSON.stringify(value)}`;
1375
+ }
1376
+ function invalidBaseUrlError(message, hint) {
1377
+ return new AthenaGatewayError({
1378
+ code: "INVALID_URL",
1379
+ message,
1380
+ status: 0,
1381
+ hint
1382
+ });
1383
+ }
1384
+ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
1385
+ const label = options.label ?? "Athena gateway base URL";
1386
+ const candidate = input ?? options.defaultBaseUrl;
1387
+ if (candidate === void 0 || candidate === null) {
1388
+ throw invalidBaseUrlError(
1389
+ `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(input)}.`,
1390
+ 'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
1391
+ );
1392
+ }
1393
+ const trimmed = candidate.trim();
1394
+ if (!trimmed) {
1395
+ throw invalidBaseUrlError(
1396
+ `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
1397
+ 'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
1398
+ );
1399
+ }
1400
+ let parsed;
1401
+ try {
1402
+ parsed = new URL(trimmed);
1403
+ } catch {
1404
+ throw invalidBaseUrlError(
1405
+ `${label} must be a valid absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
1406
+ 'Use a full URL including the protocol, for example "https://mirror3.athena-db.com".'
1407
+ );
1408
+ }
1409
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
1410
+ throw invalidBaseUrlError(
1411
+ `${label} must use http or https. Received ${JSON.stringify(trimmed)}.`,
1412
+ 'Use an Athena gateway URL such as "https://mirror3.athena-db.com".'
1413
+ );
1414
+ }
1415
+ if (parsed.search || parsed.hash) {
1416
+ throw invalidBaseUrlError(
1417
+ `${label} must not include query parameters or hash fragments. Received ${JSON.stringify(trimmed)}.`,
1418
+ 'Pass only the base URL. Endpoint paths such as "/gateway/fetch" are appended by the SDK.'
1419
+ );
1420
+ }
1421
+ return parsed.toString().replace(/\/+$/, "");
1422
+ }
1423
+ function buildAthenaGatewayUrl(baseUrl, path) {
1424
+ if (!path.startsWith("/")) {
1425
+ throw invalidBaseUrlError(
1426
+ `Athena gateway path must start with "/". Received ${JSON.stringify(path)}.`,
1427
+ 'Use a leading slash such as "/gateway/fetch" or "/".'
1428
+ );
1429
+ }
1430
+ return `${baseUrl}${path}`;
1431
+ }
1432
+
1286
1433
  // src/gateway/client.ts
1287
- var DEFAULT_BASE_URL = "https://athena-db.com";
1288
1434
  var DEFAULT_CLIENT = "railway_direct";
1289
1435
  var FALLBACK_SDK_VERSION = "1.3.0";
1290
1436
  var SDK_NAME = "xylex-group/athena";
@@ -1311,23 +1457,39 @@ function normalizeHeaderValue(value) {
1311
1457
  function isRecord2(value) {
1312
1458
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1313
1459
  }
1460
+ function nonEmptyString(value) {
1461
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
1462
+ }
1463
+ function resolveStructuredErrorPayload(payload) {
1464
+ if (!isRecord2(payload)) return null;
1465
+ return isRecord2(payload.error) ? payload.error : payload;
1466
+ }
1314
1467
  function resolveRequestId(headers) {
1315
1468
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
1316
1469
  }
1317
1470
  function resolveErrorMessage(payload, fallback) {
1318
- if (isRecord2(payload)) {
1319
- const messageCandidates = [payload.error, payload.message, payload.details];
1471
+ const structuredPayload = resolveStructuredErrorPayload(payload);
1472
+ if (structuredPayload) {
1473
+ const messageCandidates = [structuredPayload.message, structuredPayload.error, structuredPayload.details];
1320
1474
  for (const candidate of messageCandidates) {
1321
- if (typeof candidate === "string" && candidate.trim().length > 0) {
1322
- return candidate.trim();
1323
- }
1475
+ const resolved = nonEmptyString(candidate);
1476
+ if (resolved) return resolved;
1324
1477
  }
1325
1478
  }
1326
- if (typeof payload === "string" && payload.trim().length > 0) {
1327
- return payload.trim();
1328
- }
1479
+ const rawMessage = nonEmptyString(payload);
1480
+ if (rawMessage) return rawMessage;
1329
1481
  return fallback;
1330
1482
  }
1483
+ function resolveErrorHint(payload) {
1484
+ const structuredPayload = resolveStructuredErrorPayload(payload);
1485
+ return structuredPayload ? nonEmptyString(structuredPayload.hint) : void 0;
1486
+ }
1487
+ function resolveStatusText(response, payload) {
1488
+ const rawStatusText = nonEmptyString(response.statusText);
1489
+ if (rawStatusText) return rawStatusText;
1490
+ const payloadRecord = isRecord2(payload) ? payload : null;
1491
+ return payloadRecord ? nonEmptyString(payloadRecord.statusText) ?? null : null;
1492
+ }
1331
1493
  function detailsFromError(error) {
1332
1494
  return error.toDetails();
1333
1495
  }
@@ -1465,9 +1627,168 @@ function buildHeaders(config, options) {
1465
1627
  });
1466
1628
  return headers;
1467
1629
  }
1630
+ function toInvalidUrlResponse(error, endpoint, method) {
1631
+ const message = error instanceof Error ? error.message : String(error);
1632
+ const gatewayError = error instanceof AthenaGatewayError ? error : new AthenaGatewayError({
1633
+ code: "INVALID_URL",
1634
+ message,
1635
+ status: 0,
1636
+ endpoint,
1637
+ method,
1638
+ cause: message,
1639
+ hint: "Set ATHENA_URL to a full http(s) URL before running queries."
1640
+ });
1641
+ return {
1642
+ ok: false,
1643
+ status: 0,
1644
+ statusText: null,
1645
+ data: null,
1646
+ error: gatewayError.message,
1647
+ errorDetails: detailsFromError(
1648
+ new AthenaGatewayError({
1649
+ code: gatewayError.code,
1650
+ message: gatewayError.message,
1651
+ status: gatewayError.status,
1652
+ endpoint,
1653
+ method,
1654
+ requestId: gatewayError.requestId,
1655
+ hint: gatewayError.hint,
1656
+ cause: gatewayError.causeDetail
1657
+ })
1658
+ ),
1659
+ raw: null
1660
+ };
1661
+ }
1662
+ function resolveGatewayBaseUrl(input) {
1663
+ return normalizeAthenaGatewayBaseUrl(input, {
1664
+ defaultBaseUrl: ATHENA_DEFAULT_BASE_URL
1665
+ });
1666
+ }
1667
+ function resolveProbePath(path) {
1668
+ if (!path) return "/";
1669
+ if (!path.startsWith("/")) {
1670
+ throw new AthenaGatewayError({
1671
+ code: "INVALID_URL",
1672
+ message: `Athena gateway probe path must start with "/". Received ${JSON.stringify(path)}.`,
1673
+ status: 0,
1674
+ hint: 'Use a leading slash such as "/" or "/health".'
1675
+ });
1676
+ }
1677
+ return path;
1678
+ }
1679
+ function mergeConnectionHeaders(baseHeaders, headers) {
1680
+ const merged = {
1681
+ ...baseHeaders,
1682
+ ...headers ?? {}
1683
+ };
1684
+ if (!merged["X-Athena-Sdk"] && !merged["x-athena-sdk"]) {
1685
+ merged["X-Athena-Sdk"] = SDK_HEADER_VALUE;
1686
+ }
1687
+ return merged;
1688
+ }
1689
+ async function performConnectionCheck(baseUrl, requestHeaders, options) {
1690
+ const path = resolveProbePath(options?.path);
1691
+ const url = buildAthenaGatewayUrl(baseUrl, path);
1692
+ try {
1693
+ const response = await fetch(url, {
1694
+ method: "GET",
1695
+ headers: mergeConnectionHeaders(requestHeaders, options?.headers),
1696
+ signal: options?.signal
1697
+ });
1698
+ const rawText = await response.text();
1699
+ const requestId = resolveRequestId(response.headers);
1700
+ const parsedBody = parseResponseBody(
1701
+ rawText ?? "",
1702
+ response.headers.get("content-type")
1703
+ );
1704
+ if (parsedBody.parseFailed) {
1705
+ const invalidJsonError = new AthenaGatewayError({
1706
+ code: "INVALID_JSON",
1707
+ message: "Gateway probe returned malformed JSON",
1708
+ status: response.status,
1709
+ method: "GET",
1710
+ requestId,
1711
+ hint: "Verify the gateway response body is valid JSON.",
1712
+ cause: rawText.slice(0, 300)
1713
+ });
1714
+ return {
1715
+ ok: false,
1716
+ reachable: true,
1717
+ status: response.status,
1718
+ statusText: resolveStatusText(response, parsedBody.parsed),
1719
+ baseUrl,
1720
+ url,
1721
+ error: invalidJsonError.message,
1722
+ errorDetails: detailsFromError(invalidJsonError),
1723
+ raw: parsedBody.parsed
1724
+ };
1725
+ }
1726
+ const parsed = parsedBody.parsed;
1727
+ if (!response.ok) {
1728
+ const httpError = new AthenaGatewayError({
1729
+ code: "HTTP_ERROR",
1730
+ message: resolveErrorMessage(
1731
+ parsed,
1732
+ `Athena gateway GET ${path} failed with status ${response.status}`
1733
+ ),
1734
+ status: response.status,
1735
+ method: "GET",
1736
+ requestId,
1737
+ hint: resolveErrorHint(parsed)
1738
+ });
1739
+ return {
1740
+ ok: false,
1741
+ reachable: true,
1742
+ status: response.status,
1743
+ statusText: resolveStatusText(response, parsed),
1744
+ baseUrl,
1745
+ url,
1746
+ error: httpError.message,
1747
+ errorDetails: detailsFromError(httpError),
1748
+ raw: parsed
1749
+ };
1750
+ }
1751
+ return {
1752
+ ok: true,
1753
+ reachable: true,
1754
+ status: response.status,
1755
+ statusText: resolveStatusText(response, parsed),
1756
+ baseUrl,
1757
+ url,
1758
+ error: void 0,
1759
+ errorDetails: null,
1760
+ raw: parsed
1761
+ };
1762
+ } catch (callError) {
1763
+ const message = callError instanceof Error ? callError.message : String(callError);
1764
+ const networkError = new AthenaGatewayError({
1765
+ code: "NETWORK_ERROR",
1766
+ message: `Network error while probing Athena gateway ${url}: ${message}`,
1767
+ method: "GET",
1768
+ cause: message,
1769
+ hint: "Check gateway URL, DNS, and network reachability."
1770
+ });
1771
+ return {
1772
+ ok: false,
1773
+ reachable: false,
1774
+ status: 0,
1775
+ statusText: null,
1776
+ baseUrl,
1777
+ url,
1778
+ error: networkError.message,
1779
+ errorDetails: detailsFromError(networkError),
1780
+ raw: null
1781
+ };
1782
+ }
1783
+ }
1468
1784
  async function callAthena(config, endpoint, method, payload, options) {
1469
- const baseUrl = (options?.baseUrl ?? config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
1470
- const url = `${baseUrl}${endpoint}`;
1785
+ let baseUrl;
1786
+ try {
1787
+ baseUrl = resolveGatewayBaseUrl(options?.baseUrl ?? config.baseUrl);
1788
+ } catch (error) {
1789
+ return toInvalidUrlResponse(error, endpoint, method);
1790
+ }
1791
+ const url = buildAthenaGatewayUrl(baseUrl, endpoint);
1471
1792
  const headers = buildHeaders(config, options);
1472
1793
  try {
1473
1794
  const requestInit = {
@@ -1498,6 +1819,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1498
1819
  return {
1499
1820
  ok: false,
1500
1821
  status: response.status,
1822
+ statusText: resolveStatusText(response, parsedBody.parsed),
1501
1823
  data: null,
1502
1824
  error: invalidJsonError.message,
1503
1825
  errorDetails: detailsFromError(invalidJsonError),
@@ -1516,11 +1838,13 @@ async function callAthena(config, endpoint, method, payload, options) {
1516
1838
  status: response.status,
1517
1839
  endpoint,
1518
1840
  method,
1519
- requestId
1841
+ requestId,
1842
+ hint: resolveErrorHint(parsed)
1520
1843
  });
1521
1844
  return {
1522
1845
  ok: false,
1523
1846
  status: response.status,
1847
+ statusText: resolveStatusText(response, parsed),
1524
1848
  data: null,
1525
1849
  error: httpError.message,
1526
1850
  errorDetails: detailsFromError(httpError),
@@ -1532,6 +1856,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1532
1856
  return {
1533
1857
  ok: true,
1534
1858
  status: response.status,
1859
+ statusText: resolveStatusText(response, parsed),
1535
1860
  data: payloadData ?? null,
1536
1861
  count: payloadCount,
1537
1862
  error: void 0,
@@ -1551,6 +1876,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1551
1876
  return {
1552
1877
  ok: false,
1553
1878
  status: 0,
1879
+ statusText: null,
1554
1880
  data: null,
1555
1881
  error: networkError.message,
1556
1882
  errorDetails: detailsFromError(networkError),
@@ -1559,32 +1885,44 @@ async function callAthena(config, endpoint, method, payload, options) {
1559
1885
  }
1560
1886
  }
1561
1887
  function createAthenaGatewayClient(config = {}) {
1888
+ const normalizedBaseUrl = resolveGatewayBaseUrl(config.baseUrl);
1889
+ const normalizedConfig = {
1890
+ ...config,
1891
+ baseUrl: normalizedBaseUrl
1892
+ };
1562
1893
  return {
1563
- baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, ""),
1894
+ baseUrl: normalizedBaseUrl,
1564
1895
  buildHeaders(options) {
1565
- return buildHeaders(config, options);
1896
+ return buildHeaders(normalizedConfig, options);
1897
+ },
1898
+ verifyConnection(options) {
1899
+ return performConnectionCheck(
1900
+ normalizedBaseUrl,
1901
+ buildHeaders(normalizedConfig),
1902
+ options
1903
+ );
1566
1904
  },
1567
1905
  fetchGateway(payload, options) {
1568
- return callAthena(config, "/gateway/fetch", "POST", payload, options);
1906
+ return callAthena(normalizedConfig, "/gateway/fetch", "POST", payload, options);
1569
1907
  },
1570
1908
  insertGateway(payload, options) {
1571
- return callAthena(config, "/gateway/insert", "PUT", payload, options);
1909
+ return callAthena(normalizedConfig, "/gateway/insert", "PUT", payload, options);
1572
1910
  },
1573
1911
  updateGateway(payload, options) {
1574
- return callAthena(config, "/gateway/update", "POST", payload, options);
1912
+ return callAthena(normalizedConfig, "/gateway/update", "POST", payload, options);
1575
1913
  },
1576
1914
  deleteGateway(payload, options) {
1577
- return callAthena(config, "/gateway/delete", "DELETE", payload, options);
1915
+ return callAthena(normalizedConfig, "/gateway/delete", "DELETE", payload, options);
1578
1916
  },
1579
1917
  rpcGateway(payload, options) {
1580
1918
  if (options?.get) {
1581
1919
  const endpoint = buildRpcGetEndpoint(payload);
1582
- return callAthena(config, endpoint, "GET", null, options);
1920
+ return callAthena(normalizedConfig, endpoint, "GET", null, options);
1583
1921
  }
1584
- return callAthena(config, "/gateway/rpc", "POST", payload, options);
1922
+ return callAthena(normalizedConfig, "/gateway/rpc", "POST", payload, options);
1585
1923
  },
1586
1924
  queryGateway(payload, options) {
1587
- return callAthena(config, "/gateway/query", "POST", payload, options);
1925
+ return callAthena(normalizedConfig, "/gateway/query", "POST", payload, options);
1588
1926
  }
1589
1927
  };
1590
1928
  }
@@ -1592,10 +1930,29 @@ function createAthenaGatewayClient(config = {}) {
1592
1930
  // src/sql-identifiers.ts
1593
1931
  var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
1594
1932
  var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
1595
- var ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
1933
+ var SQL_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
1934
+ var RESPONSE_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_.]*)$/i;
1596
1935
  function quoteIdentifierSegment(identifier) {
1597
1936
  return `"${identifier.replace(/"/g, '""')}"`;
1598
1937
  }
1938
+ function parseAliasedIdentifierToken(token) {
1939
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(token);
1940
+ if (responseAliasMatch) {
1941
+ const [, aliasIdentifier2, baseIdentifier2] = responseAliasMatch;
1942
+ if (COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier2) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier2)) {
1943
+ return { baseIdentifier: baseIdentifier2, aliasIdentifier: aliasIdentifier2 };
1944
+ }
1945
+ }
1946
+ const sqlAliasMatch = SQL_ALIAS_PATTERN.exec(token);
1947
+ if (!sqlAliasMatch) {
1948
+ return null;
1949
+ }
1950
+ const [, baseIdentifier, aliasIdentifier] = sqlAliasMatch;
1951
+ if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
1952
+ return null;
1953
+ }
1954
+ return { baseIdentifier, aliasIdentifier };
1955
+ }
1599
1956
  function quoteQualifiedIdentifier(identifier) {
1600
1957
  return identifier.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
1601
1958
  }
@@ -1604,23 +1961,27 @@ function quoteSelectToken(token) {
1604
1961
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
1605
1962
  return quoteQualifiedIdentifier(token);
1606
1963
  }
1607
- const aliasMatch = ALIAS_PATTERN.exec(token);
1608
- if (!aliasMatch) {
1609
- return token;
1610
- }
1611
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
1612
- if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
1964
+ const aliasedIdentifier = parseAliasedIdentifierToken(token);
1965
+ if (!aliasedIdentifier) {
1613
1966
  return token;
1614
1967
  }
1968
+ const { baseIdentifier, aliasIdentifier } = aliasedIdentifier;
1615
1969
  return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
1616
1970
  }
1971
+ function quoteSelectColumnToken(token) {
1972
+ const trimmed = token.trim();
1973
+ if (!trimmed || trimmed === "*") return trimmed || "*";
1974
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(trimmed);
1975
+ if (responseAliasMatch) {
1976
+ const [, aliasIdentifier, baseIdentifier] = responseAliasMatch;
1977
+ return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
1978
+ }
1979
+ return quoteQualifiedIdentifier(trimmed);
1980
+ }
1617
1981
  function canAutoQuoteToken(token) {
1618
1982
  if (token === "*") return true;
1619
1983
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
1620
- const aliasMatch = ALIAS_PATTERN.exec(token);
1621
- if (!aliasMatch) return false;
1622
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
1623
- return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
1984
+ return parseAliasedIdentifierToken(token) != null;
1624
1985
  }
1625
1986
  function splitTopLevelCommaSeparated(input) {
1626
1987
  const parts = [];
@@ -1704,6 +2065,190 @@ function quoteSelectColumnsExpression(columns) {
1704
2065
  return tokens.map(quoteSelectToken).join(", ");
1705
2066
  }
1706
2067
 
2068
+ // src/auth/react-email.ts
2069
+ var reactEmailRenderModulePromise;
2070
+ function isRecord3(value) {
2071
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2072
+ }
2073
+ function isFunction(value) {
2074
+ return typeof value === "function";
2075
+ }
2076
+ function toStringOrUndefined(value) {
2077
+ if (typeof value !== "string") return void 0;
2078
+ return value;
2079
+ }
2080
+ function nowIsoString() {
2081
+ return (/* @__PURE__ */ new Date()).toISOString();
2082
+ }
2083
+ function emitReactEmailEvent(observe, phase, input = {}) {
2084
+ if (!observe) return;
2085
+ try {
2086
+ observe({
2087
+ phase,
2088
+ timestamp: nowIsoString(),
2089
+ ...input
2090
+ });
2091
+ } catch {
2092
+ }
2093
+ }
2094
+ function mergeRenderDefaults(input, defaults) {
2095
+ return {
2096
+ ...input,
2097
+ pretty: input.pretty ?? defaults?.pretty,
2098
+ includePlainText: input.includePlainText ?? defaults?.includePlainText
2099
+ };
2100
+ }
2101
+ function mergeRuntimeOptions(options) {
2102
+ if (!options) return void 0;
2103
+ return {
2104
+ defaults: options.defaults,
2105
+ observe: options.observe,
2106
+ route: "route" in options ? options.route : void 0
2107
+ };
2108
+ }
2109
+ async function resolveReactEmailRenderModule() {
2110
+ if (!reactEmailRenderModulePromise) {
2111
+ reactEmailRenderModulePromise = (async () => {
2112
+ try {
2113
+ const loaded = await import('@react-email/render');
2114
+ if (!isFunction(loaded.render)) {
2115
+ throw new Error("missing render(...) export");
2116
+ }
2117
+ return {
2118
+ render: loaded.render,
2119
+ toPlainText: isFunction(loaded.toPlainText) ? loaded.toPlainText : void 0,
2120
+ pretty: isFunction(loaded.pretty) ? loaded.pretty : void 0
2121
+ };
2122
+ } catch (error) {
2123
+ const message = error instanceof Error ? error.message : String(error);
2124
+ throw new Error(
2125
+ `React Email rendering requires @react-email/render. Install it in your project (for example: pnpm add @react-email/render). Loader error: ${message}`
2126
+ );
2127
+ }
2128
+ })();
2129
+ }
2130
+ if (!reactEmailRenderModulePromise) {
2131
+ throw new Error("React Email renderer module failed to initialize");
2132
+ }
2133
+ return reactEmailRenderModulePromise;
2134
+ }
2135
+ async function resolveReactEmailElement(input) {
2136
+ if (input.element != null) {
2137
+ return input.element;
2138
+ }
2139
+ if (!input.component) {
2140
+ throw new Error("react email payload requires either `element` or `component`");
2141
+ }
2142
+ try {
2143
+ const reactModule = await import('react');
2144
+ if (typeof reactModule.createElement !== "function") {
2145
+ throw new Error("react createElement(...) export is unavailable");
2146
+ }
2147
+ return reactModule.createElement(
2148
+ input.component,
2149
+ input.props ?? {}
2150
+ );
2151
+ } catch (error) {
2152
+ const message = error instanceof Error ? error.message : String(error);
2153
+ throw new Error(
2154
+ `React Email component rendering requires react runtime support. Install react in your project. Loader error: ${message}`
2155
+ );
2156
+ }
2157
+ }
2158
+ async function renderAthenaReactEmail(input, options) {
2159
+ if (!isRecord3(input)) {
2160
+ throw new Error("react email payload must be an object");
2161
+ }
2162
+ const runtimeOptions = mergeRuntimeOptions(options);
2163
+ const start = Date.now();
2164
+ emitReactEmailEvent(runtimeOptions?.observe, "render:start", {
2165
+ route: runtimeOptions?.route,
2166
+ message: "Rendering react email payload"
2167
+ });
2168
+ try {
2169
+ const normalizedInput = mergeRenderDefaults(input, runtimeOptions?.defaults);
2170
+ const element = await resolveReactEmailElement(normalizedInput);
2171
+ const renderModule = await resolveReactEmailRenderModule();
2172
+ const htmlValue = await renderModule.render(element);
2173
+ const renderedHtml = typeof htmlValue === "string" ? htmlValue : String(htmlValue ?? "");
2174
+ if (!renderedHtml.trim()) {
2175
+ throw new Error("react email renderer returned an empty HTML string");
2176
+ }
2177
+ let html = renderedHtml;
2178
+ if (normalizedInput.pretty && renderModule.pretty) {
2179
+ const prettyValue = await renderModule.pretty(renderedHtml);
2180
+ if (typeof prettyValue === "string" && prettyValue.trim().length > 0) {
2181
+ html = prettyValue;
2182
+ }
2183
+ }
2184
+ const explicitText = toStringOrUndefined(normalizedInput.text);
2185
+ if (explicitText !== void 0) {
2186
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
2187
+ route: runtimeOptions?.route,
2188
+ durationMs: Date.now() - start,
2189
+ message: "Rendered react email with explicit text"
2190
+ });
2191
+ return {
2192
+ html,
2193
+ text: explicitText
2194
+ };
2195
+ }
2196
+ if (normalizedInput.includePlainText === false || !renderModule.toPlainText) {
2197
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
2198
+ route: runtimeOptions?.route,
2199
+ durationMs: Date.now() - start,
2200
+ message: "Rendered react email without plain-text derivation"
2201
+ });
2202
+ return { html };
2203
+ }
2204
+ const plainTextValue = await renderModule.toPlainText(html);
2205
+ const plainText = toStringOrUndefined(plainTextValue);
2206
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
2207
+ route: runtimeOptions?.route,
2208
+ durationMs: Date.now() - start,
2209
+ message: plainText ? "Rendered react email with derived plain text" : "Rendered react email HTML only"
2210
+ });
2211
+ if (plainText === void 0) {
2212
+ return { html };
2213
+ }
2214
+ return {
2215
+ html,
2216
+ text: plainText
2217
+ };
2218
+ } catch (error) {
2219
+ const message = error instanceof Error ? error.message : String(error);
2220
+ emitReactEmailEvent(runtimeOptions?.observe, "render:error", {
2221
+ route: runtimeOptions?.route,
2222
+ durationMs: Date.now() - start,
2223
+ error: message,
2224
+ message: "Failed to render react email payload"
2225
+ });
2226
+ throw error;
2227
+ }
2228
+ }
2229
+ async function resolveReactEmailPayloadFields(input, fields, options) {
2230
+ const { react, ...payloadWithoutReact } = input;
2231
+ if (!react) {
2232
+ return payloadWithoutReact;
2233
+ }
2234
+ const rendered = await renderAthenaReactEmail(react, options);
2235
+ const payload = {
2236
+ ...payloadWithoutReact
2237
+ };
2238
+ payload[fields.htmlField] = rendered.html;
2239
+ const currentTextValue = payload[fields.textField];
2240
+ if (rendered.text !== void 0 && (currentTextValue === void 0 || currentTextValue === null || currentTextValue === "")) {
2241
+ payload[fields.textField] = rendered.text;
2242
+ }
2243
+ if (fields.variablesField && (payload[fields.variablesField] === void 0 || payload[fields.variablesField] === null) && isRecord3(react.props)) {
2244
+ const derivedVariables = Object.keys(react.props);
2245
+ if (derivedVariables.length > 0) {
2246
+ payload[fields.variablesField] = derivedVariables;
2247
+ }
2248
+ }
2249
+ return payload;
2250
+ }
2251
+
1707
2252
  // src/auth/client.ts
1708
2253
  var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
1709
2254
  var FALLBACK_SDK_VERSION2 = "1.0.0";
@@ -1713,7 +2258,7 @@ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
1713
2258
  function normalizeBaseUrl(baseUrl) {
1714
2259
  return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
1715
2260
  }
1716
- function isRecord3(value) {
2261
+ function isRecord4(value) {
1717
2262
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1718
2263
  }
1719
2264
  function normalizeHeaderValue2(value) {
@@ -1738,7 +2283,7 @@ function resolveRequestId2(headers) {
1738
2283
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
1739
2284
  }
1740
2285
  function resolveErrorMessage2(payload, fallback) {
1741
- if (isRecord3(payload)) {
2286
+ if (isRecord4(payload)) {
1742
2287
  const messageCandidates = [payload.error, payload.message, payload.details];
1743
2288
  for (const candidate of messageCandidates) {
1744
2289
  if (typeof candidate === "string" && candidate.trim().length > 0) {
@@ -2064,6 +2609,19 @@ function createAuthClient(config = {}) {
2064
2609
  options
2065
2610
  );
2066
2611
  };
2612
+ const withReactEmailRoute = (route) => ({
2613
+ ...resolvedConfig.reactEmail,
2614
+ route
2615
+ });
2616
+ const resolveAdminEmailPayload = (route, input) => resolveReactEmailPayloadFields(input, {
2617
+ htmlField: "htmlBody",
2618
+ textField: "textBody"
2619
+ }, withReactEmailRoute(route));
2620
+ const resolveAdminEmailTemplatePayload = (route, input) => resolveReactEmailPayloadFields(input, {
2621
+ htmlField: "htmlTemplate",
2622
+ textField: "textTemplate",
2623
+ variablesField: "variables"
2624
+ }, withReactEmailRoute(route));
2067
2625
  const listUserEmailsWithFallback = async (input, options) => {
2068
2626
  const primary = await getWithQuery(
2069
2627
  "/email/list",
@@ -2091,7 +2649,7 @@ function createAuthClient(config = {}) {
2091
2649
  data: null
2092
2650
  };
2093
2651
  }
2094
- const fallbackStatus = isRecord3(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
2652
+ const fallbackStatus = isRecord4(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
2095
2653
  return {
2096
2654
  ...fallback,
2097
2655
  data: {
@@ -2527,9 +3085,17 @@ function createAuthClient(config = {}) {
2527
3085
  email: {
2528
3086
  list: (input, options) => getWithQuery("/admin/email/list", input, options),
2529
3087
  get: (input, options) => getWithQuery("/admin/email/get", input, options),
2530
- create: (input, options) => postGeneric("/admin/email/create", input, options),
2531
- update: (input, options) => postGeneric("/admin/email/update", input, options),
2532
- delete: (input, options) => postGeneric("/admin/email/delete", input, options),
3088
+ create: async (input, options) => postGeneric(
3089
+ "/admin/email/create",
3090
+ await resolveAdminEmailPayload("/admin/email/create", input),
3091
+ options
3092
+ ),
3093
+ update: async (input, options) => postGeneric(
3094
+ "/admin/email/update",
3095
+ await resolveAdminEmailPayload("/admin/email/update", input),
3096
+ options
3097
+ ),
3098
+ delete: (input, options) => postGeneric("/admin/email/delete", input, options),
2533
3099
  failure: {
2534
3100
  list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
2535
3101
  get: (input, options) => getWithQuery("/admin/email-failure/get", input, options),
@@ -2540,17 +3106,33 @@ function createAuthClient(config = {}) {
2540
3106
  template: {
2541
3107
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
2542
3108
  get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
2543
- create: (input, options) => postGeneric("/admin/email-template/create", input, options),
2544
- update: (input, options) => postGeneric("/admin/email-template/update", input, options),
3109
+ create: async (input, options) => postGeneric(
3110
+ "/admin/email-template/create",
3111
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
3112
+ options
3113
+ ),
3114
+ update: async (input, options) => postGeneric(
3115
+ "/admin/email-template/update",
3116
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
3117
+ options
3118
+ ),
2545
3119
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
2546
3120
  }
2547
3121
  },
2548
3122
  emailTemplate: {
2549
3123
  get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
2550
- create: (input, options) => postGeneric("/admin/email-template/create", input, options),
3124
+ create: async (input, options) => postGeneric(
3125
+ "/admin/email-template/create",
3126
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
3127
+ options
3128
+ ),
2551
3129
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
2552
3130
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
2553
- update: (input, options) => postGeneric("/admin/email-template/update", input, options)
3131
+ update: async (input, options) => postGeneric(
3132
+ "/admin/email-template/update",
3133
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
3134
+ options
3135
+ )
2554
3136
  }
2555
3137
  },
2556
3138
  apiKey: {
@@ -2745,8 +3327,8 @@ function createAuthClient(config = {}) {
2745
3327
  // src/db/module.ts
2746
3328
  function createDbModule(input) {
2747
3329
  const db = {
2748
- from(table) {
2749
- return input.from(table);
3330
+ from(table, options) {
3331
+ return input.from(table, options);
2750
3332
  },
2751
3333
  select(table, columns, options) {
2752
3334
  return input.from(table).select(columns, options);
@@ -2773,17 +3355,551 @@ function createDbModule(input) {
2773
3355
  return db;
2774
3356
  }
2775
3357
 
3358
+ // src/query-ast.ts
3359
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
3360
+ var FILTER_OPERATORS = /* @__PURE__ */ new Set([
3361
+ "eq",
3362
+ "neq",
3363
+ "gt",
3364
+ "gte",
3365
+ "lt",
3366
+ "lte",
3367
+ "like",
3368
+ "ilike",
3369
+ "is",
3370
+ "in",
3371
+ "contains",
3372
+ "containedBy"
3373
+ ]);
3374
+ var BOOLEAN_SAFE_OPERATORS = /* @__PURE__ */ new Set([
3375
+ "eq",
3376
+ "neq",
3377
+ "gt",
3378
+ "gte",
3379
+ "lt",
3380
+ "lte",
3381
+ "like",
3382
+ "ilike",
3383
+ "is"
3384
+ ]);
3385
+ function isRecord5(value) {
3386
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3387
+ }
3388
+ function isUuidString(value) {
3389
+ return UUID_PATTERN.test(value.trim());
3390
+ }
3391
+ function isUuidIdentifierColumn(column) {
3392
+ return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
3393
+ }
3394
+ function shouldUseUuidTextComparison(column, value) {
3395
+ return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
3396
+ }
3397
+ function isRelationSelectNode(value) {
3398
+ return isRecord5(value) && isRecord5(value.select);
3399
+ }
3400
+ function normalizeIdentifier(value, label) {
3401
+ const normalized = value.trim();
3402
+ if (!normalized) {
3403
+ throw new Error(`${label} must be a non-empty string`);
3404
+ }
3405
+ return normalized;
3406
+ }
3407
+ function stringifyFilterValue(value) {
3408
+ if (Array.isArray(value)) {
3409
+ return value.join(",");
3410
+ }
3411
+ return String(value);
3412
+ }
3413
+ function buildGatewayCondition(operator, column, value) {
3414
+ const condition = { operator };
3415
+ if (column) {
3416
+ condition.column = column;
3417
+ if (operator === "eq") {
3418
+ condition.eq_column = column;
3419
+ }
3420
+ }
3421
+ if (value !== void 0) {
3422
+ condition.value = value;
3423
+ if (operator === "eq") {
3424
+ condition.eq_value = value;
3425
+ }
3426
+ }
3427
+ if (operator === "eq" && column && value !== void 0 && shouldUseUuidTextComparison(column, value)) {
3428
+ condition.column_cast = "text";
3429
+ condition.eq_column_cast = "text";
3430
+ }
3431
+ return condition;
3432
+ }
3433
+ function compileRelationToken(key, node) {
3434
+ const nested = compileSelectShape(node.select);
3435
+ const propertyKey = normalizeIdentifier(key, "select relation key");
3436
+ if (node.schema && node.via) {
3437
+ throw new Error(
3438
+ `findMany relation "${propertyKey}" cannot combine schema and via yet; use schema with the relation key, or use via without schema`
3439
+ );
3440
+ }
3441
+ const relationTokenBase = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
3442
+ if (node.schema && relationTokenBase.includes(".")) {
3443
+ throw new Error(
3444
+ `findMany relation "${propertyKey}" already resolves to a qualified relation token; do not also set schema`
3445
+ );
3446
+ }
3447
+ const relationSchema = node.schema?.trim();
3448
+ const relationToken = relationSchema ? `${normalizeIdentifier(relationSchema, "select relation schema")}.${relationTokenBase}` : relationTokenBase;
3449
+ const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
3450
+ const prefix = alias ? `${alias}:` : "";
3451
+ return `${prefix}${relationToken}(${nested})`;
3452
+ }
3453
+ function compileSelectShape(select) {
3454
+ if (!isRecord5(select)) {
3455
+ throw new Error("findMany select must be an object");
3456
+ }
3457
+ const tokens = [];
3458
+ for (const [rawKey, rawValue] of Object.entries(select)) {
3459
+ if (rawValue === void 0) {
3460
+ continue;
3461
+ }
3462
+ if (rawValue === true) {
3463
+ tokens.push(normalizeIdentifier(rawKey, "select column"));
3464
+ continue;
3465
+ }
3466
+ if (isRelationSelectNode(rawValue)) {
3467
+ tokens.push(compileRelationToken(rawKey, rawValue));
3468
+ continue;
3469
+ }
3470
+ throw new Error(`Unsupported select node for "${rawKey}"`);
3471
+ }
3472
+ if (tokens.length === 0) {
3473
+ throw new Error("findMany select requires at least one field");
3474
+ }
3475
+ return tokens.join(",");
3476
+ }
3477
+ function selectShapeUsesRelationSchema(select) {
3478
+ if (!isRecord5(select)) {
3479
+ return false;
3480
+ }
3481
+ for (const rawValue of Object.values(select)) {
3482
+ if (!isRelationSelectNode(rawValue)) {
3483
+ continue;
3484
+ }
3485
+ if (typeof rawValue.schema === "string" && rawValue.schema.trim().length > 0) {
3486
+ return true;
3487
+ }
3488
+ if (selectShapeUsesRelationSchema(rawValue.select)) {
3489
+ return true;
3490
+ }
3491
+ }
3492
+ return false;
3493
+ }
3494
+ function compileColumnWhere(column, input) {
3495
+ const normalizedColumn = normalizeIdentifier(column, "where column");
3496
+ if (!isRecord5(input)) {
3497
+ return [buildGatewayCondition("eq", normalizedColumn, input)];
3498
+ }
3499
+ const conditions = [];
3500
+ for (const [rawOperator, rawValue] of Object.entries(input)) {
3501
+ if (rawValue === void 0) {
3502
+ continue;
3503
+ }
3504
+ if (!FILTER_OPERATORS.has(rawOperator)) {
3505
+ throw new Error(`Unsupported where operator "${rawOperator}" on "${normalizedColumn}"`);
3506
+ }
3507
+ if ((rawOperator === "in" || rawOperator === "contains" || rawOperator === "containedBy") && !Array.isArray(rawValue)) {
3508
+ throw new Error(`where.${normalizedColumn}.${rawOperator} requires an array value`);
3509
+ }
3510
+ conditions.push(
3511
+ buildGatewayCondition(
3512
+ rawOperator,
3513
+ normalizedColumn,
3514
+ rawValue
3515
+ )
3516
+ );
3517
+ }
3518
+ if (conditions.length === 0) {
3519
+ throw new Error(`where.${normalizedColumn} requires at least one operator`);
3520
+ }
3521
+ return conditions;
3522
+ }
3523
+ function compileBooleanExpressionTerms(clause, label) {
3524
+ if (!isRecord5(clause)) {
3525
+ throw new Error(`findMany where.${label} clauses must be objects`);
3526
+ }
3527
+ const entries = Object.entries(clause).filter(([, value]) => value !== void 0);
3528
+ if (entries.length !== 1) {
3529
+ throw new Error(`findMany where.${label} clauses must target exactly one column`);
3530
+ }
3531
+ const [rawColumn, rawValue] = entries[0];
3532
+ const column = normalizeIdentifier(rawColumn, `where.${label} column`);
3533
+ if (!isRecord5(rawValue)) {
3534
+ return [`${column}.eq.${stringifyFilterValue(rawValue)}`];
3535
+ }
3536
+ const operatorEntries = Object.entries(rawValue).filter(([, value]) => value !== void 0);
3537
+ if (operatorEntries.length === 0) {
3538
+ throw new Error(`findMany where.${label}.${column} requires at least one operator`);
3539
+ }
3540
+ if (label === "not" && operatorEntries.length > 1) {
3541
+ throw new Error("findMany where.not only supports a single lossless operator expression");
3542
+ }
3543
+ return operatorEntries.map(([rawOperator, rawOperand]) => {
3544
+ if (!BOOLEAN_SAFE_OPERATORS.has(rawOperator)) {
3545
+ throw new Error(`findMany where.${label} only supports lossless scalar operators`);
3546
+ }
3547
+ if (Array.isArray(rawOperand)) {
3548
+ throw new Error(`findMany where.${label} does not support array-valued operators`);
3549
+ }
3550
+ return `${column}.${rawOperator}.${stringifyFilterValue(rawOperand)}`;
3551
+ });
3552
+ }
3553
+ function compileWhere(where) {
3554
+ if (where === void 0) {
3555
+ return void 0;
3556
+ }
3557
+ if (!isRecord5(where)) {
3558
+ throw new Error("findMany where must be an object");
3559
+ }
3560
+ const conditions = [];
3561
+ for (const [rawKey, rawValue] of Object.entries(where)) {
3562
+ if (rawValue === void 0) {
3563
+ continue;
3564
+ }
3565
+ if (rawKey === "or") {
3566
+ if (!Array.isArray(rawValue) || rawValue.length === 0) {
3567
+ throw new Error("findMany where.or must be a non-empty array");
3568
+ }
3569
+ const expressions = rawValue.flatMap(
3570
+ (value) => compileBooleanExpressionTerms(value, "or")
3571
+ );
3572
+ conditions.push(buildGatewayCondition("or", void 0, expressions.join(",")));
3573
+ continue;
3574
+ }
3575
+ if (rawKey === "not") {
3576
+ const expressions = compileBooleanExpressionTerms(rawValue, "not");
3577
+ if (expressions.length !== 1) {
3578
+ throw new Error("findMany where.not must compile to exactly one lossless expression");
3579
+ }
3580
+ conditions.push(buildGatewayCondition("not", void 0, expressions[0]));
3581
+ continue;
3582
+ }
3583
+ conditions.push(...compileColumnWhere(rawKey, rawValue));
3584
+ }
3585
+ return conditions.length > 0 ? conditions : void 0;
3586
+ }
3587
+ function resolveOrderDirection(input) {
3588
+ if (typeof input === "boolean") {
3589
+ return input === false ? "descending" : "ascending";
3590
+ }
3591
+ if (typeof input === "string") {
3592
+ const normalized = input.trim().toLowerCase();
3593
+ if (normalized === "asc" || normalized === "ascending") {
3594
+ return "ascending";
3595
+ }
3596
+ if (normalized === "desc" || normalized === "descending") {
3597
+ return "descending";
3598
+ }
3599
+ throw new Error(`Unsupported orderBy direction "${input}"`);
3600
+ }
3601
+ return input.ascending === false ? "descending" : "ascending";
3602
+ }
3603
+ function compileOrderBy(orderBy) {
3604
+ if (orderBy === void 0) {
3605
+ return void 0;
3606
+ }
3607
+ if (!isRecord5(orderBy)) {
3608
+ throw new Error("findMany orderBy must be an object");
3609
+ }
3610
+ if ("column" in orderBy) {
3611
+ return {
3612
+ field: normalizeIdentifier(String(orderBy.column), "orderBy column"),
3613
+ direction: orderBy.ascending === false ? "descending" : "ascending"
3614
+ };
3615
+ }
3616
+ const entries = Object.entries(orderBy).filter(([, value]) => value !== void 0);
3617
+ if (entries.length === 0) {
3618
+ return void 0;
3619
+ }
3620
+ if (entries.length > 1) {
3621
+ throw new Error("findMany orderBy only supports a single column in v1");
3622
+ }
3623
+ const [column, input] = entries[0];
3624
+ return {
3625
+ field: normalizeIdentifier(column, "orderBy column"),
3626
+ direction: resolveOrderDirection(input)
3627
+ };
3628
+ }
3629
+
3630
+ // src/gateway/structured-select.ts
3631
+ var IDENTIFIER_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
3632
+ function isIdentifierPath(value) {
3633
+ const segments = value.split(".").map((segment) => segment.trim());
3634
+ return segments.length > 1 && segments.every((segment) => IDENTIFIER_SEGMENT_PATTERN.test(segment));
3635
+ }
3636
+ function extractRelationHead(raw) {
3637
+ const trimmed = raw.trim();
3638
+ if (!trimmed) return "";
3639
+ const aliasIndex = trimmed.indexOf(":");
3640
+ const withoutAlias = aliasIndex >= 0 ? trimmed.slice(aliasIndex + 1).trim() : trimmed;
3641
+ const modifierIndex = withoutAlias.indexOf("!");
3642
+ return (modifierIndex >= 0 ? withoutAlias.slice(0, modifierIndex) : withoutAlias).trim();
3643
+ }
3644
+ function hasSchemaQualifiedRelationToken(select) {
3645
+ let singleQuoted = false;
3646
+ let doubleQuoted = false;
3647
+ let tokenStart = 0;
3648
+ for (let index = 0; index < select.length; index += 1) {
3649
+ const char = select[index];
3650
+ const next = index + 1 < select.length ? select[index + 1] : "";
3651
+ if (singleQuoted) {
3652
+ if (char === "'" && next === "'") {
3653
+ index += 1;
3654
+ continue;
3655
+ }
3656
+ if (char === "'") {
3657
+ singleQuoted = false;
3658
+ }
3659
+ continue;
3660
+ }
3661
+ if (doubleQuoted) {
3662
+ if (char === '"' && next === '"') {
3663
+ index += 1;
3664
+ continue;
3665
+ }
3666
+ if (char === '"') {
3667
+ doubleQuoted = false;
3668
+ }
3669
+ continue;
3670
+ }
3671
+ if (char === "'") {
3672
+ singleQuoted = true;
3673
+ continue;
3674
+ }
3675
+ if (char === '"') {
3676
+ doubleQuoted = true;
3677
+ continue;
3678
+ }
3679
+ if (char === "(") {
3680
+ const relationHead = extractRelationHead(select.slice(tokenStart, index));
3681
+ if (isIdentifierPath(relationHead)) {
3682
+ return true;
3683
+ }
3684
+ tokenStart = index + 1;
3685
+ continue;
3686
+ }
3687
+ if (char === "," || char === ")") {
3688
+ tokenStart = index + 1;
3689
+ }
3690
+ }
3691
+ return false;
3692
+ }
3693
+ function toStructuredSelectString(columns) {
3694
+ return Array.isArray(columns) ? columns.join(",") : columns;
3695
+ }
3696
+ function buildStructuredWhere(conditions) {
3697
+ if (!conditions?.length) return void 0;
3698
+ const where = {};
3699
+ for (const condition of conditions) {
3700
+ if (!condition.column) {
3701
+ return null;
3702
+ }
3703
+ if (condition.column_cast !== void 0 || condition.value_cast !== void 0) {
3704
+ return null;
3705
+ }
3706
+ const operand = condition.value;
3707
+ const operator = condition.operator;
3708
+ if (operator === "eq") {
3709
+ if (operand === void 0) return null;
3710
+ } else if (operator === "neq" || operator === "gt" || operator === "lt") {
3711
+ if (operand === void 0) return null;
3712
+ } else if (operator === "in") {
3713
+ if (!Array.isArray(operand)) return null;
3714
+ } else {
3715
+ return null;
3716
+ }
3717
+ const existing = where[condition.column];
3718
+ if (existing !== void 0 && (typeof existing !== "object" || existing === null || Array.isArray(existing))) {
3719
+ return null;
3720
+ }
3721
+ const next = existing ?? {};
3722
+ if (Object.prototype.hasOwnProperty.call(next, operator)) {
3723
+ return null;
3724
+ }
3725
+ next[operator] = operand;
3726
+ where[condition.column] = next;
3727
+ }
3728
+ return where;
3729
+ }
3730
+ function buildStructuredOrderBy(order) {
3731
+ if (!order?.field) return void 0;
3732
+ return {
3733
+ [order.field]: order.direction === "descending" ? "desc" : "asc"
3734
+ };
3735
+ }
3736
+ function buildStructuredSelectTransport(input) {
3737
+ const select = toStructuredSelectString(input.columns).trim();
3738
+ if (!select || select === "*") {
3739
+ return null;
3740
+ }
3741
+ if (!hasSchemaQualifiedRelationToken(select)) {
3742
+ return null;
3743
+ }
3744
+ if (input.count !== void 0 || input.head !== void 0) {
3745
+ return {
3746
+ error: "Schema-qualified nested select strings require structured select transport, which does not support count/head options in athena-js yet."
3747
+ };
3748
+ }
3749
+ const where = buildStructuredWhere(input.conditions);
3750
+ if (where === null) {
3751
+ return {
3752
+ error: "Schema-qualified nested select strings only support eq, neq, gt, lt, and in filters in athena-js structured select transport."
3753
+ };
3754
+ }
3755
+ return {
3756
+ select,
3757
+ payload: {
3758
+ table_name: input.tableName,
3759
+ select,
3760
+ where,
3761
+ orderBy: buildStructuredOrderBy(input.order),
3762
+ limit: input.limit,
3763
+ offset: input.offset,
3764
+ strip_nulls: input.stripNulls
3765
+ }
3766
+ };
3767
+ }
3768
+
3769
+ // src/query-transport.ts
3770
+ function canUseFindManyAstTransport(state) {
3771
+ return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
3772
+ }
3773
+ function toFindManyAstOrder(order) {
3774
+ if (!order) {
3775
+ return void 0;
3776
+ }
3777
+ return {
3778
+ column: order.field,
3779
+ ascending: order.direction !== "descending"
3780
+ };
3781
+ }
3782
+ function resolvePagination(input) {
3783
+ let limit = input.limit;
3784
+ let offset = input.offset;
3785
+ if (limit === void 0 && input.pageSize !== void 0) {
3786
+ limit = Math.max(0, Math.trunc(input.pageSize));
3787
+ }
3788
+ if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
3789
+ offset = (Math.trunc(input.currentPage) - 1) * Math.max(0, Math.trunc(input.pageSize));
3790
+ }
3791
+ return { limit, offset };
3792
+ }
3793
+ function hasTypedEqualityComparison(conditions) {
3794
+ return conditions?.some(
3795
+ (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
3796
+ ) ?? false;
3797
+ }
3798
+ function createSelectTransportPlan(input) {
3799
+ const conditions = input.state.conditions.length ? input.state.conditions.map((condition) => ({ ...condition })) : void 0;
3800
+ if (hasTypedEqualityComparison(conditions) && !input.options?.head && !input.options?.count && conditions) {
3801
+ const query = input.buildTypedSelectQuery({
3802
+ tableName: input.tableName,
3803
+ columns: input.columns,
3804
+ conditions,
3805
+ limit: input.state.limit,
3806
+ offset: input.state.offset,
3807
+ currentPage: input.state.currentPage,
3808
+ pageSize: input.state.pageSize,
3809
+ order: input.state.order
3810
+ });
3811
+ if (query) {
3812
+ return {
3813
+ kind: "query",
3814
+ query,
3815
+ payload: { query }
3816
+ };
3817
+ }
3818
+ }
3819
+ const pagination = resolvePagination({
3820
+ limit: input.state.limit,
3821
+ offset: input.state.offset,
3822
+ currentPage: input.state.currentPage,
3823
+ pageSize: input.state.pageSize
3824
+ });
3825
+ const stripNulls = input.options?.stripNulls ?? true;
3826
+ const structuredSelectTransport = buildStructuredSelectTransport({
3827
+ tableName: input.tableName,
3828
+ columns: input.columns,
3829
+ conditions,
3830
+ limit: pagination.limit,
3831
+ offset: pagination.offset,
3832
+ order: input.state.order,
3833
+ stripNulls,
3834
+ count: input.options?.count,
3835
+ head: input.options?.head
3836
+ });
3837
+ if (structuredSelectTransport && "error" in structuredSelectTransport) {
3838
+ throw new Error(structuredSelectTransport.error);
3839
+ }
3840
+ if (structuredSelectTransport) {
3841
+ const { payload, select } = structuredSelectTransport;
3842
+ return {
3843
+ kind: "fetch",
3844
+ payload,
3845
+ debug: {
3846
+ columns: select,
3847
+ conditions,
3848
+ limit: pagination.limit,
3849
+ offset: pagination.offset,
3850
+ order: input.state.order
3851
+ }
3852
+ };
3853
+ }
3854
+ return {
3855
+ kind: "fetch",
3856
+ payload: {
3857
+ table_name: input.tableName,
3858
+ columns: input.columns,
3859
+ conditions,
3860
+ limit: input.state.limit,
3861
+ offset: input.state.offset,
3862
+ current_page: input.state.currentPage,
3863
+ page_size: input.state.pageSize,
3864
+ total_pages: input.state.totalPages,
3865
+ sort_by: input.state.order,
3866
+ strip_nulls: stripNulls,
3867
+ count: input.options?.count,
3868
+ head: input.options?.head
3869
+ },
3870
+ debug: {
3871
+ columns: input.columns,
3872
+ conditions,
3873
+ limit: input.state.limit,
3874
+ offset: input.state.offset,
3875
+ currentPage: input.state.currentPage,
3876
+ pageSize: input.state.pageSize,
3877
+ order: input.state.order
3878
+ }
3879
+ };
3880
+ }
3881
+
2776
3882
  // src/client.ts
2777
3883
  var DEFAULT_COLUMNS = "*";
2778
- var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
2779
3884
  var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
2780
3885
  var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
3886
+ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
3887
+ "src\\client.ts",
3888
+ "src/client.ts",
3889
+ "dist\\client.",
3890
+ "dist/client.",
3891
+ "node_modules\\@xylex-group\\athena",
3892
+ "node_modules/@xylex-group/athena",
3893
+ "node:internal",
3894
+ "internal/process"
3895
+ ];
2781
3896
  function formatResult(response) {
2782
3897
  const result = {
2783
3898
  data: response.data ?? null,
2784
- error: response.error ?? null,
3899
+ error: null,
2785
3900
  errorDetails: response.errorDetails ?? null,
2786
3901
  status: response.status,
3902
+ statusText: response.statusText ?? null,
2787
3903
  raw: response.raw
2788
3904
  };
2789
3905
  if (response.count !== void 0) {
@@ -2800,19 +3916,236 @@ function attachNormalizedError(result, normalizedError) {
2800
3916
  });
2801
3917
  }
2802
3918
  function createResultFormatter(experimental) {
2803
- if (!experimental?.enableErrorNormalization) {
2804
- return formatResult;
2805
- }
2806
3919
  return (response, context) => {
2807
3920
  const result = formatResult(response);
2808
- if (result.error == null) {
3921
+ if (response.error == null && response.errorDetails == null) {
2809
3922
  return result;
2810
3923
  }
2811
- const normalizedError = normalizeAthenaError(result, context);
3924
+ const normalizedError = normalizeAthenaError(
3925
+ {
3926
+ ...result,
3927
+ error: response.error ?? response.errorDetails?.message ?? null
3928
+ },
3929
+ context
3930
+ );
3931
+ result.error = createResultError(response, result, normalizedError);
2812
3932
  attachNormalizedError(result, normalizedError);
2813
3933
  return result;
2814
3934
  };
2815
3935
  }
3936
+ function isRecord6(value) {
3937
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3938
+ }
3939
+ function firstNonEmptyString2(...values) {
3940
+ for (const value of values) {
3941
+ if (typeof value === "string" && value.trim().length > 0) {
3942
+ return value.trim();
3943
+ }
3944
+ }
3945
+ return void 0;
3946
+ }
3947
+ function resolveStructuredErrorPayload2(raw) {
3948
+ if (!isRecord6(raw)) return null;
3949
+ return isRecord6(raw.error) ? raw.error : raw;
3950
+ }
3951
+ function resolveStructuredErrorDetails(payload, message) {
3952
+ if (!payload || !("details" in payload)) {
3953
+ return null;
3954
+ }
3955
+ const details = payload.details;
3956
+ if (details == null) {
3957
+ return null;
3958
+ }
3959
+ if (typeof details === "string" && details.trim() === message.trim()) {
3960
+ return null;
3961
+ }
3962
+ return details;
3963
+ }
3964
+ function createResultError(response, result, normalized) {
3965
+ const rawRecord = isRecord6(response.raw) ? response.raw : null;
3966
+ const payload = resolveStructuredErrorPayload2(response.raw);
3967
+ const message = firstNonEmptyString2(
3968
+ response.error,
3969
+ payload?.message,
3970
+ payload?.error,
3971
+ payload?.details,
3972
+ response.errorDetails?.message,
3973
+ normalized.message
3974
+ ) ?? normalized.message;
3975
+ const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
3976
+ const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
3977
+ const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
3978
+ const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
3979
+ return {
3980
+ message,
3981
+ code,
3982
+ athenaCode: normalized.code,
3983
+ gatewayCode: response.errorDetails?.code ?? null,
3984
+ kind: normalized.kind,
3985
+ category: normalized.category,
3986
+ retryable: normalized.retryable,
3987
+ details,
3988
+ hint,
3989
+ status: result.status,
3990
+ statusText,
3991
+ constraint: normalized.constraint,
3992
+ table: normalized.table,
3993
+ operation: normalized.operation,
3994
+ endpoint: response.errorDetails?.endpoint,
3995
+ method: response.errorDetails?.method,
3996
+ requestId: response.errorDetails?.requestId,
3997
+ cause: response.errorDetails?.cause,
3998
+ raw: result.raw
3999
+ };
4000
+ }
4001
+ function parseQueryTraceCallsiteFrame(frame) {
4002
+ const trimmed = frame.trim();
4003
+ if (!trimmed) {
4004
+ return null;
4005
+ }
4006
+ let body = trimmed.replace(/^at\s+/, "");
4007
+ if (body.startsWith("async ")) {
4008
+ body = body.slice(6);
4009
+ }
4010
+ let functionName;
4011
+ let location = body;
4012
+ const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
4013
+ if (wrappedMatch) {
4014
+ functionName = wrappedMatch[1].trim() || void 0;
4015
+ location = wrappedMatch[2].trim();
4016
+ }
4017
+ const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
4018
+ if (!locationMatch) {
4019
+ return null;
4020
+ }
4021
+ const filePath = locationMatch[1].replace(/^file:\/\//, "");
4022
+ const line = Number(locationMatch[2]);
4023
+ const column = Number(locationMatch[3]);
4024
+ if (!Number.isFinite(line) || !Number.isFinite(column)) {
4025
+ return null;
4026
+ }
4027
+ const normalizedPath = filePath.replace(/\\/g, "/");
4028
+ const fileName = normalizedPath.split("/").at(-1) ?? filePath;
4029
+ return {
4030
+ filePath,
4031
+ fileName,
4032
+ line,
4033
+ column,
4034
+ frame: trimmed,
4035
+ functionName
4036
+ };
4037
+ }
4038
+ function captureQueryTraceCallsite() {
4039
+ const stack = new Error().stack;
4040
+ if (!stack) return null;
4041
+ const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
4042
+ for (const frame of frames) {
4043
+ if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
4044
+ continue;
4045
+ }
4046
+ const callsite = parseQueryTraceCallsiteFrame(frame);
4047
+ if (callsite) return callsite;
4048
+ }
4049
+ const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
4050
+ return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
4051
+ }
4052
+ function defaultQueryTraceLogger(event) {
4053
+ const target = event.table ?? event.functionName ?? "gateway";
4054
+ const outcomeState = event.outcome?.error ? "error" : "ok";
4055
+ const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
4056
+ console.info(banner, event);
4057
+ }
4058
+ function captureTraceCallsite(tracer) {
4059
+ return tracer?.captureCallsite() ?? null;
4060
+ }
4061
+ function createTraceCallsiteStore(tracer, initialCallsite) {
4062
+ let storedCallsite = initialCallsite ?? void 0;
4063
+ return {
4064
+ resolve(callsite) {
4065
+ if (callsite) {
4066
+ storedCallsite = callsite;
4067
+ return callsite;
4068
+ }
4069
+ if (storedCallsite !== void 0) {
4070
+ return storedCallsite;
4071
+ }
4072
+ const capturedCallsite = captureTraceCallsite(tracer);
4073
+ if (capturedCallsite) {
4074
+ storedCallsite = capturedCallsite;
4075
+ }
4076
+ return capturedCallsite;
4077
+ }
4078
+ };
4079
+ }
4080
+ function createQueryTracer(experimental) {
4081
+ const traceOption = experimental?.traceQueries;
4082
+ if (!traceOption) {
4083
+ return void 0;
4084
+ }
4085
+ const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
4086
+ const emit = (event) => {
4087
+ try {
4088
+ logger(event);
4089
+ } catch (error) {
4090
+ console.warn("[athena-js][trace] logger failed", error);
4091
+ }
4092
+ };
4093
+ return {
4094
+ captureCallsite: captureQueryTraceCallsite,
4095
+ publishSuccess(context, result, durationMs, callsite) {
4096
+ emit({
4097
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4098
+ durationMs,
4099
+ operation: context.operation,
4100
+ endpoint: context.endpoint,
4101
+ table: context.table,
4102
+ functionName: context.functionName,
4103
+ sql: context.sql,
4104
+ payload: context.payload,
4105
+ options: context.options,
4106
+ callsite,
4107
+ outcome: {
4108
+ status: result.status,
4109
+ error: result.error,
4110
+ errorDetails: result.errorDetails ?? null,
4111
+ count: result.count ?? null,
4112
+ data: result.data,
4113
+ raw: result.raw
4114
+ }
4115
+ });
4116
+ },
4117
+ publishFailure(context, error, durationMs, callsite) {
4118
+ emit({
4119
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4120
+ durationMs,
4121
+ operation: context.operation,
4122
+ endpoint: context.endpoint,
4123
+ table: context.table,
4124
+ functionName: context.functionName,
4125
+ sql: context.sql,
4126
+ payload: context.payload,
4127
+ options: context.options,
4128
+ callsite,
4129
+ thrownError: error
4130
+ });
4131
+ }
4132
+ };
4133
+ }
4134
+ async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
4135
+ if (!tracer) {
4136
+ return runner();
4137
+ }
4138
+ const callsite = callsiteOverride ?? tracer.captureCallsite();
4139
+ const startedAt = Date.now();
4140
+ try {
4141
+ const result = await runner();
4142
+ tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
4143
+ return result;
4144
+ } catch (error) {
4145
+ tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
4146
+ throw error;
4147
+ }
4148
+ }
2816
4149
  function toSingleResult(response) {
2817
4150
  const payload = response.data;
2818
4151
  const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
@@ -2833,15 +4166,16 @@ function asAthenaJsonObject(value) {
2833
4166
  function asAthenaJsonObjectArray(values) {
2834
4167
  return values;
2835
4168
  }
2836
- function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
4169
+ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
2837
4170
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
2838
4171
  let selectedOptions;
2839
4172
  let promise = null;
2840
- const run = (columns, options) => {
4173
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
4174
+ const run = (columns, options, callsite) => {
2841
4175
  const payloadColumns = columns ?? selectedColumns;
2842
4176
  const payloadOptions = options ?? selectedOptions;
2843
4177
  if (!promise) {
2844
- promise = executor(payloadColumns, payloadOptions);
4178
+ promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
2845
4179
  }
2846
4180
  return promise;
2847
4181
  };
@@ -2849,7 +4183,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2849
4183
  select(columns = selectedColumns, options) {
2850
4184
  selectedColumns = columns;
2851
4185
  selectedOptions = options ?? selectedOptions;
2852
- return run(columns, options);
4186
+ return run(columns, options, captureTraceCallsite(tracer));
2853
4187
  },
2854
4188
  returning(columns = selectedColumns, options) {
2855
4189
  return mutationQuery.select(columns, options);
@@ -2857,7 +4191,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2857
4191
  single(columns = selectedColumns, options) {
2858
4192
  selectedColumns = columns;
2859
4193
  selectedOptions = options ?? selectedOptions;
2860
- return run(columns, options).then(toSingleResult);
4194
+ return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
2861
4195
  },
2862
4196
  maybeSingle(columns = selectedColumns, options) {
2863
4197
  return mutationQuery.single(columns, options);
@@ -2880,21 +4214,12 @@ function getResourceId(state) {
2880
4214
  );
2881
4215
  return candidate?.value?.toString();
2882
4216
  }
2883
- function stringifyFilterValue(value) {
4217
+ function stringifyFilterValue2(value) {
2884
4218
  if (Array.isArray(value)) {
2885
4219
  return value.join(",");
2886
4220
  }
2887
4221
  return String(value);
2888
4222
  }
2889
- function isUuidString(value) {
2890
- return UUID_PATTERN.test(value.trim());
2891
- }
2892
- function isUuidIdentifierColumn(column) {
2893
- return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
2894
- }
2895
- function shouldUseUuidTextComparison(column, value) {
2896
- return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
2897
- }
2898
4223
  function normalizeCast(cast) {
2899
4224
  const normalized = cast.trim().toLowerCase();
2900
4225
  if (!SAFE_CAST_PATTERN.test(normalized)) {
@@ -2917,25 +4242,92 @@ function withCast(expression, cast) {
2917
4242
  }
2918
4243
  function buildSelectColumnsClause(columns) {
2919
4244
  if (Array.isArray(columns)) {
2920
- return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
4245
+ return columns.map((column) => quoteSelectColumnToken(column)).join(", ");
2921
4246
  }
2922
4247
  return quoteSelectColumnsExpression(columns);
2923
4248
  }
4249
+ function parseIdentifierSegment(input) {
4250
+ const trimmed = input.trim();
4251
+ if (!trimmed) return null;
4252
+ if (!trimmed.startsWith('"')) {
4253
+ return {
4254
+ normalizedValue: trimmed.toLowerCase()
4255
+ };
4256
+ }
4257
+ let value = "";
4258
+ let index = 1;
4259
+ let closed = false;
4260
+ while (index < trimmed.length) {
4261
+ const char = trimmed[index];
4262
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
4263
+ if (char === '"' && next === '"') {
4264
+ value += '"';
4265
+ index += 2;
4266
+ continue;
4267
+ }
4268
+ if (char === '"') {
4269
+ closed = true;
4270
+ index += 1;
4271
+ break;
4272
+ }
4273
+ value += char;
4274
+ index += 1;
4275
+ }
4276
+ if (!closed || trimmed.slice(index).trim().length > 0 || !value.trim()) {
4277
+ return null;
4278
+ }
4279
+ return {
4280
+ normalizedValue: value
4281
+ };
4282
+ }
4283
+ function splitQualifiedTableName(tableName) {
4284
+ const trimmed = tableName.trim();
4285
+ let inQuotes = false;
4286
+ for (let index = 0; index < trimmed.length; index += 1) {
4287
+ const char = trimmed[index];
4288
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
4289
+ if (char === '"') {
4290
+ if (inQuotes && next === '"') {
4291
+ index += 1;
4292
+ continue;
4293
+ }
4294
+ inQuotes = !inQuotes;
4295
+ continue;
4296
+ }
4297
+ if (char === "." && !inQuotes) {
4298
+ const schemaSegment = trimmed.slice(0, index).trim();
4299
+ const tableSegment = trimmed.slice(index + 1).trim();
4300
+ if (!schemaSegment || !tableSegment) {
4301
+ return null;
4302
+ }
4303
+ return { schemaSegment };
4304
+ }
4305
+ }
4306
+ return null;
4307
+ }
2924
4308
  function resolveTableNameForCall(tableName, schema) {
2925
4309
  if (!schema) return tableName;
2926
4310
  const normalizedSchema = schema.trim();
2927
4311
  if (!normalizedSchema) {
2928
4312
  throw new Error("schema option must be a non-empty string");
2929
4313
  }
2930
- if (tableName.includes(".")) {
2931
- if (tableName.startsWith(`${normalizedSchema}.`)) {
2932
- return tableName;
4314
+ const normalizedTableName = tableName.trim();
4315
+ const parsedSchema = parseIdentifierSegment(normalizedSchema);
4316
+ if (!parsedSchema) {
4317
+ throw new Error("schema option must be a non-empty string");
4318
+ }
4319
+ const qualified = splitQualifiedTableName(normalizedTableName);
4320
+ if (qualified) {
4321
+ const parsedTableSchema = parseIdentifierSegment(qualified.schemaSegment);
4322
+ const sameSchema = parsedTableSchema ? parsedTableSchema.normalizedValue === parsedSchema.normalizedValue : normalizedTableName.startsWith(`${normalizedSchema}.`);
4323
+ if (sameSchema) {
4324
+ return normalizedTableName;
2933
4325
  }
2934
4326
  throw new Error(
2935
- `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
4327
+ `schema option "${normalizedSchema}" conflicts with schema-qualified table "${normalizedTableName}"`
2936
4328
  );
2937
4329
  }
2938
- return `${normalizedSchema}.${tableName}`;
4330
+ return `${normalizedSchema}.${normalizedTableName}`;
2939
4331
  }
2940
4332
  function conditionToSqlClause(condition) {
2941
4333
  if (!condition.column) return null;
@@ -3013,6 +4405,226 @@ function buildTypedSelectQuery(input) {
3013
4405
  }
3014
4406
  return `${sqlParts.join(" ")};`;
3015
4407
  }
4408
+ function sanitizeSqlComment(comment) {
4409
+ return comment.replace(/\*\//g, "* /");
4410
+ }
4411
+ function toSqlJsonLiteral(value) {
4412
+ if (value === void 0) return "DEFAULT";
4413
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4414
+ return toSqlLiteral(value);
4415
+ }
4416
+ return `'${escapeSqlStringLiteral(JSON.stringify(value))}'::jsonb`;
4417
+ }
4418
+ function conditionToDebugSqlClause(condition) {
4419
+ const exact = conditionToSqlClause(condition);
4420
+ if (exact) return exact;
4421
+ const rawCondition = sanitizeSqlComment(JSON.stringify(condition));
4422
+ if (!condition.column) {
4423
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
4424
+ }
4425
+ const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
4426
+ const value = condition.value;
4427
+ const rhs = withCast(toSqlJsonLiteral(value), condition.value_cast);
4428
+ switch (condition.operator) {
4429
+ case "contains":
4430
+ return `${column} @> ${rhs}`;
4431
+ case "containedBy":
4432
+ return `${column} <@ ${rhs}`;
4433
+ case "not":
4434
+ return `TRUE /* NOT expression passthrough: ${rawCondition} */`;
4435
+ case "or":
4436
+ return `TRUE /* OR expression passthrough: ${rawCondition} */`;
4437
+ default:
4438
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
4439
+ }
4440
+ }
4441
+ function appendOrderLimitOffset(sqlParts, order, limit, offset) {
4442
+ if (order?.field) {
4443
+ const direction = order.direction === "descending" ? "DESC" : "ASC";
4444
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(order.field)} ${direction}`);
4445
+ }
4446
+ if (limit !== void 0) {
4447
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
4448
+ }
4449
+ if (offset !== void 0) {
4450
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
4451
+ }
4452
+ }
4453
+ function buildDebugSelectQuery(input) {
4454
+ const sqlParts = [
4455
+ `SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
4456
+ ];
4457
+ if (input.conditions?.length) {
4458
+ const whereClauses = input.conditions.map(conditionToDebugSqlClause);
4459
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
4460
+ }
4461
+ const pagination = resolvePagination(input);
4462
+ appendOrderLimitOffset(sqlParts, input.order, pagination.limit, pagination.offset);
4463
+ return `${sqlParts.join(" ")};`;
4464
+ }
4465
+ function resolveDebugTableIdentifier(tableName) {
4466
+ if (!tableName?.trim()) {
4467
+ return '"__unknown_table__"';
4468
+ }
4469
+ return quoteQualifiedIdentifier(tableName);
4470
+ }
4471
+ function buildInsertDebugSql(payload) {
4472
+ const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
4473
+ const columns = [];
4474
+ const seen = /* @__PURE__ */ new Set();
4475
+ for (const row of rows) {
4476
+ for (const column of Object.keys(row)) {
4477
+ if (seen.has(column)) continue;
4478
+ seen.add(column);
4479
+ columns.push(column);
4480
+ }
4481
+ }
4482
+ const sqlParts = [`INSERT INTO ${quoteQualifiedIdentifier(payload.table_name)}`];
4483
+ if (!rows.length || !columns.length) {
4484
+ sqlParts.push("DEFAULT VALUES");
4485
+ if (rows.length > 1) {
4486
+ sqlParts.push(`/* trace: ${rows.length} rows collapsed to DEFAULT VALUES */`);
4487
+ }
4488
+ } else {
4489
+ const valuesClause = rows.map((row) => {
4490
+ const values = columns.map((column) => {
4491
+ const hasColumn = Object.prototype.hasOwnProperty.call(row, column);
4492
+ if (!hasColumn) {
4493
+ return payload.default_to_null ? "NULL" : "DEFAULT";
4494
+ }
4495
+ const rowValue = row[column];
4496
+ return toSqlJsonLiteral(rowValue);
4497
+ });
4498
+ return `(${values.join(", ")})`;
4499
+ }).join(", ");
4500
+ const columnClause = columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
4501
+ sqlParts.push(`(${columnClause})`);
4502
+ sqlParts.push(`VALUES ${valuesClause}`);
4503
+ }
4504
+ if (payload.on_conflict) {
4505
+ const conflictColumns = Array.isArray(payload.on_conflict) ? payload.on_conflict.map((column) => quoteQualifiedIdentifier(column)).join(", ") : payload.on_conflict;
4506
+ if (payload.update_body && Object.keys(payload.update_body).length > 0) {
4507
+ const assignments = Object.entries(payload.update_body).map(
4508
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
4509
+ );
4510
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO UPDATE SET ${assignments.join(", ")}`);
4511
+ } else {
4512
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO NOTHING`);
4513
+ }
4514
+ }
4515
+ if (payload.columns) {
4516
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
4517
+ }
4518
+ return `${sqlParts.join(" ")};`;
4519
+ }
4520
+ function buildUpdateDebugSql(payload) {
4521
+ const set = payload.set ?? payload.data ?? {};
4522
+ const assignments = Object.entries(set).map(
4523
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
4524
+ );
4525
+ const sqlParts = [
4526
+ `UPDATE ${resolveDebugTableIdentifier(payload.table_name)} SET ${assignments.length ? assignments.join(", ") : "/* empty set */"}`
4527
+ ];
4528
+ if (payload.conditions?.length) {
4529
+ const whereClauses = payload.conditions.map(conditionToDebugSqlClause);
4530
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
4531
+ }
4532
+ const pagination = resolvePagination({
4533
+ currentPage: payload.current_page,
4534
+ pageSize: payload.page_size
4535
+ });
4536
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
4537
+ if (payload.columns) {
4538
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
4539
+ }
4540
+ return `${sqlParts.join(" ")};`;
4541
+ }
4542
+ function buildDeleteDebugSql(payload) {
4543
+ const sqlParts = [`DELETE FROM ${quoteQualifiedIdentifier(payload.table_name)}`];
4544
+ const whereClauses = [];
4545
+ if (payload.resource_id) {
4546
+ whereClauses.push(`"resource_id" = ${toSqlLiteral(payload.resource_id)}`);
4547
+ }
4548
+ if (payload.conditions?.length) {
4549
+ whereClauses.push(...payload.conditions.map(conditionToDebugSqlClause));
4550
+ }
4551
+ if (whereClauses.length) {
4552
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
4553
+ }
4554
+ const pagination = resolvePagination({
4555
+ currentPage: payload.current_page,
4556
+ pageSize: payload.page_size
4557
+ });
4558
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
4559
+ if (payload.columns) {
4560
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
4561
+ }
4562
+ return `${sqlParts.join(" ")};`;
4563
+ }
4564
+ function rpcFilterToSqlClause(filter) {
4565
+ const column = quoteQualifiedIdentifier(filter.column);
4566
+ const value = filter.value;
4567
+ switch (filter.operator) {
4568
+ case "eq":
4569
+ case "neq":
4570
+ case "gt":
4571
+ case "gte":
4572
+ case "lt":
4573
+ case "lte":
4574
+ case "like":
4575
+ case "ilike": {
4576
+ if (value === void 0 || Array.isArray(value)) {
4577
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4578
+ }
4579
+ const operatorMap = {
4580
+ eq: "=",
4581
+ neq: "!=",
4582
+ gt: ">",
4583
+ gte: ">=",
4584
+ lt: "<",
4585
+ lte: "<=",
4586
+ like: "LIKE",
4587
+ ilike: "ILIKE"
4588
+ };
4589
+ return `${column} ${operatorMap[filter.operator]} ${toSqlLiteral(value)}`;
4590
+ }
4591
+ case "is":
4592
+ if (value === null) return `${column} IS NULL`;
4593
+ if (value === true) return `${column} IS TRUE`;
4594
+ if (value === false) return `${column} IS FALSE`;
4595
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4596
+ case "in":
4597
+ if (!Array.isArray(value)) {
4598
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4599
+ }
4600
+ if (value.length === 0) return "FALSE";
4601
+ return `${column} IN (${value.map((item) => toSqlLiteral(item)).join(", ")})`;
4602
+ default:
4603
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4604
+ }
4605
+ }
4606
+ function buildRpcDebugSql(payload) {
4607
+ const argsEntries = payload.args ? Object.entries(payload.args) : [];
4608
+ const argsClause = argsEntries.map(([key, value]) => `${quoteQualifiedIdentifier(key)} => ${toSqlJsonLiteral(value)}`).join(", ");
4609
+ const functionRef = payload.schema ? `${quoteQualifiedIdentifier(payload.schema)}.${quoteQualifiedIdentifier(payload.function)}` : quoteQualifiedIdentifier(payload.function);
4610
+ const sqlParts = [
4611
+ `SELECT ${payload.select ? quoteSelectColumnsExpression(payload.select) : "*"} FROM ${functionRef}(${argsClause})`
4612
+ ];
4613
+ if (payload.filters?.length) {
4614
+ sqlParts.push(`WHERE ${payload.filters.map(rpcFilterToSqlClause).join(" AND ")}`);
4615
+ }
4616
+ if (payload.order?.column) {
4617
+ const direction = payload.order.ascending === false ? "DESC" : "ASC";
4618
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(payload.order.column)} ${direction}`);
4619
+ }
4620
+ if (payload.limit !== void 0) {
4621
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(payload.limit))}`);
4622
+ }
4623
+ if (payload.offset !== void 0) {
4624
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(payload.offset))}`);
4625
+ }
4626
+ return `${sqlParts.join(" ")};`;
4627
+ }
3016
4628
  function createFilterMethods(state, addCondition, self) {
3017
4629
  return {
3018
4630
  eq(column, value) {
@@ -3124,7 +4736,7 @@ function createFilterMethods(state, addCondition, self) {
3124
4736
  not(columnOrExpression, operator, value) {
3125
4737
  const expression = String(columnOrExpression);
3126
4738
  if (operator != null && value !== void 0) {
3127
- addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
4739
+ addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue2(value)}`);
3128
4740
  } else {
3129
4741
  addCondition("not", void 0, expression);
3130
4742
  }
@@ -3187,14 +4799,15 @@ function createRpcFilterMethods(filters, self) {
3187
4799
  }
3188
4800
  };
3189
4801
  }
3190
- function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
4802
+ function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
3191
4803
  const state = {
3192
4804
  filters: []
3193
4805
  };
3194
4806
  let selectedColumns;
3195
4807
  let selectedOptions;
3196
4808
  let promise = null;
3197
- const executeRpc = async (columns, options) => {
4809
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
4810
+ const executeRpc = async (columns, options, callsite) => {
3198
4811
  const mergedOptions = mergeOptions(baseOptions, options);
3199
4812
  const payload = {
3200
4813
  function: functionName,
@@ -3208,14 +4821,30 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
3208
4821
  offset: state.offset,
3209
4822
  order: state.order
3210
4823
  };
3211
- const response = await client.rpcGateway(payload, mergedOptions);
3212
- return formatGatewayResult(response, { operation: "rpc" });
4824
+ const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
4825
+ const sql = buildRpcDebugSql(payload);
4826
+ return executeWithQueryTrace(
4827
+ tracer,
4828
+ {
4829
+ operation: "rpc",
4830
+ endpoint,
4831
+ functionName,
4832
+ sql,
4833
+ payload,
4834
+ options: mergedOptions
4835
+ },
4836
+ async () => {
4837
+ const response = await client.rpcGateway(payload, mergedOptions);
4838
+ return formatGatewayResult(response, { operation: "rpc" });
4839
+ },
4840
+ callsite
4841
+ );
3213
4842
  };
3214
- const run = (columns, options) => {
4843
+ const run = (columns, options, callsite) => {
3215
4844
  const payloadColumns = columns ?? selectedColumns;
3216
4845
  const payloadOptions = options ?? selectedOptions;
3217
4846
  if (!promise) {
3218
- promise = executeRpc(payloadColumns, payloadOptions);
4847
+ promise = executeRpc(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
3219
4848
  }
3220
4849
  return promise;
3221
4850
  };
@@ -3225,10 +4854,10 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
3225
4854
  select(columns = selectedColumns, options) {
3226
4855
  selectedColumns = columns;
3227
4856
  selectedOptions = options ?? selectedOptions;
3228
- return run(columns, options);
4857
+ return run(columns, options, captureTraceCallsite(tracer));
3229
4858
  },
3230
4859
  async single(columns, options) {
3231
- const result = await run(columns, options);
4860
+ const result = await run(columns, options, captureTraceCallsite(tracer));
3232
4861
  return toSingleResult(result);
3233
4862
  },
3234
4863
  maybeSingle(columns, options) {
@@ -3263,7 +4892,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
3263
4892
  });
3264
4893
  return builder;
3265
4894
  }
3266
- function createTableBuilder(tableName, client, formatGatewayResult) {
4895
+ function createTableBuilder(tableName, client, formatGatewayResult, tracer, experimental) {
3267
4896
  const state = {
3268
4897
  conditions: []
3269
4898
  };
@@ -3295,70 +4924,103 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3295
4924
  }
3296
4925
  state.conditions.push(condition);
3297
4926
  };
4927
+ const snapshotState = () => ({
4928
+ conditions: state.conditions.map((condition) => ({ ...condition })),
4929
+ limit: state.limit,
4930
+ offset: state.offset,
4931
+ order: state.order ? { ...state.order } : void 0,
4932
+ currentPage: state.currentPage,
4933
+ pageSize: state.pageSize,
4934
+ totalPages: state.totalPages
4935
+ });
3298
4936
  const builder = {};
3299
4937
  const filterMethods = createFilterMethods(
3300
4938
  state,
3301
4939
  addCondition,
3302
4940
  builder
3303
4941
  );
3304
- const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
4942
+ const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
3305
4943
  const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
3306
- const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
3307
- const hasTypedEqualityComparison = conditions?.some(
3308
- (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
3309
- ) ?? false;
3310
- if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
3311
- const query = buildTypedSelectQuery({
3312
- tableName: resolvedTableName,
3313
- columns,
3314
- conditions,
3315
- limit: state.limit,
3316
- offset: state.offset,
3317
- currentPage: state.currentPage,
3318
- pageSize: state.pageSize,
3319
- order: state.order
3320
- });
3321
- if (query) {
3322
- const queryResponse = await client.queryGateway({ query }, options);
3323
- return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
3324
- }
3325
- }
3326
- const payload = {
3327
- table_name: resolvedTableName,
4944
+ const plan = createSelectTransportPlan({
4945
+ tableName: resolvedTableName,
3328
4946
  columns,
3329
- conditions,
3330
- limit: state.limit,
3331
- offset: state.offset,
3332
- current_page: state.currentPage,
3333
- page_size: state.pageSize,
3334
- total_pages: state.totalPages,
3335
- sort_by: state.order,
3336
- strip_nulls: options?.stripNulls ?? true,
3337
- count: options?.count,
3338
- head: options?.head
3339
- };
3340
- const response = await client.fetchGateway(payload, options);
3341
- return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4947
+ state: executionState,
4948
+ options,
4949
+ buildTypedSelectQuery
4950
+ });
4951
+ if (plan.kind === "query") {
4952
+ return executeWithQueryTrace(
4953
+ tracer,
4954
+ {
4955
+ operation: "select",
4956
+ endpoint: "/gateway/query",
4957
+ table: resolvedTableName,
4958
+ sql: plan.query,
4959
+ payload: plan.payload,
4960
+ options
4961
+ },
4962
+ async () => {
4963
+ const queryResponse = await client.queryGateway(plan.payload, options);
4964
+ return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
4965
+ },
4966
+ callsite
4967
+ );
4968
+ }
4969
+ const sql = buildDebugSelectQuery({
4970
+ tableName: resolvedTableName,
4971
+ ...plan.debug
4972
+ });
4973
+ return executeWithQueryTrace(
4974
+ tracer,
4975
+ {
4976
+ operation: "select",
4977
+ endpoint: "/gateway/fetch",
4978
+ table: resolvedTableName,
4979
+ sql,
4980
+ payload: plan.payload,
4981
+ options
4982
+ },
4983
+ async () => {
4984
+ const response = await client.fetchGateway(plan.payload, options);
4985
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4986
+ },
4987
+ callsite
4988
+ );
3342
4989
  };
3343
- const createSelectChain = (columns, options) => {
4990
+ const createSelectChain = (columns, options, initialCallsite) => {
3344
4991
  const chain = {};
4992
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
3345
4993
  const filterMethods2 = createFilterMethods(state, addCondition, chain);
3346
4994
  Object.assign(chain, filterMethods2, {
3347
4995
  async single(cols, opts) {
3348
- const r = await runSelect(cols ?? columns, opts ?? options);
4996
+ const r = await runSelect(
4997
+ cols ?? columns,
4998
+ opts ?? options,
4999
+ snapshotState(),
5000
+ callsiteStore.resolve(captureTraceCallsite(tracer))
5001
+ );
3349
5002
  return toSingleResult(r);
3350
5003
  },
3351
5004
  maybeSingle(cols, opts) {
3352
5005
  return chain.single(cols, opts);
3353
5006
  },
3354
5007
  then(onfulfilled, onrejected) {
3355
- return runSelect(columns, options).then(onfulfilled, onrejected);
5008
+ return runSelect(
5009
+ columns,
5010
+ options,
5011
+ snapshotState(),
5012
+ callsiteStore.resolve()
5013
+ ).then(onfulfilled, onrejected);
3356
5014
  },
3357
5015
  catch(onrejected) {
3358
- return runSelect(columns, options).catch(onrejected);
5016
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).catch(
5017
+ onrejected
5018
+ );
3359
5019
  },
3360
5020
  finally(onfinally) {
3361
- return runSelect(columns, options).finally(onfinally);
5021
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).finally(
5022
+ onfinally
5023
+ );
3362
5024
  }
3363
5025
  });
3364
5026
  return chain;
@@ -3375,11 +5037,75 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3375
5037
  return builder;
3376
5038
  },
3377
5039
  select(columns = DEFAULT_COLUMNS, options) {
3378
- return createSelectChain(columns, options);
5040
+ return createSelectChain(columns, options, captureTraceCallsite(tracer));
5041
+ },
5042
+ async findMany(options) {
5043
+ const columns = compileSelectShape(options.select);
5044
+ const baseState = snapshotState();
5045
+ const executionState = snapshotState();
5046
+ const callsite = captureTraceCallsite(tracer);
5047
+ const compiledWhere = compileWhere(options.where);
5048
+ if (compiledWhere?.length) {
5049
+ executionState.conditions.push(...compiledWhere);
5050
+ }
5051
+ if (options.orderBy !== void 0) {
5052
+ executionState.order = compileOrderBy(options.orderBy);
5053
+ }
5054
+ if (options.limit !== void 0) {
5055
+ executionState.limit = options.limit;
5056
+ }
5057
+ if (experimental?.findManyAst && canUseFindManyAstTransport(baseState) && !selectShapeUsesRelationSchema(options.select)) {
5058
+ const resolvedTableName = resolveTableNameForCall(tableName, void 0);
5059
+ const payload = {
5060
+ table_name: resolvedTableName,
5061
+ select: options.select
5062
+ };
5063
+ if (options.where !== void 0) {
5064
+ payload.where = options.where;
5065
+ }
5066
+ const astOrder = toFindManyAstOrder(executionState.order);
5067
+ if (astOrder !== void 0) {
5068
+ payload.orderBy = astOrder;
5069
+ }
5070
+ if (executionState.limit !== void 0) {
5071
+ payload.limit = executionState.limit;
5072
+ }
5073
+ const sql = buildDebugSelectQuery({
5074
+ tableName: resolvedTableName,
5075
+ columns,
5076
+ conditions: executionState.conditions,
5077
+ limit: executionState.limit,
5078
+ order: executionState.order
5079
+ });
5080
+ return executeWithQueryTrace(
5081
+ tracer,
5082
+ {
5083
+ operation: "select",
5084
+ endpoint: "/gateway/fetch",
5085
+ table: resolvedTableName,
5086
+ sql,
5087
+ payload
5088
+ },
5089
+ async () => {
5090
+ const response = await client.fetchGateway(
5091
+ payload
5092
+ );
5093
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
5094
+ },
5095
+ callsite
5096
+ );
5097
+ }
5098
+ return runSelect(
5099
+ columns,
5100
+ void 0,
5101
+ executionState,
5102
+ callsite
5103
+ );
3379
5104
  },
3380
5105
  insert(values, options) {
5106
+ const mutationCallsite = captureTraceCallsite(tracer);
3381
5107
  if (Array.isArray(values)) {
3382
- const executeInsertMany = async (columns, selectOptions) => {
5108
+ const executeInsertMany = async (columns, selectOptions, callsite) => {
3383
5109
  const mergedOptions = mergeOptions(options, selectOptions);
3384
5110
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3385
5111
  const payload = {
@@ -3392,12 +5118,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3392
5118
  if (mergedOptions?.defaultToNull !== void 0) {
3393
5119
  payload.default_to_null = mergedOptions.defaultToNull;
3394
5120
  }
3395
- const response = await client.insertGateway(payload, mergedOptions);
3396
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
5121
+ const sql = buildInsertDebugSql(payload);
5122
+ return executeWithQueryTrace(
5123
+ tracer,
5124
+ {
5125
+ operation: "insert",
5126
+ endpoint: "/gateway/insert",
5127
+ table: resolvedTableName,
5128
+ sql,
5129
+ payload,
5130
+ options: mergedOptions
5131
+ },
5132
+ async () => {
5133
+ const response = await client.insertGateway(payload, mergedOptions);
5134
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
5135
+ },
5136
+ callsite
5137
+ );
3397
5138
  };
3398
- return createMutationQuery(executeInsertMany);
5139
+ return createMutationQuery(executeInsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
3399
5140
  }
3400
- const executeInsertOne = async (columns, selectOptions) => {
5141
+ const executeInsertOne = async (columns, selectOptions, callsite) => {
3401
5142
  const mergedOptions = mergeOptions(options, selectOptions);
3402
5143
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3403
5144
  const payload = {
@@ -3410,14 +5151,30 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3410
5151
  if (mergedOptions?.defaultToNull !== void 0) {
3411
5152
  payload.default_to_null = mergedOptions.defaultToNull;
3412
5153
  }
3413
- const response = await client.insertGateway(payload, mergedOptions);
3414
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
5154
+ const sql = buildInsertDebugSql(payload);
5155
+ return executeWithQueryTrace(
5156
+ tracer,
5157
+ {
5158
+ operation: "insert",
5159
+ endpoint: "/gateway/insert",
5160
+ table: resolvedTableName,
5161
+ sql,
5162
+ payload,
5163
+ options: mergedOptions
5164
+ },
5165
+ async () => {
5166
+ const response = await client.insertGateway(payload, mergedOptions);
5167
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
5168
+ },
5169
+ callsite
5170
+ );
3415
5171
  };
3416
- return createMutationQuery(executeInsertOne);
5172
+ return createMutationQuery(executeInsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
3417
5173
  },
3418
5174
  upsert(values, options) {
5175
+ const mutationCallsite = captureTraceCallsite(tracer);
3419
5176
  if (Array.isArray(values)) {
3420
- const executeUpsertMany = async (columns, selectOptions) => {
5177
+ const executeUpsertMany = async (columns, selectOptions, callsite) => {
3421
5178
  const mergedOptions = mergeOptions(options, selectOptions);
3422
5179
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3423
5180
  const payload = {
@@ -3432,12 +5189,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3432
5189
  if (mergedOptions?.defaultToNull !== void 0) {
3433
5190
  payload.default_to_null = mergedOptions.defaultToNull;
3434
5191
  }
3435
- const response = await client.insertGateway(payload, mergedOptions);
3436
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
5192
+ const sql = buildInsertDebugSql(payload);
5193
+ return executeWithQueryTrace(
5194
+ tracer,
5195
+ {
5196
+ operation: "upsert",
5197
+ endpoint: "/gateway/insert",
5198
+ table: resolvedTableName,
5199
+ sql,
5200
+ payload,
5201
+ options: mergedOptions
5202
+ },
5203
+ async () => {
5204
+ const response = await client.insertGateway(payload, mergedOptions);
5205
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
5206
+ },
5207
+ callsite
5208
+ );
3437
5209
  };
3438
- return createMutationQuery(executeUpsertMany);
5210
+ return createMutationQuery(executeUpsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
3439
5211
  }
3440
- const executeUpsertOne = async (columns, selectOptions) => {
5212
+ const executeUpsertOne = async (columns, selectOptions, callsite) => {
3441
5213
  const mergedOptions = mergeOptions(options, selectOptions);
3442
5214
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3443
5215
  const payload = {
@@ -3452,13 +5224,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3452
5224
  if (mergedOptions?.defaultToNull !== void 0) {
3453
5225
  payload.default_to_null = mergedOptions.defaultToNull;
3454
5226
  }
3455
- const response = await client.insertGateway(payload, mergedOptions);
3456
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
5227
+ const sql = buildInsertDebugSql(payload);
5228
+ return executeWithQueryTrace(
5229
+ tracer,
5230
+ {
5231
+ operation: "upsert",
5232
+ endpoint: "/gateway/insert",
5233
+ table: resolvedTableName,
5234
+ sql,
5235
+ payload,
5236
+ options: mergedOptions
5237
+ },
5238
+ async () => {
5239
+ const response = await client.insertGateway(payload, mergedOptions);
5240
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
5241
+ },
5242
+ callsite
5243
+ );
3457
5244
  };
3458
- return createMutationQuery(executeUpsertOne);
5245
+ return createMutationQuery(executeUpsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
3459
5246
  },
3460
5247
  update(values, options) {
3461
- const executeUpdate = async (columns, selectOptions) => {
5248
+ const mutationCallsite = captureTraceCallsite(tracer);
5249
+ const executeUpdate = async (columns, selectOptions, callsite) => {
3462
5250
  const filters = state.conditions.length ? [...state.conditions] : void 0;
3463
5251
  const mergedOptions = mergeOptions(options, selectOptions);
3464
5252
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
@@ -3473,10 +5261,25 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3473
5261
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
3474
5262
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
3475
5263
  if (columns) payload.columns = columns;
3476
- const response = await client.updateGateway(payload, mergedOptions);
3477
- return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
5264
+ const sql = buildUpdateDebugSql(payload);
5265
+ return executeWithQueryTrace(
5266
+ tracer,
5267
+ {
5268
+ operation: "update",
5269
+ endpoint: "/gateway/update",
5270
+ table: resolvedTableName,
5271
+ sql,
5272
+ payload,
5273
+ options: mergedOptions
5274
+ },
5275
+ async () => {
5276
+ const response = await client.updateGateway(payload, mergedOptions);
5277
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
5278
+ },
5279
+ callsite
5280
+ );
3478
5281
  };
3479
- const mutation = createMutationQuery(executeUpdate, null);
5282
+ const mutation = createMutationQuery(executeUpdate, null, tracer, mutationCallsite);
3480
5283
  const updateChain = {};
3481
5284
  const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
3482
5285
  Object.assign(updateChain, filterMethods2, mutation);
@@ -3488,7 +5291,8 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3488
5291
  if (!resourceId && !filters?.length) {
3489
5292
  throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
3490
5293
  }
3491
- const executeDelete = async (columns, selectOptions) => {
5294
+ const mutationCallsite = captureTraceCallsite(tracer);
5295
+ const executeDelete = async (columns, selectOptions, callsite) => {
3492
5296
  const mergedOptions = mergeOptions(options, selectOptions);
3493
5297
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3494
5298
  const payload = {
@@ -3501,13 +5305,33 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3501
5305
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
3502
5306
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
3503
5307
  if (columns) payload.columns = columns;
3504
- const response = await client.deleteGateway(payload, mergedOptions);
3505
- return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
5308
+ const sql = buildDeleteDebugSql(payload);
5309
+ return executeWithQueryTrace(
5310
+ tracer,
5311
+ {
5312
+ operation: "delete",
5313
+ endpoint: "/gateway/delete",
5314
+ table: resolvedTableName,
5315
+ sql,
5316
+ payload,
5317
+ options: mergedOptions
5318
+ },
5319
+ async () => {
5320
+ const response = await client.deleteGateway(payload, mergedOptions);
5321
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
5322
+ },
5323
+ callsite
5324
+ );
3506
5325
  };
3507
- return createMutationQuery(executeDelete, null);
5326
+ return createMutationQuery(executeDelete, null, tracer, mutationCallsite);
3508
5327
  },
3509
5328
  async single(columns, options) {
3510
- const response = await builder.select(columns, options);
5329
+ const response = await runSelect(
5330
+ columns ?? DEFAULT_COLUMNS,
5331
+ options,
5332
+ snapshotState(),
5333
+ captureTraceCallsite(tracer)
5334
+ );
3511
5335
  return toSingleResult(response);
3512
5336
  },
3513
5337
  async maybeSingle(columns, options) {
@@ -3516,14 +5340,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3516
5340
  });
3517
5341
  return builder;
3518
5342
  }
3519
- function createQueryBuilder(client, formatGatewayResult) {
5343
+ function createQueryBuilder(client, formatGatewayResult, tracer) {
3520
5344
  return async function query(query, options) {
3521
5345
  const normalizedQuery = query.trim();
3522
5346
  if (!normalizedQuery) {
3523
5347
  throw new Error("query requires a non-empty string");
3524
5348
  }
3525
- const response = await client.queryGateway({ query: normalizedQuery }, options);
3526
- return formatGatewayResult(response, { operation: "query" });
5349
+ const payload = { query: normalizedQuery };
5350
+ const callsite = captureTraceCallsite(tracer);
5351
+ return executeWithQueryTrace(
5352
+ tracer,
5353
+ {
5354
+ operation: "query",
5355
+ endpoint: "/gateway/query",
5356
+ sql: normalizedQuery,
5357
+ payload,
5358
+ options
5359
+ },
5360
+ async () => {
5361
+ const response = await client.queryGateway(payload, options);
5362
+ return formatGatewayResult(response, { operation: "query" });
5363
+ },
5364
+ callsite
5365
+ );
3527
5366
  };
3528
5367
  }
3529
5368
  function createClientFromConfig(config) {
@@ -3534,9 +5373,16 @@ function createClientFromConfig(config) {
3534
5373
  backend: config.backend,
3535
5374
  headers: config.headers
3536
5375
  });
3537
- const formatGatewayResult = createResultFormatter(config.experimental);
5376
+ const formatGatewayResult = createResultFormatter();
5377
+ const queryTracer = createQueryTracer(config.experimental);
3538
5378
  const auth = createAuthClient(config.auth);
3539
- const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
5379
+ const from = (table, options) => createTableBuilder(
5380
+ resolveTableNameForCall(table, options?.schema),
5381
+ gateway,
5382
+ formatGatewayResult,
5383
+ queryTracer,
5384
+ config.experimental
5385
+ );
3540
5386
  const rpc = (fn, args, options) => {
3541
5387
  const normalizedFn = fn.trim();
3542
5388
  if (!normalizedFn) {
@@ -3547,16 +5393,19 @@ function createClientFromConfig(config) {
3547
5393
  args,
3548
5394
  options,
3549
5395
  gateway,
3550
- formatGatewayResult
5396
+ formatGatewayResult,
5397
+ queryTracer,
5398
+ captureTraceCallsite(queryTracer)
3551
5399
  );
3552
5400
  };
3553
- const query = createQueryBuilder(gateway, formatGatewayResult);
5401
+ const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
3554
5402
  const db = createDbModule({ from, rpc, query });
3555
5403
  return {
3556
5404
  from,
3557
5405
  db,
3558
5406
  rpc,
3559
5407
  query,
5408
+ verifyConnection: gateway.verifyConnection,
3560
5409
  auth: auth.auth
3561
5410
  };
3562
5411
  }
@@ -4020,7 +5869,7 @@ var AthenaGatewayCatalogClient = class {
4020
5869
  async queryRows(query) {
4021
5870
  const result = await this.client.query(query);
4022
5871
  if (result.error || result.status < 200 || result.status >= 300) {
4023
- throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
5872
+ throw new Error(result.error?.message ?? `Gateway query failed with status ${result.status}`);
4024
5873
  }
4025
5874
  return result.data ?? [];
4026
5875
  }
@@ -4117,10 +5966,24 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
4117
5966
  }
4118
5967
 
4119
5968
  // src/generator/pipeline.ts
5969
+ function canOverwriteArtifact(file) {
5970
+ return file.kind === "model" || file.kind === "schema";
5971
+ }
5972
+ async function fileExists(path) {
5973
+ try {
5974
+ await promises.stat(path);
5975
+ return true;
5976
+ } catch {
5977
+ return false;
5978
+ }
5979
+ }
4120
5980
  async function writeArtifacts(files, cwd) {
4121
5981
  const writtenFiles = [];
4122
5982
  for (const file of files) {
4123
5983
  const absolutePath = path.resolve(cwd, file.path);
5984
+ if (!canOverwriteArtifact(file) && await fileExists(absolutePath)) {
5985
+ continue;
5986
+ }
4124
5987
  await promises.mkdir(path.dirname(absolutePath), { recursive: true });
4125
5988
  await promises.writeFile(absolutePath, file.content, "utf8");
4126
5989
  writtenFiles.push(file.path);