@xylex-group/athena 2.1.2 → 2.3.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 +287 -116
  2. package/dist/browser.cjs +1628 -156
  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 +1625 -156
  7. package/dist/browser.js.map +1 -1
  8. package/dist/cli/index.cjs +1532 -145
  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 +1533 -146
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.cjs +1658 -167
  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 +1656 -168
  19. package/dist/index.js.map +1 -1
  20. package/dist/{model-form-2hqmoOUX.d.ts → model-form-BpDXlbxb.d.ts} +97 -2
  21. package/dist/{model-form-Cy-zaO0u.d.cts → model-form-hoE2jHIi.d.cts} +97 -2
  22. package/dist/{pipeline-BOPszLsL.d.ts → pipeline-BNIw8pDQ.d.ts} +1 -1
  23. package/dist/{pipeline-E3FDbs4W.d.cts → pipeline-DNIpEsN8.d.cts} +1 -1
  24. package/dist/{client-dpAp-NZK.d.cts → react-email-BvyCZnfW.d.cts} +349 -174
  25. package/dist/{client-BX0NQqOn.d.ts → react-email-qPA1wjFV.d.ts} +349 -174
  26. package/dist/react.cjs +30 -9
  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 +30 -9
  31. package/dist/react.js.map +1 -1
  32. package/dist/{types-BaBzjwXr.d.cts → types-A5e97acl.d.cts} +2 -1
  33. package/dist/{types-BaBzjwXr.d.ts → types-A5e97acl.d.ts} +2 -1
  34. package/dist/{types-CeBPrnGj.d.ts → types-BnD22-vb.d.ts} +1 -1
  35. package/dist/{types-CpqL-pZx.d.cts → types-bDlr4u7p.d.cts} +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 +75 -17
@@ -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
  }
@@ -510,13 +549,50 @@ function normalizeAthenaError(resultOrError, context) {
510
549
  return withContextOverrides(attached, context);
511
550
  }
512
551
  if (isAthenaResultLike(resultOrError)) {
552
+ if (isAthenaResultErrorLike(resultOrError.error)) {
553
+ return {
554
+ kind: resultOrError.error.kind ?? classifyKind(resultOrError.status, gatewayCodeFromUnknownError(resultOrError.error), resultOrError.error.message),
555
+ code: resultOrError.error.athenaCode ?? toAthenaErrorCode(
556
+ resultOrError.error.kind ?? classifyKind(
557
+ resultOrError.status,
558
+ gatewayCodeFromUnknownError(resultOrError.error),
559
+ resultOrError.error.message
560
+ ),
561
+ resultOrError.error.status ?? resultOrError.status,
562
+ gatewayCodeFromUnknownError(resultOrError.error)
563
+ ),
564
+ category: resultOrError.error.category ?? toAthenaErrorCategory(
565
+ resultOrError.error.kind ?? classifyKind(
566
+ resultOrError.status,
567
+ gatewayCodeFromUnknownError(resultOrError.error),
568
+ resultOrError.error.message
569
+ ),
570
+ resultOrError.error.status ?? resultOrError.status
571
+ ),
572
+ retryable: resultOrError.error.retryable ?? isRetryable(
573
+ resultOrError.error.kind ?? classifyKind(
574
+ resultOrError.status,
575
+ gatewayCodeFromUnknownError(resultOrError.error),
576
+ resultOrError.error.message
577
+ ),
578
+ resultOrError.error.status ?? resultOrError.status
579
+ ),
580
+ status: resultOrError.error.status ?? resultOrError.status,
581
+ constraint: resultOrError.error.constraint,
582
+ table: context?.table ?? resultOrError.error.table,
583
+ operation: context?.operation ?? resultOrError.error.operation,
584
+ message: resultOrError.error.message,
585
+ raw: resultOrError.error.raw ?? resultOrError.raw
586
+ };
587
+ }
513
588
  const details = resultOrError.errorDetails;
514
- const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
589
+ const message2 = messageFromUnknownError(resultOrError.error) ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
515
590
  const operation = context?.operation ?? operationFromDetails(details);
516
591
  const table = context?.table ?? extractTable(message2);
517
592
  const constraint = extractConstraint(message2);
518
- const kind2 = classifyKind(resultOrError.status, details?.code, message2);
519
- const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
593
+ const gatewayCode = details?.code ?? gatewayCodeFromUnknownError(resultOrError.error);
594
+ const kind2 = classifyKind(resultOrError.status, gatewayCode, message2);
595
+ const code = toAthenaErrorCode(kind2, resultOrError.status, gatewayCode);
520
596
  const category = toAthenaErrorCategory(kind2, resultOrError.status);
521
597
  return {
522
598
  kind: kind2,
@@ -794,7 +870,7 @@ function normalizeBooleanFlag(rawValue, fallback) {
794
870
  return rawValue;
795
871
  }
796
872
  if (typeof rawValue === "string") {
797
- return parseBooleanFlag(rawValue, fallback);
873
+ return parseBooleanFlag2(rawValue, fallback);
798
874
  }
799
875
  return fallback;
800
876
  }
@@ -1311,23 +1387,39 @@ function normalizeHeaderValue(value) {
1311
1387
  function isRecord2(value) {
1312
1388
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1313
1389
  }
1390
+ function nonEmptyString(value) {
1391
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
1392
+ }
1393
+ function resolveStructuredErrorPayload(payload) {
1394
+ if (!isRecord2(payload)) return null;
1395
+ return isRecord2(payload.error) ? payload.error : payload;
1396
+ }
1314
1397
  function resolveRequestId(headers) {
1315
1398
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
1316
1399
  }
1317
1400
  function resolveErrorMessage(payload, fallback) {
1318
- if (isRecord2(payload)) {
1319
- const messageCandidates = [payload.error, payload.message, payload.details];
1401
+ const structuredPayload = resolveStructuredErrorPayload(payload);
1402
+ if (structuredPayload) {
1403
+ const messageCandidates = [structuredPayload.message, structuredPayload.error, structuredPayload.details];
1320
1404
  for (const candidate of messageCandidates) {
1321
- if (typeof candidate === "string" && candidate.trim().length > 0) {
1322
- return candidate.trim();
1323
- }
1405
+ const resolved = nonEmptyString(candidate);
1406
+ if (resolved) return resolved;
1324
1407
  }
1325
1408
  }
1326
- if (typeof payload === "string" && payload.trim().length > 0) {
1327
- return payload.trim();
1328
- }
1409
+ const rawMessage = nonEmptyString(payload);
1410
+ if (rawMessage) return rawMessage;
1329
1411
  return fallback;
1330
1412
  }
1413
+ function resolveErrorHint(payload) {
1414
+ const structuredPayload = resolveStructuredErrorPayload(payload);
1415
+ return structuredPayload ? nonEmptyString(structuredPayload.hint) : void 0;
1416
+ }
1417
+ function resolveStatusText(response, payload) {
1418
+ const rawStatusText = nonEmptyString(response.statusText);
1419
+ if (rawStatusText) return rawStatusText;
1420
+ const payloadRecord = isRecord2(payload) ? payload : null;
1421
+ return payloadRecord ? nonEmptyString(payloadRecord.statusText) ?? null : null;
1422
+ }
1331
1423
  function detailsFromError(error) {
1332
1424
  return error.toDetails();
1333
1425
  }
@@ -1498,6 +1590,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1498
1590
  return {
1499
1591
  ok: false,
1500
1592
  status: response.status,
1593
+ statusText: resolveStatusText(response, parsedBody.parsed),
1501
1594
  data: null,
1502
1595
  error: invalidJsonError.message,
1503
1596
  errorDetails: detailsFromError(invalidJsonError),
@@ -1516,11 +1609,13 @@ async function callAthena(config, endpoint, method, payload, options) {
1516
1609
  status: response.status,
1517
1610
  endpoint,
1518
1611
  method,
1519
- requestId
1612
+ requestId,
1613
+ hint: resolveErrorHint(parsed)
1520
1614
  });
1521
1615
  return {
1522
1616
  ok: false,
1523
1617
  status: response.status,
1618
+ statusText: resolveStatusText(response, parsed),
1524
1619
  data: null,
1525
1620
  error: httpError.message,
1526
1621
  errorDetails: detailsFromError(httpError),
@@ -1532,6 +1627,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1532
1627
  return {
1533
1628
  ok: true,
1534
1629
  status: response.status,
1630
+ statusText: resolveStatusText(response, parsed),
1535
1631
  data: payloadData ?? null,
1536
1632
  count: payloadCount,
1537
1633
  error: void 0,
@@ -1551,6 +1647,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1551
1647
  return {
1552
1648
  ok: false,
1553
1649
  status: 0,
1650
+ statusText: null,
1554
1651
  data: null,
1555
1652
  error: networkError.message,
1556
1653
  errorDetails: detailsFromError(networkError),
@@ -1592,10 +1689,29 @@ function createAthenaGatewayClient(config = {}) {
1592
1689
  // src/sql-identifiers.ts
1593
1690
  var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
1594
1691
  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;
1692
+ var SQL_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
1693
+ var RESPONSE_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_.]*)$/i;
1596
1694
  function quoteIdentifierSegment(identifier) {
1597
1695
  return `"${identifier.replace(/"/g, '""')}"`;
1598
1696
  }
1697
+ function parseAliasedIdentifierToken(token) {
1698
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(token);
1699
+ if (responseAliasMatch) {
1700
+ const [, aliasIdentifier2, baseIdentifier2] = responseAliasMatch;
1701
+ if (COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier2) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier2)) {
1702
+ return { baseIdentifier: baseIdentifier2, aliasIdentifier: aliasIdentifier2 };
1703
+ }
1704
+ }
1705
+ const sqlAliasMatch = SQL_ALIAS_PATTERN.exec(token);
1706
+ if (!sqlAliasMatch) {
1707
+ return null;
1708
+ }
1709
+ const [, baseIdentifier, aliasIdentifier] = sqlAliasMatch;
1710
+ if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
1711
+ return null;
1712
+ }
1713
+ return { baseIdentifier, aliasIdentifier };
1714
+ }
1599
1715
  function quoteQualifiedIdentifier(identifier) {
1600
1716
  return identifier.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
1601
1717
  }
@@ -1604,23 +1720,27 @@ function quoteSelectToken(token) {
1604
1720
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
1605
1721
  return quoteQualifiedIdentifier(token);
1606
1722
  }
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)) {
1723
+ const aliasedIdentifier = parseAliasedIdentifierToken(token);
1724
+ if (!aliasedIdentifier) {
1613
1725
  return token;
1614
1726
  }
1727
+ const { baseIdentifier, aliasIdentifier } = aliasedIdentifier;
1615
1728
  return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
1616
1729
  }
1730
+ function quoteSelectColumnToken(token) {
1731
+ const trimmed = token.trim();
1732
+ if (!trimmed || trimmed === "*") return trimmed || "*";
1733
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(trimmed);
1734
+ if (responseAliasMatch) {
1735
+ const [, aliasIdentifier, baseIdentifier] = responseAliasMatch;
1736
+ return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
1737
+ }
1738
+ return quoteQualifiedIdentifier(trimmed);
1739
+ }
1617
1740
  function canAutoQuoteToken(token) {
1618
1741
  if (token === "*") return true;
1619
1742
  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);
1743
+ return parseAliasedIdentifierToken(token) != null;
1624
1744
  }
1625
1745
  function splitTopLevelCommaSeparated(input) {
1626
1746
  const parts = [];
@@ -1704,6 +1824,190 @@ function quoteSelectColumnsExpression(columns) {
1704
1824
  return tokens.map(quoteSelectToken).join(", ");
1705
1825
  }
1706
1826
 
1827
+ // src/auth/react-email.ts
1828
+ var reactEmailRenderModulePromise;
1829
+ function isRecord3(value) {
1830
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1831
+ }
1832
+ function isFunction(value) {
1833
+ return typeof value === "function";
1834
+ }
1835
+ function toStringOrUndefined(value) {
1836
+ if (typeof value !== "string") return void 0;
1837
+ return value;
1838
+ }
1839
+ function nowIsoString() {
1840
+ return (/* @__PURE__ */ new Date()).toISOString();
1841
+ }
1842
+ function emitReactEmailEvent(observe, phase, input = {}) {
1843
+ if (!observe) return;
1844
+ try {
1845
+ observe({
1846
+ phase,
1847
+ timestamp: nowIsoString(),
1848
+ ...input
1849
+ });
1850
+ } catch {
1851
+ }
1852
+ }
1853
+ function mergeRenderDefaults(input, defaults) {
1854
+ return {
1855
+ ...input,
1856
+ pretty: input.pretty ?? defaults?.pretty,
1857
+ includePlainText: input.includePlainText ?? defaults?.includePlainText
1858
+ };
1859
+ }
1860
+ function mergeRuntimeOptions(options) {
1861
+ if (!options) return void 0;
1862
+ return {
1863
+ defaults: options.defaults,
1864
+ observe: options.observe,
1865
+ route: "route" in options ? options.route : void 0
1866
+ };
1867
+ }
1868
+ async function resolveReactEmailRenderModule() {
1869
+ if (!reactEmailRenderModulePromise) {
1870
+ reactEmailRenderModulePromise = (async () => {
1871
+ try {
1872
+ const loaded = await import('@react-email/render');
1873
+ if (!isFunction(loaded.render)) {
1874
+ throw new Error("missing render(...) export");
1875
+ }
1876
+ return {
1877
+ render: loaded.render,
1878
+ toPlainText: isFunction(loaded.toPlainText) ? loaded.toPlainText : void 0,
1879
+ pretty: isFunction(loaded.pretty) ? loaded.pretty : void 0
1880
+ };
1881
+ } catch (error) {
1882
+ const message = error instanceof Error ? error.message : String(error);
1883
+ throw new Error(
1884
+ `React Email rendering requires @react-email/render. Install it in your project (for example: pnpm add @react-email/render). Loader error: ${message}`
1885
+ );
1886
+ }
1887
+ })();
1888
+ }
1889
+ if (!reactEmailRenderModulePromise) {
1890
+ throw new Error("React Email renderer module failed to initialize");
1891
+ }
1892
+ return reactEmailRenderModulePromise;
1893
+ }
1894
+ async function resolveReactEmailElement(input) {
1895
+ if (input.element != null) {
1896
+ return input.element;
1897
+ }
1898
+ if (!input.component) {
1899
+ throw new Error("react email payload requires either `element` or `component`");
1900
+ }
1901
+ try {
1902
+ const reactModule = await import('react');
1903
+ if (typeof reactModule.createElement !== "function") {
1904
+ throw new Error("react createElement(...) export is unavailable");
1905
+ }
1906
+ return reactModule.createElement(
1907
+ input.component,
1908
+ input.props ?? {}
1909
+ );
1910
+ } catch (error) {
1911
+ const message = error instanceof Error ? error.message : String(error);
1912
+ throw new Error(
1913
+ `React Email component rendering requires react runtime support. Install react in your project. Loader error: ${message}`
1914
+ );
1915
+ }
1916
+ }
1917
+ async function renderAthenaReactEmail(input, options) {
1918
+ if (!isRecord3(input)) {
1919
+ throw new Error("react email payload must be an object");
1920
+ }
1921
+ const runtimeOptions = mergeRuntimeOptions(options);
1922
+ const start = Date.now();
1923
+ emitReactEmailEvent(runtimeOptions?.observe, "render:start", {
1924
+ route: runtimeOptions?.route,
1925
+ message: "Rendering react email payload"
1926
+ });
1927
+ try {
1928
+ const normalizedInput = mergeRenderDefaults(input, runtimeOptions?.defaults);
1929
+ const element = await resolveReactEmailElement(normalizedInput);
1930
+ const renderModule = await resolveReactEmailRenderModule();
1931
+ const htmlValue = await renderModule.render(element);
1932
+ const renderedHtml = typeof htmlValue === "string" ? htmlValue : String(htmlValue ?? "");
1933
+ if (!renderedHtml.trim()) {
1934
+ throw new Error("react email renderer returned an empty HTML string");
1935
+ }
1936
+ let html = renderedHtml;
1937
+ if (normalizedInput.pretty && renderModule.pretty) {
1938
+ const prettyValue = await renderModule.pretty(renderedHtml);
1939
+ if (typeof prettyValue === "string" && prettyValue.trim().length > 0) {
1940
+ html = prettyValue;
1941
+ }
1942
+ }
1943
+ const explicitText = toStringOrUndefined(normalizedInput.text);
1944
+ if (explicitText !== void 0) {
1945
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
1946
+ route: runtimeOptions?.route,
1947
+ durationMs: Date.now() - start,
1948
+ message: "Rendered react email with explicit text"
1949
+ });
1950
+ return {
1951
+ html,
1952
+ text: explicitText
1953
+ };
1954
+ }
1955
+ if (normalizedInput.includePlainText === false || !renderModule.toPlainText) {
1956
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
1957
+ route: runtimeOptions?.route,
1958
+ durationMs: Date.now() - start,
1959
+ message: "Rendered react email without plain-text derivation"
1960
+ });
1961
+ return { html };
1962
+ }
1963
+ const plainTextValue = await renderModule.toPlainText(html);
1964
+ const plainText = toStringOrUndefined(plainTextValue);
1965
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
1966
+ route: runtimeOptions?.route,
1967
+ durationMs: Date.now() - start,
1968
+ message: plainText ? "Rendered react email with derived plain text" : "Rendered react email HTML only"
1969
+ });
1970
+ if (plainText === void 0) {
1971
+ return { html };
1972
+ }
1973
+ return {
1974
+ html,
1975
+ text: plainText
1976
+ };
1977
+ } catch (error) {
1978
+ const message = error instanceof Error ? error.message : String(error);
1979
+ emitReactEmailEvent(runtimeOptions?.observe, "render:error", {
1980
+ route: runtimeOptions?.route,
1981
+ durationMs: Date.now() - start,
1982
+ error: message,
1983
+ message: "Failed to render react email payload"
1984
+ });
1985
+ throw error;
1986
+ }
1987
+ }
1988
+ async function resolveReactEmailPayloadFields(input, fields, options) {
1989
+ const { react, ...payloadWithoutReact } = input;
1990
+ if (!react) {
1991
+ return payloadWithoutReact;
1992
+ }
1993
+ const rendered = await renderAthenaReactEmail(react, options);
1994
+ const payload = {
1995
+ ...payloadWithoutReact
1996
+ };
1997
+ payload[fields.htmlField] = rendered.html;
1998
+ const currentTextValue = payload[fields.textField];
1999
+ if (rendered.text !== void 0 && (currentTextValue === void 0 || currentTextValue === null || currentTextValue === "")) {
2000
+ payload[fields.textField] = rendered.text;
2001
+ }
2002
+ if (fields.variablesField && (payload[fields.variablesField] === void 0 || payload[fields.variablesField] === null) && isRecord3(react.props)) {
2003
+ const derivedVariables = Object.keys(react.props);
2004
+ if (derivedVariables.length > 0) {
2005
+ payload[fields.variablesField] = derivedVariables;
2006
+ }
2007
+ }
2008
+ return payload;
2009
+ }
2010
+
1707
2011
  // src/auth/client.ts
1708
2012
  var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
1709
2013
  var FALLBACK_SDK_VERSION2 = "1.0.0";
@@ -1713,7 +2017,7 @@ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
1713
2017
  function normalizeBaseUrl(baseUrl) {
1714
2018
  return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
1715
2019
  }
1716
- function isRecord3(value) {
2020
+ function isRecord4(value) {
1717
2021
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1718
2022
  }
1719
2023
  function normalizeHeaderValue2(value) {
@@ -1738,7 +2042,7 @@ function resolveRequestId2(headers) {
1738
2042
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
1739
2043
  }
1740
2044
  function resolveErrorMessage2(payload, fallback) {
1741
- if (isRecord3(payload)) {
2045
+ if (isRecord4(payload)) {
1742
2046
  const messageCandidates = [payload.error, payload.message, payload.details];
1743
2047
  for (const candidate of messageCandidates) {
1744
2048
  if (typeof candidate === "string" && candidate.trim().length > 0) {
@@ -2064,6 +2368,19 @@ function createAuthClient(config = {}) {
2064
2368
  options
2065
2369
  );
2066
2370
  };
2371
+ const withReactEmailRoute = (route) => ({
2372
+ ...resolvedConfig.reactEmail,
2373
+ route
2374
+ });
2375
+ const resolveAdminEmailPayload = (route, input) => resolveReactEmailPayloadFields(input, {
2376
+ htmlField: "htmlBody",
2377
+ textField: "textBody"
2378
+ }, withReactEmailRoute(route));
2379
+ const resolveAdminEmailTemplatePayload = (route, input) => resolveReactEmailPayloadFields(input, {
2380
+ htmlField: "htmlTemplate",
2381
+ textField: "textTemplate",
2382
+ variablesField: "variables"
2383
+ }, withReactEmailRoute(route));
2067
2384
  const listUserEmailsWithFallback = async (input, options) => {
2068
2385
  const primary = await getWithQuery(
2069
2386
  "/email/list",
@@ -2091,7 +2408,7 @@ function createAuthClient(config = {}) {
2091
2408
  data: null
2092
2409
  };
2093
2410
  }
2094
- const fallbackStatus = isRecord3(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
2411
+ const fallbackStatus = isRecord4(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
2095
2412
  return {
2096
2413
  ...fallback,
2097
2414
  data: {
@@ -2527,8 +2844,16 @@ function createAuthClient(config = {}) {
2527
2844
  email: {
2528
2845
  list: (input, options) => getWithQuery("/admin/email/list", input, options),
2529
2846
  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),
2847
+ create: async (input, options) => postGeneric(
2848
+ "/admin/email/create",
2849
+ await resolveAdminEmailPayload("/admin/email/create", input),
2850
+ options
2851
+ ),
2852
+ update: async (input, options) => postGeneric(
2853
+ "/admin/email/update",
2854
+ await resolveAdminEmailPayload("/admin/email/update", input),
2855
+ options
2856
+ ),
2532
2857
  delete: (input, options) => postGeneric("/admin/email/delete", input, options),
2533
2858
  failure: {
2534
2859
  list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
@@ -2540,17 +2865,33 @@ function createAuthClient(config = {}) {
2540
2865
  template: {
2541
2866
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
2542
2867
  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),
2868
+ create: async (input, options) => postGeneric(
2869
+ "/admin/email-template/create",
2870
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
2871
+ options
2872
+ ),
2873
+ update: async (input, options) => postGeneric(
2874
+ "/admin/email-template/update",
2875
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
2876
+ options
2877
+ ),
2545
2878
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
2546
2879
  }
2547
2880
  },
2548
2881
  emailTemplate: {
2549
2882
  get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
2550
- create: (input, options) => postGeneric("/admin/email-template/create", input, options),
2883
+ create: async (input, options) => postGeneric(
2884
+ "/admin/email-template/create",
2885
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
2886
+ options
2887
+ ),
2551
2888
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
2552
2889
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
2553
- update: (input, options) => postGeneric("/admin/email-template/update", input, options)
2890
+ update: async (input, options) => postGeneric(
2891
+ "/admin/email-template/update",
2892
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
2893
+ options
2894
+ )
2554
2895
  }
2555
2896
  },
2556
2897
  apiKey: {
@@ -2773,17 +3114,282 @@ function createDbModule(input) {
2773
3114
  return db;
2774
3115
  }
2775
3116
 
3117
+ // src/query-ast.ts
3118
+ 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;
3119
+ var FILTER_OPERATORS = /* @__PURE__ */ new Set([
3120
+ "eq",
3121
+ "neq",
3122
+ "gt",
3123
+ "gte",
3124
+ "lt",
3125
+ "lte",
3126
+ "like",
3127
+ "ilike",
3128
+ "is",
3129
+ "in",
3130
+ "contains",
3131
+ "containedBy"
3132
+ ]);
3133
+ var BOOLEAN_SAFE_OPERATORS = /* @__PURE__ */ new Set([
3134
+ "eq",
3135
+ "neq",
3136
+ "gt",
3137
+ "gte",
3138
+ "lt",
3139
+ "lte",
3140
+ "like",
3141
+ "ilike",
3142
+ "is"
3143
+ ]);
3144
+ function isRecord5(value) {
3145
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3146
+ }
3147
+ function isUuidString(value) {
3148
+ return UUID_PATTERN.test(value.trim());
3149
+ }
3150
+ function isUuidIdentifierColumn(column) {
3151
+ return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
3152
+ }
3153
+ function shouldUseUuidTextComparison(column, value) {
3154
+ return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
3155
+ }
3156
+ function isRelationSelectNode(value) {
3157
+ return isRecord5(value) && isRecord5(value.select);
3158
+ }
3159
+ function normalizeIdentifier(value, label) {
3160
+ const normalized = value.trim();
3161
+ if (!normalized) {
3162
+ throw new Error(`${label} must be a non-empty string`);
3163
+ }
3164
+ return normalized;
3165
+ }
3166
+ function stringifyFilterValue(value) {
3167
+ if (Array.isArray(value)) {
3168
+ return value.join(",");
3169
+ }
3170
+ return String(value);
3171
+ }
3172
+ function buildGatewayCondition(operator, column, value) {
3173
+ const condition = { operator };
3174
+ if (column) {
3175
+ condition.column = column;
3176
+ if (operator === "eq") {
3177
+ condition.eq_column = column;
3178
+ }
3179
+ }
3180
+ if (value !== void 0) {
3181
+ condition.value = value;
3182
+ if (operator === "eq") {
3183
+ condition.eq_value = value;
3184
+ }
3185
+ }
3186
+ if (operator === "eq" && column && value !== void 0 && shouldUseUuidTextComparison(column, value)) {
3187
+ condition.column_cast = "text";
3188
+ condition.eq_column_cast = "text";
3189
+ }
3190
+ return condition;
3191
+ }
3192
+ function compileRelationToken(key, node) {
3193
+ const nested = compileSelectShape(node.select);
3194
+ const propertyKey = normalizeIdentifier(key, "select relation key");
3195
+ const relationToken = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
3196
+ const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
3197
+ const prefix = alias ? `${alias}:` : "";
3198
+ return `${prefix}${relationToken}(${nested})`;
3199
+ }
3200
+ function compileSelectShape(select) {
3201
+ if (!isRecord5(select)) {
3202
+ throw new Error("findMany select must be an object");
3203
+ }
3204
+ const tokens = [];
3205
+ for (const [rawKey, rawValue] of Object.entries(select)) {
3206
+ if (rawValue === void 0) {
3207
+ continue;
3208
+ }
3209
+ if (rawValue === true) {
3210
+ tokens.push(normalizeIdentifier(rawKey, "select column"));
3211
+ continue;
3212
+ }
3213
+ if (isRelationSelectNode(rawValue)) {
3214
+ tokens.push(compileRelationToken(rawKey, rawValue));
3215
+ continue;
3216
+ }
3217
+ throw new Error(`Unsupported select node for "${rawKey}"`);
3218
+ }
3219
+ if (tokens.length === 0) {
3220
+ throw new Error("findMany select requires at least one field");
3221
+ }
3222
+ return tokens.join(",");
3223
+ }
3224
+ function compileColumnWhere(column, input) {
3225
+ const normalizedColumn = normalizeIdentifier(column, "where column");
3226
+ if (!isRecord5(input)) {
3227
+ return [buildGatewayCondition("eq", normalizedColumn, input)];
3228
+ }
3229
+ const conditions = [];
3230
+ for (const [rawOperator, rawValue] of Object.entries(input)) {
3231
+ if (rawValue === void 0) {
3232
+ continue;
3233
+ }
3234
+ if (!FILTER_OPERATORS.has(rawOperator)) {
3235
+ throw new Error(`Unsupported where operator "${rawOperator}" on "${normalizedColumn}"`);
3236
+ }
3237
+ if ((rawOperator === "in" || rawOperator === "contains" || rawOperator === "containedBy") && !Array.isArray(rawValue)) {
3238
+ throw new Error(`where.${normalizedColumn}.${rawOperator} requires an array value`);
3239
+ }
3240
+ conditions.push(
3241
+ buildGatewayCondition(
3242
+ rawOperator,
3243
+ normalizedColumn,
3244
+ rawValue
3245
+ )
3246
+ );
3247
+ }
3248
+ if (conditions.length === 0) {
3249
+ throw new Error(`where.${normalizedColumn} requires at least one operator`);
3250
+ }
3251
+ return conditions;
3252
+ }
3253
+ function compileBooleanExpressionTerms(clause, label) {
3254
+ if (!isRecord5(clause)) {
3255
+ throw new Error(`findMany where.${label} clauses must be objects`);
3256
+ }
3257
+ const entries = Object.entries(clause).filter(([, value]) => value !== void 0);
3258
+ if (entries.length !== 1) {
3259
+ throw new Error(`findMany where.${label} clauses must target exactly one column`);
3260
+ }
3261
+ const [rawColumn, rawValue] = entries[0];
3262
+ const column = normalizeIdentifier(rawColumn, `where.${label} column`);
3263
+ if (!isRecord5(rawValue)) {
3264
+ return [`${column}.eq.${stringifyFilterValue(rawValue)}`];
3265
+ }
3266
+ const operatorEntries = Object.entries(rawValue).filter(([, value]) => value !== void 0);
3267
+ if (operatorEntries.length === 0) {
3268
+ throw new Error(`findMany where.${label}.${column} requires at least one operator`);
3269
+ }
3270
+ if (label === "not" && operatorEntries.length > 1) {
3271
+ throw new Error("findMany where.not only supports a single lossless operator expression");
3272
+ }
3273
+ return operatorEntries.map(([rawOperator, rawOperand]) => {
3274
+ if (!BOOLEAN_SAFE_OPERATORS.has(rawOperator)) {
3275
+ throw new Error(`findMany where.${label} only supports lossless scalar operators`);
3276
+ }
3277
+ if (Array.isArray(rawOperand)) {
3278
+ throw new Error(`findMany where.${label} does not support array-valued operators`);
3279
+ }
3280
+ return `${column}.${rawOperator}.${stringifyFilterValue(rawOperand)}`;
3281
+ });
3282
+ }
3283
+ function compileWhere(where) {
3284
+ if (where === void 0) {
3285
+ return void 0;
3286
+ }
3287
+ if (!isRecord5(where)) {
3288
+ throw new Error("findMany where must be an object");
3289
+ }
3290
+ const conditions = [];
3291
+ for (const [rawKey, rawValue] of Object.entries(where)) {
3292
+ if (rawValue === void 0) {
3293
+ continue;
3294
+ }
3295
+ if (rawKey === "or") {
3296
+ if (!Array.isArray(rawValue) || rawValue.length === 0) {
3297
+ throw new Error("findMany where.or must be a non-empty array");
3298
+ }
3299
+ const expressions = rawValue.flatMap(
3300
+ (value) => compileBooleanExpressionTerms(value, "or")
3301
+ );
3302
+ conditions.push(buildGatewayCondition("or", void 0, expressions.join(",")));
3303
+ continue;
3304
+ }
3305
+ if (rawKey === "not") {
3306
+ const expressions = compileBooleanExpressionTerms(rawValue, "not");
3307
+ if (expressions.length !== 1) {
3308
+ throw new Error("findMany where.not must compile to exactly one lossless expression");
3309
+ }
3310
+ conditions.push(buildGatewayCondition("not", void 0, expressions[0]));
3311
+ continue;
3312
+ }
3313
+ conditions.push(...compileColumnWhere(rawKey, rawValue));
3314
+ }
3315
+ return conditions.length > 0 ? conditions : void 0;
3316
+ }
3317
+ function resolveOrderDirection(input) {
3318
+ if (typeof input === "boolean") {
3319
+ return input === false ? "descending" : "ascending";
3320
+ }
3321
+ if (typeof input === "string") {
3322
+ const normalized = input.trim().toLowerCase();
3323
+ if (normalized === "asc" || normalized === "ascending") {
3324
+ return "ascending";
3325
+ }
3326
+ if (normalized === "desc" || normalized === "descending") {
3327
+ return "descending";
3328
+ }
3329
+ throw new Error(`Unsupported orderBy direction "${input}"`);
3330
+ }
3331
+ return input.ascending === false ? "descending" : "ascending";
3332
+ }
3333
+ function compileOrderBy(orderBy) {
3334
+ if (orderBy === void 0) {
3335
+ return void 0;
3336
+ }
3337
+ if (!isRecord5(orderBy)) {
3338
+ throw new Error("findMany orderBy must be an object");
3339
+ }
3340
+ if ("column" in orderBy) {
3341
+ return {
3342
+ field: normalizeIdentifier(String(orderBy.column), "orderBy column"),
3343
+ direction: orderBy.ascending === false ? "descending" : "ascending"
3344
+ };
3345
+ }
3346
+ const entries = Object.entries(orderBy).filter(([, value]) => value !== void 0);
3347
+ if (entries.length === 0) {
3348
+ return void 0;
3349
+ }
3350
+ if (entries.length > 1) {
3351
+ throw new Error("findMany orderBy only supports a single column in v1");
3352
+ }
3353
+ const [column, input] = entries[0];
3354
+ return {
3355
+ field: normalizeIdentifier(column, "orderBy column"),
3356
+ direction: resolveOrderDirection(input)
3357
+ };
3358
+ }
3359
+
2776
3360
  // src/client.ts
2777
3361
  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
3362
  var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
2780
3363
  var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
3364
+ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
3365
+ "src\\client.ts",
3366
+ "src/client.ts",
3367
+ "dist\\client.",
3368
+ "dist/client.",
3369
+ "node_modules\\@xylex-group\\athena",
3370
+ "node_modules/@xylex-group/athena",
3371
+ "node:internal",
3372
+ "internal/process"
3373
+ ];
3374
+ function canUseFindManyAstTransport(state) {
3375
+ return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
3376
+ }
3377
+ function toFindManyAstOrder(order) {
3378
+ if (!order) {
3379
+ return void 0;
3380
+ }
3381
+ return {
3382
+ column: order.field,
3383
+ ascending: order.direction !== "descending"
3384
+ };
3385
+ }
2781
3386
  function formatResult(response) {
2782
3387
  const result = {
2783
3388
  data: response.data ?? null,
2784
- error: response.error ?? null,
3389
+ error: null,
2785
3390
  errorDetails: response.errorDetails ?? null,
2786
3391
  status: response.status,
3392
+ statusText: response.statusText ?? null,
2787
3393
  raw: response.raw
2788
3394
  };
2789
3395
  if (response.count !== void 0) {
@@ -2800,26 +3406,243 @@ function attachNormalizedError(result, normalizedError) {
2800
3406
  });
2801
3407
  }
2802
3408
  function createResultFormatter(experimental) {
2803
- if (!experimental?.enableErrorNormalization) {
2804
- return formatResult;
2805
- }
2806
3409
  return (response, context) => {
2807
3410
  const result = formatResult(response);
2808
- if (result.error == null) {
3411
+ if (response.error == null && response.errorDetails == null) {
2809
3412
  return result;
2810
3413
  }
2811
- const normalizedError = normalizeAthenaError(result, context);
3414
+ const normalizedError = normalizeAthenaError(
3415
+ {
3416
+ ...result,
3417
+ error: response.error ?? response.errorDetails?.message ?? null
3418
+ },
3419
+ context
3420
+ );
3421
+ result.error = createResultError(response, result, normalizedError);
2812
3422
  attachNormalizedError(result, normalizedError);
2813
3423
  return result;
2814
3424
  };
2815
3425
  }
2816
- function toSingleResult(response) {
2817
- const payload = response.data;
2818
- const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
2819
- return {
2820
- ...response,
2821
- data: singleData
2822
- };
3426
+ function isRecord6(value) {
3427
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3428
+ }
3429
+ function firstNonEmptyString2(...values) {
3430
+ for (const value of values) {
3431
+ if (typeof value === "string" && value.trim().length > 0) {
3432
+ return value.trim();
3433
+ }
3434
+ }
3435
+ return void 0;
3436
+ }
3437
+ function resolveStructuredErrorPayload2(raw) {
3438
+ if (!isRecord6(raw)) return null;
3439
+ return isRecord6(raw.error) ? raw.error : raw;
3440
+ }
3441
+ function resolveStructuredErrorDetails(payload, message) {
3442
+ if (!payload || !("details" in payload)) {
3443
+ return null;
3444
+ }
3445
+ const details = payload.details;
3446
+ if (details == null) {
3447
+ return null;
3448
+ }
3449
+ if (typeof details === "string" && details.trim() === message.trim()) {
3450
+ return null;
3451
+ }
3452
+ return details;
3453
+ }
3454
+ function createResultError(response, result, normalized) {
3455
+ const rawRecord = isRecord6(response.raw) ? response.raw : null;
3456
+ const payload = resolveStructuredErrorPayload2(response.raw);
3457
+ const message = firstNonEmptyString2(
3458
+ response.error,
3459
+ payload?.message,
3460
+ payload?.error,
3461
+ payload?.details,
3462
+ response.errorDetails?.message,
3463
+ normalized.message
3464
+ ) ?? normalized.message;
3465
+ const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
3466
+ const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
3467
+ const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
3468
+ const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
3469
+ return {
3470
+ message,
3471
+ code,
3472
+ athenaCode: normalized.code,
3473
+ gatewayCode: response.errorDetails?.code ?? null,
3474
+ kind: normalized.kind,
3475
+ category: normalized.category,
3476
+ retryable: normalized.retryable,
3477
+ details,
3478
+ hint,
3479
+ status: result.status,
3480
+ statusText,
3481
+ constraint: normalized.constraint,
3482
+ table: normalized.table,
3483
+ operation: normalized.operation,
3484
+ endpoint: response.errorDetails?.endpoint,
3485
+ method: response.errorDetails?.method,
3486
+ requestId: response.errorDetails?.requestId,
3487
+ cause: response.errorDetails?.cause,
3488
+ raw: result.raw
3489
+ };
3490
+ }
3491
+ function parseQueryTraceCallsiteFrame(frame) {
3492
+ const trimmed = frame.trim();
3493
+ if (!trimmed) {
3494
+ return null;
3495
+ }
3496
+ let body = trimmed.replace(/^at\s+/, "");
3497
+ if (body.startsWith("async ")) {
3498
+ body = body.slice(6);
3499
+ }
3500
+ let functionName;
3501
+ let location = body;
3502
+ const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
3503
+ if (wrappedMatch) {
3504
+ functionName = wrappedMatch[1].trim() || void 0;
3505
+ location = wrappedMatch[2].trim();
3506
+ }
3507
+ const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
3508
+ if (!locationMatch) {
3509
+ return null;
3510
+ }
3511
+ const filePath = locationMatch[1].replace(/^file:\/\//, "");
3512
+ const line = Number(locationMatch[2]);
3513
+ const column = Number(locationMatch[3]);
3514
+ if (!Number.isFinite(line) || !Number.isFinite(column)) {
3515
+ return null;
3516
+ }
3517
+ const normalizedPath = filePath.replace(/\\/g, "/");
3518
+ const fileName = normalizedPath.split("/").at(-1) ?? filePath;
3519
+ return {
3520
+ filePath,
3521
+ fileName,
3522
+ line,
3523
+ column,
3524
+ frame: trimmed,
3525
+ functionName
3526
+ };
3527
+ }
3528
+ function captureQueryTraceCallsite() {
3529
+ const stack = new Error().stack;
3530
+ if (!stack) return null;
3531
+ const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
3532
+ for (const frame of frames) {
3533
+ if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
3534
+ continue;
3535
+ }
3536
+ const callsite = parseQueryTraceCallsiteFrame(frame);
3537
+ if (callsite) return callsite;
3538
+ }
3539
+ const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
3540
+ return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
3541
+ }
3542
+ function defaultQueryTraceLogger(event) {
3543
+ const target = event.table ?? event.functionName ?? "gateway";
3544
+ const outcomeState = event.outcome?.error ? "error" : "ok";
3545
+ const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
3546
+ console.info(banner, event);
3547
+ }
3548
+ function captureTraceCallsite(tracer) {
3549
+ return tracer?.captureCallsite() ?? null;
3550
+ }
3551
+ function createTraceCallsiteStore(tracer, initialCallsite) {
3552
+ let storedCallsite = initialCallsite ?? void 0;
3553
+ return {
3554
+ resolve(callsite) {
3555
+ if (callsite) {
3556
+ storedCallsite = callsite;
3557
+ return callsite;
3558
+ }
3559
+ if (storedCallsite !== void 0) {
3560
+ return storedCallsite;
3561
+ }
3562
+ const capturedCallsite = captureTraceCallsite(tracer);
3563
+ if (capturedCallsite) {
3564
+ storedCallsite = capturedCallsite;
3565
+ }
3566
+ return capturedCallsite;
3567
+ }
3568
+ };
3569
+ }
3570
+ function createQueryTracer(experimental) {
3571
+ const traceOption = experimental?.traceQueries;
3572
+ if (!traceOption) {
3573
+ return void 0;
3574
+ }
3575
+ const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
3576
+ const emit = (event) => {
3577
+ try {
3578
+ logger(event);
3579
+ } catch (error) {
3580
+ console.warn("[athena-js][trace] logger failed", error);
3581
+ }
3582
+ };
3583
+ return {
3584
+ captureCallsite: captureQueryTraceCallsite,
3585
+ publishSuccess(context, result, durationMs, callsite) {
3586
+ emit({
3587
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3588
+ durationMs,
3589
+ operation: context.operation,
3590
+ endpoint: context.endpoint,
3591
+ table: context.table,
3592
+ functionName: context.functionName,
3593
+ sql: context.sql,
3594
+ payload: context.payload,
3595
+ options: context.options,
3596
+ callsite,
3597
+ outcome: {
3598
+ status: result.status,
3599
+ error: result.error,
3600
+ errorDetails: result.errorDetails ?? null,
3601
+ count: result.count ?? null,
3602
+ data: result.data,
3603
+ raw: result.raw
3604
+ }
3605
+ });
3606
+ },
3607
+ publishFailure(context, error, durationMs, callsite) {
3608
+ emit({
3609
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3610
+ durationMs,
3611
+ operation: context.operation,
3612
+ endpoint: context.endpoint,
3613
+ table: context.table,
3614
+ functionName: context.functionName,
3615
+ sql: context.sql,
3616
+ payload: context.payload,
3617
+ options: context.options,
3618
+ callsite,
3619
+ thrownError: error
3620
+ });
3621
+ }
3622
+ };
3623
+ }
3624
+ async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
3625
+ if (!tracer) {
3626
+ return runner();
3627
+ }
3628
+ const callsite = callsiteOverride ?? tracer.captureCallsite();
3629
+ const startedAt = Date.now();
3630
+ try {
3631
+ const result = await runner();
3632
+ tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
3633
+ return result;
3634
+ } catch (error) {
3635
+ tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
3636
+ throw error;
3637
+ }
3638
+ }
3639
+ function toSingleResult(response) {
3640
+ const payload = response.data;
3641
+ const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
3642
+ return {
3643
+ ...response,
3644
+ data: singleData
3645
+ };
2823
3646
  }
2824
3647
  function mergeOptions(...options) {
2825
3648
  return options.reduce((acc, next) => {
@@ -2833,15 +3656,16 @@ function asAthenaJsonObject(value) {
2833
3656
  function asAthenaJsonObjectArray(values) {
2834
3657
  return values;
2835
3658
  }
2836
- function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
3659
+ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
2837
3660
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
2838
3661
  let selectedOptions;
2839
3662
  let promise = null;
2840
- const run = (columns, options) => {
3663
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
3664
+ const run = (columns, options, callsite) => {
2841
3665
  const payloadColumns = columns ?? selectedColumns;
2842
3666
  const payloadOptions = options ?? selectedOptions;
2843
3667
  if (!promise) {
2844
- promise = executor(payloadColumns, payloadOptions);
3668
+ promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
2845
3669
  }
2846
3670
  return promise;
2847
3671
  };
@@ -2849,7 +3673,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2849
3673
  select(columns = selectedColumns, options) {
2850
3674
  selectedColumns = columns;
2851
3675
  selectedOptions = options ?? selectedOptions;
2852
- return run(columns, options);
3676
+ return run(columns, options, captureTraceCallsite(tracer));
2853
3677
  },
2854
3678
  returning(columns = selectedColumns, options) {
2855
3679
  return mutationQuery.select(columns, options);
@@ -2857,7 +3681,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2857
3681
  single(columns = selectedColumns, options) {
2858
3682
  selectedColumns = columns;
2859
3683
  selectedOptions = options ?? selectedOptions;
2860
- return run(columns, options).then(toSingleResult);
3684
+ return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
2861
3685
  },
2862
3686
  maybeSingle(columns = selectedColumns, options) {
2863
3687
  return mutationQuery.single(columns, options);
@@ -2880,21 +3704,12 @@ function getResourceId(state) {
2880
3704
  );
2881
3705
  return candidate?.value?.toString();
2882
3706
  }
2883
- function stringifyFilterValue(value) {
3707
+ function stringifyFilterValue2(value) {
2884
3708
  if (Array.isArray(value)) {
2885
3709
  return value.join(",");
2886
3710
  }
2887
3711
  return String(value);
2888
3712
  }
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
3713
  function normalizeCast(cast) {
2899
3714
  const normalized = cast.trim().toLowerCase();
2900
3715
  if (!SAFE_CAST_PATTERN.test(normalized)) {
@@ -2917,25 +3732,92 @@ function withCast(expression, cast) {
2917
3732
  }
2918
3733
  function buildSelectColumnsClause(columns) {
2919
3734
  if (Array.isArray(columns)) {
2920
- return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
3735
+ return columns.map((column) => quoteSelectColumnToken(column)).join(", ");
2921
3736
  }
2922
3737
  return quoteSelectColumnsExpression(columns);
2923
3738
  }
3739
+ function parseIdentifierSegment(input) {
3740
+ const trimmed = input.trim();
3741
+ if (!trimmed) return null;
3742
+ if (!trimmed.startsWith('"')) {
3743
+ return {
3744
+ normalizedValue: trimmed.toLowerCase()
3745
+ };
3746
+ }
3747
+ let value = "";
3748
+ let index = 1;
3749
+ let closed = false;
3750
+ while (index < trimmed.length) {
3751
+ const char = trimmed[index];
3752
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
3753
+ if (char === '"' && next === '"') {
3754
+ value += '"';
3755
+ index += 2;
3756
+ continue;
3757
+ }
3758
+ if (char === '"') {
3759
+ closed = true;
3760
+ index += 1;
3761
+ break;
3762
+ }
3763
+ value += char;
3764
+ index += 1;
3765
+ }
3766
+ if (!closed || trimmed.slice(index).trim().length > 0 || !value.trim()) {
3767
+ return null;
3768
+ }
3769
+ return {
3770
+ normalizedValue: value
3771
+ };
3772
+ }
3773
+ function splitQualifiedTableName(tableName) {
3774
+ const trimmed = tableName.trim();
3775
+ let inQuotes = false;
3776
+ for (let index = 0; index < trimmed.length; index += 1) {
3777
+ const char = trimmed[index];
3778
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
3779
+ if (char === '"') {
3780
+ if (inQuotes && next === '"') {
3781
+ index += 1;
3782
+ continue;
3783
+ }
3784
+ inQuotes = !inQuotes;
3785
+ continue;
3786
+ }
3787
+ if (char === "." && !inQuotes) {
3788
+ const schemaSegment = trimmed.slice(0, index).trim();
3789
+ const tableSegment = trimmed.slice(index + 1).trim();
3790
+ if (!schemaSegment || !tableSegment) {
3791
+ return null;
3792
+ }
3793
+ return { schemaSegment };
3794
+ }
3795
+ }
3796
+ return null;
3797
+ }
2924
3798
  function resolveTableNameForCall(tableName, schema) {
2925
3799
  if (!schema) return tableName;
2926
3800
  const normalizedSchema = schema.trim();
2927
3801
  if (!normalizedSchema) {
2928
3802
  throw new Error("schema option must be a non-empty string");
2929
3803
  }
2930
- if (tableName.includes(".")) {
2931
- if (tableName.startsWith(`${normalizedSchema}.`)) {
2932
- return tableName;
3804
+ const normalizedTableName = tableName.trim();
3805
+ const parsedSchema = parseIdentifierSegment(normalizedSchema);
3806
+ if (!parsedSchema) {
3807
+ throw new Error("schema option must be a non-empty string");
3808
+ }
3809
+ const qualified = splitQualifiedTableName(normalizedTableName);
3810
+ if (qualified) {
3811
+ const parsedTableSchema = parseIdentifierSegment(qualified.schemaSegment);
3812
+ const sameSchema = parsedTableSchema ? parsedTableSchema.normalizedValue === parsedSchema.normalizedValue : normalizedTableName.startsWith(`${normalizedSchema}.`);
3813
+ if (sameSchema) {
3814
+ return normalizedTableName;
2933
3815
  }
2934
3816
  throw new Error(
2935
- `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
3817
+ `schema option "${normalizedSchema}" conflicts with schema-qualified table "${normalizedTableName}"`
2936
3818
  );
2937
3819
  }
2938
- return `${normalizedSchema}.${tableName}`;
3820
+ return `${normalizedSchema}.${normalizedTableName}`;
2939
3821
  }
2940
3822
  function conditionToSqlClause(condition) {
2941
3823
  if (!condition.column) return null;
@@ -3013,6 +3895,237 @@ function buildTypedSelectQuery(input) {
3013
3895
  }
3014
3896
  return `${sqlParts.join(" ")};`;
3015
3897
  }
3898
+ function sanitizeSqlComment(comment) {
3899
+ return comment.replace(/\*\//g, "* /");
3900
+ }
3901
+ function toSqlJsonLiteral(value) {
3902
+ if (value === void 0) return "DEFAULT";
3903
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3904
+ return toSqlLiteral(value);
3905
+ }
3906
+ return `'${escapeSqlStringLiteral(JSON.stringify(value))}'::jsonb`;
3907
+ }
3908
+ function conditionToDebugSqlClause(condition) {
3909
+ const exact = conditionToSqlClause(condition);
3910
+ if (exact) return exact;
3911
+ const rawCondition = sanitizeSqlComment(JSON.stringify(condition));
3912
+ if (!condition.column) {
3913
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
3914
+ }
3915
+ const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
3916
+ const value = condition.value;
3917
+ const rhs = withCast(toSqlJsonLiteral(value), condition.value_cast);
3918
+ switch (condition.operator) {
3919
+ case "contains":
3920
+ return `${column} @> ${rhs}`;
3921
+ case "containedBy":
3922
+ return `${column} <@ ${rhs}`;
3923
+ case "not":
3924
+ return `TRUE /* NOT expression passthrough: ${rawCondition} */`;
3925
+ case "or":
3926
+ return `TRUE /* OR expression passthrough: ${rawCondition} */`;
3927
+ default:
3928
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
3929
+ }
3930
+ }
3931
+ function resolvePagination(input) {
3932
+ let limit = input.limit;
3933
+ let offset = input.offset;
3934
+ if (limit === void 0 && input.pageSize !== void 0) {
3935
+ limit = input.pageSize;
3936
+ }
3937
+ if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
3938
+ offset = (input.currentPage - 1) * input.pageSize;
3939
+ }
3940
+ return { limit, offset };
3941
+ }
3942
+ function appendOrderLimitOffset(sqlParts, order, limit, offset) {
3943
+ if (order?.field) {
3944
+ const direction = order.direction === "descending" ? "DESC" : "ASC";
3945
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(order.field)} ${direction}`);
3946
+ }
3947
+ if (limit !== void 0) {
3948
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
3949
+ }
3950
+ if (offset !== void 0) {
3951
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
3952
+ }
3953
+ }
3954
+ function buildDebugSelectQuery(input) {
3955
+ const sqlParts = [
3956
+ `SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
3957
+ ];
3958
+ if (input.conditions?.length) {
3959
+ const whereClauses = input.conditions.map(conditionToDebugSqlClause);
3960
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
3961
+ }
3962
+ const pagination = resolvePagination(input);
3963
+ appendOrderLimitOffset(sqlParts, input.order, pagination.limit, pagination.offset);
3964
+ return `${sqlParts.join(" ")};`;
3965
+ }
3966
+ function resolveDebugTableIdentifier(tableName) {
3967
+ if (!tableName?.trim()) {
3968
+ return '"__unknown_table__"';
3969
+ }
3970
+ return quoteQualifiedIdentifier(tableName);
3971
+ }
3972
+ function buildInsertDebugSql(payload) {
3973
+ const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
3974
+ const columns = [];
3975
+ const seen = /* @__PURE__ */ new Set();
3976
+ for (const row of rows) {
3977
+ for (const column of Object.keys(row)) {
3978
+ if (seen.has(column)) continue;
3979
+ seen.add(column);
3980
+ columns.push(column);
3981
+ }
3982
+ }
3983
+ const sqlParts = [`INSERT INTO ${quoteQualifiedIdentifier(payload.table_name)}`];
3984
+ if (!rows.length || !columns.length) {
3985
+ sqlParts.push("DEFAULT VALUES");
3986
+ if (rows.length > 1) {
3987
+ sqlParts.push(`/* trace: ${rows.length} rows collapsed to DEFAULT VALUES */`);
3988
+ }
3989
+ } else {
3990
+ const valuesClause = rows.map((row) => {
3991
+ const values = columns.map((column) => {
3992
+ const hasColumn = Object.prototype.hasOwnProperty.call(row, column);
3993
+ if (!hasColumn) {
3994
+ return payload.default_to_null ? "NULL" : "DEFAULT";
3995
+ }
3996
+ const rowValue = row[column];
3997
+ return toSqlJsonLiteral(rowValue);
3998
+ });
3999
+ return `(${values.join(", ")})`;
4000
+ }).join(", ");
4001
+ const columnClause = columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
4002
+ sqlParts.push(`(${columnClause})`);
4003
+ sqlParts.push(`VALUES ${valuesClause}`);
4004
+ }
4005
+ if (payload.on_conflict) {
4006
+ const conflictColumns = Array.isArray(payload.on_conflict) ? payload.on_conflict.map((column) => quoteQualifiedIdentifier(column)).join(", ") : payload.on_conflict;
4007
+ if (payload.update_body && Object.keys(payload.update_body).length > 0) {
4008
+ const assignments = Object.entries(payload.update_body).map(
4009
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
4010
+ );
4011
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO UPDATE SET ${assignments.join(", ")}`);
4012
+ } else {
4013
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO NOTHING`);
4014
+ }
4015
+ }
4016
+ if (payload.columns) {
4017
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
4018
+ }
4019
+ return `${sqlParts.join(" ")};`;
4020
+ }
4021
+ function buildUpdateDebugSql(payload) {
4022
+ const set = payload.set ?? payload.data ?? {};
4023
+ const assignments = Object.entries(set).map(
4024
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
4025
+ );
4026
+ const sqlParts = [
4027
+ `UPDATE ${resolveDebugTableIdentifier(payload.table_name)} SET ${assignments.length ? assignments.join(", ") : "/* empty set */"}`
4028
+ ];
4029
+ if (payload.conditions?.length) {
4030
+ const whereClauses = payload.conditions.map(conditionToDebugSqlClause);
4031
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
4032
+ }
4033
+ const pagination = resolvePagination({
4034
+ currentPage: payload.current_page,
4035
+ pageSize: payload.page_size
4036
+ });
4037
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
4038
+ if (payload.columns) {
4039
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
4040
+ }
4041
+ return `${sqlParts.join(" ")};`;
4042
+ }
4043
+ function buildDeleteDebugSql(payload) {
4044
+ const sqlParts = [`DELETE FROM ${quoteQualifiedIdentifier(payload.table_name)}`];
4045
+ const whereClauses = [];
4046
+ if (payload.resource_id) {
4047
+ whereClauses.push(`"resource_id" = ${toSqlLiteral(payload.resource_id)}`);
4048
+ }
4049
+ if (payload.conditions?.length) {
4050
+ whereClauses.push(...payload.conditions.map(conditionToDebugSqlClause));
4051
+ }
4052
+ if (whereClauses.length) {
4053
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
4054
+ }
4055
+ const pagination = resolvePagination({
4056
+ currentPage: payload.current_page,
4057
+ pageSize: payload.page_size
4058
+ });
4059
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
4060
+ if (payload.columns) {
4061
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
4062
+ }
4063
+ return `${sqlParts.join(" ")};`;
4064
+ }
4065
+ function rpcFilterToSqlClause(filter) {
4066
+ const column = quoteQualifiedIdentifier(filter.column);
4067
+ const value = filter.value;
4068
+ switch (filter.operator) {
4069
+ case "eq":
4070
+ case "neq":
4071
+ case "gt":
4072
+ case "gte":
4073
+ case "lt":
4074
+ case "lte":
4075
+ case "like":
4076
+ case "ilike": {
4077
+ if (value === void 0 || Array.isArray(value)) {
4078
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4079
+ }
4080
+ const operatorMap = {
4081
+ eq: "=",
4082
+ neq: "!=",
4083
+ gt: ">",
4084
+ gte: ">=",
4085
+ lt: "<",
4086
+ lte: "<=",
4087
+ like: "LIKE",
4088
+ ilike: "ILIKE"
4089
+ };
4090
+ return `${column} ${operatorMap[filter.operator]} ${toSqlLiteral(value)}`;
4091
+ }
4092
+ case "is":
4093
+ if (value === null) return `${column} IS NULL`;
4094
+ if (value === true) return `${column} IS TRUE`;
4095
+ if (value === false) return `${column} IS FALSE`;
4096
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4097
+ case "in":
4098
+ if (!Array.isArray(value)) {
4099
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4100
+ }
4101
+ if (value.length === 0) return "FALSE";
4102
+ return `${column} IN (${value.map((item) => toSqlLiteral(item)).join(", ")})`;
4103
+ default:
4104
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4105
+ }
4106
+ }
4107
+ function buildRpcDebugSql(payload) {
4108
+ const argsEntries = payload.args ? Object.entries(payload.args) : [];
4109
+ const argsClause = argsEntries.map(([key, value]) => `${quoteQualifiedIdentifier(key)} => ${toSqlJsonLiteral(value)}`).join(", ");
4110
+ const functionRef = payload.schema ? `${quoteQualifiedIdentifier(payload.schema)}.${quoteQualifiedIdentifier(payload.function)}` : quoteQualifiedIdentifier(payload.function);
4111
+ const sqlParts = [
4112
+ `SELECT ${payload.select ? quoteSelectColumnsExpression(payload.select) : "*"} FROM ${functionRef}(${argsClause})`
4113
+ ];
4114
+ if (payload.filters?.length) {
4115
+ sqlParts.push(`WHERE ${payload.filters.map(rpcFilterToSqlClause).join(" AND ")}`);
4116
+ }
4117
+ if (payload.order?.column) {
4118
+ const direction = payload.order.ascending === false ? "DESC" : "ASC";
4119
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(payload.order.column)} ${direction}`);
4120
+ }
4121
+ if (payload.limit !== void 0) {
4122
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(payload.limit))}`);
4123
+ }
4124
+ if (payload.offset !== void 0) {
4125
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(payload.offset))}`);
4126
+ }
4127
+ return `${sqlParts.join(" ")};`;
4128
+ }
3016
4129
  function createFilterMethods(state, addCondition, self) {
3017
4130
  return {
3018
4131
  eq(column, value) {
@@ -3124,7 +4237,7 @@ function createFilterMethods(state, addCondition, self) {
3124
4237
  not(columnOrExpression, operator, value) {
3125
4238
  const expression = String(columnOrExpression);
3126
4239
  if (operator != null && value !== void 0) {
3127
- addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
4240
+ addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue2(value)}`);
3128
4241
  } else {
3129
4242
  addCondition("not", void 0, expression);
3130
4243
  }
@@ -3187,14 +4300,15 @@ function createRpcFilterMethods(filters, self) {
3187
4300
  }
3188
4301
  };
3189
4302
  }
3190
- function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
4303
+ function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
3191
4304
  const state = {
3192
4305
  filters: []
3193
4306
  };
3194
4307
  let selectedColumns;
3195
4308
  let selectedOptions;
3196
4309
  let promise = null;
3197
- const executeRpc = async (columns, options) => {
4310
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
4311
+ const executeRpc = async (columns, options, callsite) => {
3198
4312
  const mergedOptions = mergeOptions(baseOptions, options);
3199
4313
  const payload = {
3200
4314
  function: functionName,
@@ -3208,14 +4322,30 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
3208
4322
  offset: state.offset,
3209
4323
  order: state.order
3210
4324
  };
3211
- const response = await client.rpcGateway(payload, mergedOptions);
3212
- return formatGatewayResult(response, { operation: "rpc" });
4325
+ const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
4326
+ const sql = buildRpcDebugSql(payload);
4327
+ return executeWithQueryTrace(
4328
+ tracer,
4329
+ {
4330
+ operation: "rpc",
4331
+ endpoint,
4332
+ functionName,
4333
+ sql,
4334
+ payload,
4335
+ options: mergedOptions
4336
+ },
4337
+ async () => {
4338
+ const response = await client.rpcGateway(payload, mergedOptions);
4339
+ return formatGatewayResult(response, { operation: "rpc" });
4340
+ },
4341
+ callsite
4342
+ );
3213
4343
  };
3214
- const run = (columns, options) => {
4344
+ const run = (columns, options, callsite) => {
3215
4345
  const payloadColumns = columns ?? selectedColumns;
3216
4346
  const payloadOptions = options ?? selectedOptions;
3217
4347
  if (!promise) {
3218
- promise = executeRpc(payloadColumns, payloadOptions);
4348
+ promise = executeRpc(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
3219
4349
  }
3220
4350
  return promise;
3221
4351
  };
@@ -3225,10 +4355,10 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
3225
4355
  select(columns = selectedColumns, options) {
3226
4356
  selectedColumns = columns;
3227
4357
  selectedOptions = options ?? selectedOptions;
3228
- return run(columns, options);
4358
+ return run(columns, options, captureTraceCallsite(tracer));
3229
4359
  },
3230
4360
  async single(columns, options) {
3231
- const result = await run(columns, options);
4361
+ const result = await run(columns, options, captureTraceCallsite(tracer));
3232
4362
  return toSingleResult(result);
3233
4363
  },
3234
4364
  maybeSingle(columns, options) {
@@ -3263,7 +4393,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
3263
4393
  });
3264
4394
  return builder;
3265
4395
  }
3266
- function createTableBuilder(tableName, client, formatGatewayResult) {
4396
+ function createTableBuilder(tableName, client, formatGatewayResult, tracer, experimental) {
3267
4397
  const state = {
3268
4398
  conditions: []
3269
4399
  };
@@ -3295,15 +4425,24 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3295
4425
  }
3296
4426
  state.conditions.push(condition);
3297
4427
  };
4428
+ const snapshotState = () => ({
4429
+ conditions: state.conditions.map((condition) => ({ ...condition })),
4430
+ limit: state.limit,
4431
+ offset: state.offset,
4432
+ order: state.order ? { ...state.order } : void 0,
4433
+ currentPage: state.currentPage,
4434
+ pageSize: state.pageSize,
4435
+ totalPages: state.totalPages
4436
+ });
3298
4437
  const builder = {};
3299
4438
  const filterMethods = createFilterMethods(
3300
4439
  state,
3301
4440
  addCondition,
3302
4441
  builder
3303
4442
  );
3304
- const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
4443
+ const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
3305
4444
  const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
3306
- const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
4445
+ const conditions = executionState.conditions.length ? executionState.conditions.map((condition) => ({ ...condition })) : void 0;
3307
4446
  const hasTypedEqualityComparison = conditions?.some(
3308
4447
  (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
3309
4448
  ) ?? false;
@@ -3312,53 +4451,107 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3312
4451
  tableName: resolvedTableName,
3313
4452
  columns,
3314
4453
  conditions,
3315
- limit: state.limit,
3316
- offset: state.offset,
3317
- currentPage: state.currentPage,
3318
- pageSize: state.pageSize,
3319
- order: state.order
4454
+ limit: executionState.limit,
4455
+ offset: executionState.offset,
4456
+ currentPage: executionState.currentPage,
4457
+ pageSize: executionState.pageSize,
4458
+ order: executionState.order
3320
4459
  });
3321
4460
  if (query) {
3322
- const queryResponse = await client.queryGateway({ query }, options);
3323
- return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
4461
+ const payload2 = { query };
4462
+ return executeWithQueryTrace(
4463
+ tracer,
4464
+ {
4465
+ operation: "select",
4466
+ endpoint: "/gateway/query",
4467
+ table: resolvedTableName,
4468
+ sql: query,
4469
+ payload: payload2,
4470
+ options
4471
+ },
4472
+ async () => {
4473
+ const queryResponse = await client.queryGateway(payload2, options);
4474
+ return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
4475
+ },
4476
+ callsite
4477
+ );
3324
4478
  }
3325
4479
  }
3326
4480
  const payload = {
3327
4481
  table_name: resolvedTableName,
3328
4482
  columns,
3329
4483
  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,
4484
+ limit: executionState.limit,
4485
+ offset: executionState.offset,
4486
+ current_page: executionState.currentPage,
4487
+ page_size: executionState.pageSize,
4488
+ total_pages: executionState.totalPages,
4489
+ sort_by: executionState.order,
3336
4490
  strip_nulls: options?.stripNulls ?? true,
3337
4491
  count: options?.count,
3338
4492
  head: options?.head
3339
4493
  };
3340
- const response = await client.fetchGateway(payload, options);
3341
- return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4494
+ const sql = buildDebugSelectQuery({
4495
+ tableName: resolvedTableName,
4496
+ columns,
4497
+ conditions,
4498
+ limit: executionState.limit,
4499
+ offset: executionState.offset,
4500
+ currentPage: executionState.currentPage,
4501
+ pageSize: executionState.pageSize,
4502
+ order: executionState.order
4503
+ });
4504
+ return executeWithQueryTrace(
4505
+ tracer,
4506
+ {
4507
+ operation: "select",
4508
+ endpoint: "/gateway/fetch",
4509
+ table: resolvedTableName,
4510
+ sql,
4511
+ payload,
4512
+ options
4513
+ },
4514
+ async () => {
4515
+ const response = await client.fetchGateway(payload, options);
4516
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4517
+ },
4518
+ callsite
4519
+ );
3342
4520
  };
3343
- const createSelectChain = (columns, options) => {
4521
+ const createSelectChain = (columns, options, initialCallsite) => {
3344
4522
  const chain = {};
4523
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
3345
4524
  const filterMethods2 = createFilterMethods(state, addCondition, chain);
3346
4525
  Object.assign(chain, filterMethods2, {
3347
4526
  async single(cols, opts) {
3348
- const r = await runSelect(cols ?? columns, opts ?? options);
4527
+ const r = await runSelect(
4528
+ cols ?? columns,
4529
+ opts ?? options,
4530
+ snapshotState(),
4531
+ callsiteStore.resolve(captureTraceCallsite(tracer))
4532
+ );
3349
4533
  return toSingleResult(r);
3350
4534
  },
3351
4535
  maybeSingle(cols, opts) {
3352
4536
  return chain.single(cols, opts);
3353
4537
  },
3354
4538
  then(onfulfilled, onrejected) {
3355
- return runSelect(columns, options).then(onfulfilled, onrejected);
4539
+ return runSelect(
4540
+ columns,
4541
+ options,
4542
+ snapshotState(),
4543
+ callsiteStore.resolve()
4544
+ ).then(onfulfilled, onrejected);
3356
4545
  },
3357
4546
  catch(onrejected) {
3358
- return runSelect(columns, options).catch(onrejected);
4547
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).catch(
4548
+ onrejected
4549
+ );
3359
4550
  },
3360
4551
  finally(onfinally) {
3361
- return runSelect(columns, options).finally(onfinally);
4552
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).finally(
4553
+ onfinally
4554
+ );
3362
4555
  }
3363
4556
  });
3364
4557
  return chain;
@@ -3375,11 +4568,75 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3375
4568
  return builder;
3376
4569
  },
3377
4570
  select(columns = DEFAULT_COLUMNS, options) {
3378
- return createSelectChain(columns, options);
4571
+ return createSelectChain(columns, options, captureTraceCallsite(tracer));
4572
+ },
4573
+ async findMany(options) {
4574
+ const columns = compileSelectShape(options.select);
4575
+ const baseState = snapshotState();
4576
+ const executionState = snapshotState();
4577
+ const callsite = captureTraceCallsite(tracer);
4578
+ const compiledWhere = compileWhere(options.where);
4579
+ if (compiledWhere?.length) {
4580
+ executionState.conditions.push(...compiledWhere);
4581
+ }
4582
+ if (options.orderBy !== void 0) {
4583
+ executionState.order = compileOrderBy(options.orderBy);
4584
+ }
4585
+ if (options.limit !== void 0) {
4586
+ executionState.limit = options.limit;
4587
+ }
4588
+ if (experimental?.findManyAst && canUseFindManyAstTransport(baseState)) {
4589
+ const resolvedTableName = resolveTableNameForCall(tableName, void 0);
4590
+ const payload = {
4591
+ table_name: resolvedTableName,
4592
+ select: options.select
4593
+ };
4594
+ if (options.where !== void 0) {
4595
+ payload.where = options.where;
4596
+ }
4597
+ const astOrder = toFindManyAstOrder(executionState.order);
4598
+ if (astOrder !== void 0) {
4599
+ payload.orderBy = astOrder;
4600
+ }
4601
+ if (executionState.limit !== void 0) {
4602
+ payload.limit = executionState.limit;
4603
+ }
4604
+ const sql = buildDebugSelectQuery({
4605
+ tableName: resolvedTableName,
4606
+ columns,
4607
+ conditions: executionState.conditions,
4608
+ limit: executionState.limit,
4609
+ order: executionState.order
4610
+ });
4611
+ return executeWithQueryTrace(
4612
+ tracer,
4613
+ {
4614
+ operation: "select",
4615
+ endpoint: "/gateway/fetch",
4616
+ table: resolvedTableName,
4617
+ sql,
4618
+ payload
4619
+ },
4620
+ async () => {
4621
+ const response = await client.fetchGateway(
4622
+ payload
4623
+ );
4624
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4625
+ },
4626
+ callsite
4627
+ );
4628
+ }
4629
+ return runSelect(
4630
+ columns,
4631
+ void 0,
4632
+ executionState,
4633
+ callsite
4634
+ );
3379
4635
  },
3380
4636
  insert(values, options) {
4637
+ const mutationCallsite = captureTraceCallsite(tracer);
3381
4638
  if (Array.isArray(values)) {
3382
- const executeInsertMany = async (columns, selectOptions) => {
4639
+ const executeInsertMany = async (columns, selectOptions, callsite) => {
3383
4640
  const mergedOptions = mergeOptions(options, selectOptions);
3384
4641
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3385
4642
  const payload = {
@@ -3392,12 +4649,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3392
4649
  if (mergedOptions?.defaultToNull !== void 0) {
3393
4650
  payload.default_to_null = mergedOptions.defaultToNull;
3394
4651
  }
3395
- const response = await client.insertGateway(payload, mergedOptions);
3396
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4652
+ const sql = buildInsertDebugSql(payload);
4653
+ return executeWithQueryTrace(
4654
+ tracer,
4655
+ {
4656
+ operation: "insert",
4657
+ endpoint: "/gateway/insert",
4658
+ table: resolvedTableName,
4659
+ sql,
4660
+ payload,
4661
+ options: mergedOptions
4662
+ },
4663
+ async () => {
4664
+ const response = await client.insertGateway(payload, mergedOptions);
4665
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4666
+ },
4667
+ callsite
4668
+ );
3397
4669
  };
3398
- return createMutationQuery(executeInsertMany);
4670
+ return createMutationQuery(executeInsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
3399
4671
  }
3400
- const executeInsertOne = async (columns, selectOptions) => {
4672
+ const executeInsertOne = async (columns, selectOptions, callsite) => {
3401
4673
  const mergedOptions = mergeOptions(options, selectOptions);
3402
4674
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3403
4675
  const payload = {
@@ -3410,14 +4682,30 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3410
4682
  if (mergedOptions?.defaultToNull !== void 0) {
3411
4683
  payload.default_to_null = mergedOptions.defaultToNull;
3412
4684
  }
3413
- const response = await client.insertGateway(payload, mergedOptions);
3414
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4685
+ const sql = buildInsertDebugSql(payload);
4686
+ return executeWithQueryTrace(
4687
+ tracer,
4688
+ {
4689
+ operation: "insert",
4690
+ endpoint: "/gateway/insert",
4691
+ table: resolvedTableName,
4692
+ sql,
4693
+ payload,
4694
+ options: mergedOptions
4695
+ },
4696
+ async () => {
4697
+ const response = await client.insertGateway(payload, mergedOptions);
4698
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4699
+ },
4700
+ callsite
4701
+ );
3415
4702
  };
3416
- return createMutationQuery(executeInsertOne);
4703
+ return createMutationQuery(executeInsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
3417
4704
  },
3418
4705
  upsert(values, options) {
4706
+ const mutationCallsite = captureTraceCallsite(tracer);
3419
4707
  if (Array.isArray(values)) {
3420
- const executeUpsertMany = async (columns, selectOptions) => {
4708
+ const executeUpsertMany = async (columns, selectOptions, callsite) => {
3421
4709
  const mergedOptions = mergeOptions(options, selectOptions);
3422
4710
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3423
4711
  const payload = {
@@ -3432,12 +4720,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3432
4720
  if (mergedOptions?.defaultToNull !== void 0) {
3433
4721
  payload.default_to_null = mergedOptions.defaultToNull;
3434
4722
  }
3435
- const response = await client.insertGateway(payload, mergedOptions);
3436
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4723
+ const sql = buildInsertDebugSql(payload);
4724
+ return executeWithQueryTrace(
4725
+ tracer,
4726
+ {
4727
+ operation: "upsert",
4728
+ endpoint: "/gateway/insert",
4729
+ table: resolvedTableName,
4730
+ sql,
4731
+ payload,
4732
+ options: mergedOptions
4733
+ },
4734
+ async () => {
4735
+ const response = await client.insertGateway(payload, mergedOptions);
4736
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4737
+ },
4738
+ callsite
4739
+ );
3437
4740
  };
3438
- return createMutationQuery(executeUpsertMany);
4741
+ return createMutationQuery(executeUpsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
3439
4742
  }
3440
- const executeUpsertOne = async (columns, selectOptions) => {
4743
+ const executeUpsertOne = async (columns, selectOptions, callsite) => {
3441
4744
  const mergedOptions = mergeOptions(options, selectOptions);
3442
4745
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3443
4746
  const payload = {
@@ -3452,13 +4755,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3452
4755
  if (mergedOptions?.defaultToNull !== void 0) {
3453
4756
  payload.default_to_null = mergedOptions.defaultToNull;
3454
4757
  }
3455
- const response = await client.insertGateway(payload, mergedOptions);
3456
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4758
+ const sql = buildInsertDebugSql(payload);
4759
+ return executeWithQueryTrace(
4760
+ tracer,
4761
+ {
4762
+ operation: "upsert",
4763
+ endpoint: "/gateway/insert",
4764
+ table: resolvedTableName,
4765
+ sql,
4766
+ payload,
4767
+ options: mergedOptions
4768
+ },
4769
+ async () => {
4770
+ const response = await client.insertGateway(payload, mergedOptions);
4771
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4772
+ },
4773
+ callsite
4774
+ );
3457
4775
  };
3458
- return createMutationQuery(executeUpsertOne);
4776
+ return createMutationQuery(executeUpsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
3459
4777
  },
3460
4778
  update(values, options) {
3461
- const executeUpdate = async (columns, selectOptions) => {
4779
+ const mutationCallsite = captureTraceCallsite(tracer);
4780
+ const executeUpdate = async (columns, selectOptions, callsite) => {
3462
4781
  const filters = state.conditions.length ? [...state.conditions] : void 0;
3463
4782
  const mergedOptions = mergeOptions(options, selectOptions);
3464
4783
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
@@ -3473,10 +4792,25 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3473
4792
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
3474
4793
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
3475
4794
  if (columns) payload.columns = columns;
3476
- const response = await client.updateGateway(payload, mergedOptions);
3477
- return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
4795
+ const sql = buildUpdateDebugSql(payload);
4796
+ return executeWithQueryTrace(
4797
+ tracer,
4798
+ {
4799
+ operation: "update",
4800
+ endpoint: "/gateway/update",
4801
+ table: resolvedTableName,
4802
+ sql,
4803
+ payload,
4804
+ options: mergedOptions
4805
+ },
4806
+ async () => {
4807
+ const response = await client.updateGateway(payload, mergedOptions);
4808
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
4809
+ },
4810
+ callsite
4811
+ );
3478
4812
  };
3479
- const mutation = createMutationQuery(executeUpdate, null);
4813
+ const mutation = createMutationQuery(executeUpdate, null, tracer, mutationCallsite);
3480
4814
  const updateChain = {};
3481
4815
  const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
3482
4816
  Object.assign(updateChain, filterMethods2, mutation);
@@ -3488,7 +4822,8 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3488
4822
  if (!resourceId && !filters?.length) {
3489
4823
  throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
3490
4824
  }
3491
- const executeDelete = async (columns, selectOptions) => {
4825
+ const mutationCallsite = captureTraceCallsite(tracer);
4826
+ const executeDelete = async (columns, selectOptions, callsite) => {
3492
4827
  const mergedOptions = mergeOptions(options, selectOptions);
3493
4828
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
3494
4829
  const payload = {
@@ -3501,13 +4836,33 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3501
4836
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
3502
4837
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
3503
4838
  if (columns) payload.columns = columns;
3504
- const response = await client.deleteGateway(payload, mergedOptions);
3505
- return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
4839
+ const sql = buildDeleteDebugSql(payload);
4840
+ return executeWithQueryTrace(
4841
+ tracer,
4842
+ {
4843
+ operation: "delete",
4844
+ endpoint: "/gateway/delete",
4845
+ table: resolvedTableName,
4846
+ sql,
4847
+ payload,
4848
+ options: mergedOptions
4849
+ },
4850
+ async () => {
4851
+ const response = await client.deleteGateway(payload, mergedOptions);
4852
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
4853
+ },
4854
+ callsite
4855
+ );
3506
4856
  };
3507
- return createMutationQuery(executeDelete, null);
4857
+ return createMutationQuery(executeDelete, null, tracer, mutationCallsite);
3508
4858
  },
3509
4859
  async single(columns, options) {
3510
- const response = await builder.select(columns, options);
4860
+ const response = await runSelect(
4861
+ columns ?? DEFAULT_COLUMNS,
4862
+ options,
4863
+ snapshotState(),
4864
+ captureTraceCallsite(tracer)
4865
+ );
3511
4866
  return toSingleResult(response);
3512
4867
  },
3513
4868
  async maybeSingle(columns, options) {
@@ -3516,14 +4871,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
3516
4871
  });
3517
4872
  return builder;
3518
4873
  }
3519
- function createQueryBuilder(client, formatGatewayResult) {
4874
+ function createQueryBuilder(client, formatGatewayResult, tracer) {
3520
4875
  return async function query(query, options) {
3521
4876
  const normalizedQuery = query.trim();
3522
4877
  if (!normalizedQuery) {
3523
4878
  throw new Error("query requires a non-empty string");
3524
4879
  }
3525
- const response = await client.queryGateway({ query: normalizedQuery }, options);
3526
- return formatGatewayResult(response, { operation: "query" });
4880
+ const payload = { query: normalizedQuery };
4881
+ const callsite = captureTraceCallsite(tracer);
4882
+ return executeWithQueryTrace(
4883
+ tracer,
4884
+ {
4885
+ operation: "query",
4886
+ endpoint: "/gateway/query",
4887
+ sql: normalizedQuery,
4888
+ payload,
4889
+ options
4890
+ },
4891
+ async () => {
4892
+ const response = await client.queryGateway(payload, options);
4893
+ return formatGatewayResult(response, { operation: "query" });
4894
+ },
4895
+ callsite
4896
+ );
3527
4897
  };
3528
4898
  }
3529
4899
  function createClientFromConfig(config) {
@@ -3534,9 +4904,10 @@ function createClientFromConfig(config) {
3534
4904
  backend: config.backend,
3535
4905
  headers: config.headers
3536
4906
  });
3537
- const formatGatewayResult = createResultFormatter(config.experimental);
4907
+ const formatGatewayResult = createResultFormatter();
4908
+ const queryTracer = createQueryTracer(config.experimental);
3538
4909
  const auth = createAuthClient(config.auth);
3539
- const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
4910
+ const from = (table) => createTableBuilder(table, gateway, formatGatewayResult, queryTracer, config.experimental);
3540
4911
  const rpc = (fn, args, options) => {
3541
4912
  const normalizedFn = fn.trim();
3542
4913
  if (!normalizedFn) {
@@ -3547,10 +4918,12 @@ function createClientFromConfig(config) {
3547
4918
  args,
3548
4919
  options,
3549
4920
  gateway,
3550
- formatGatewayResult
4921
+ formatGatewayResult,
4922
+ queryTracer,
4923
+ captureTraceCallsite(queryTracer)
3551
4924
  );
3552
4925
  };
3553
- const query = createQueryBuilder(gateway, formatGatewayResult);
4926
+ const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
3554
4927
  const db = createDbModule({ from, rpc, query });
3555
4928
  return {
3556
4929
  from,
@@ -4020,7 +5393,7 @@ var AthenaGatewayCatalogClient = class {
4020
5393
  async queryRows(query) {
4021
5394
  const result = await this.client.query(query);
4022
5395
  if (result.error || result.status < 200 || result.status >= 300) {
4023
- throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
5396
+ throw new Error(result.error?.message ?? `Gateway query failed with status ${result.status}`);
4024
5397
  }
4025
5398
  return result.data ?? [];
4026
5399
  }
@@ -4117,10 +5490,24 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
4117
5490
  }
4118
5491
 
4119
5492
  // src/generator/pipeline.ts
5493
+ function canOverwriteArtifact(file) {
5494
+ return file.kind === "model" || file.kind === "schema";
5495
+ }
5496
+ async function fileExists(path) {
5497
+ try {
5498
+ await promises.stat(path);
5499
+ return true;
5500
+ } catch {
5501
+ return false;
5502
+ }
5503
+ }
4120
5504
  async function writeArtifacts(files, cwd) {
4121
5505
  const writtenFiles = [];
4122
5506
  for (const file of files) {
4123
5507
  const absolutePath = path.resolve(cwd, file.path);
5508
+ if (!canOverwriteArtifact(file) && await fileExists(absolutePath)) {
5509
+ continue;
5510
+ }
4124
5511
  await promises.mkdir(path.dirname(absolutePath), { recursive: true });
4125
5512
  await promises.writeFile(absolutePath, file.content, "utf8");
4126
5513
  writtenFiles.push(file.path);