@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
package/dist/browser.js CHANGED
@@ -86,23 +86,39 @@ function normalizeHeaderValue(value) {
86
86
  function isRecord(value) {
87
87
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
88
88
  }
89
+ function nonEmptyString(value) {
90
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
91
+ }
92
+ function resolveStructuredErrorPayload(payload) {
93
+ if (!isRecord(payload)) return null;
94
+ return isRecord(payload.error) ? payload.error : payload;
95
+ }
89
96
  function resolveRequestId(headers) {
90
97
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
91
98
  }
92
99
  function resolveErrorMessage(payload, fallback) {
93
- if (isRecord(payload)) {
94
- const messageCandidates = [payload.error, payload.message, payload.details];
100
+ const structuredPayload = resolveStructuredErrorPayload(payload);
101
+ if (structuredPayload) {
102
+ const messageCandidates = [structuredPayload.message, structuredPayload.error, structuredPayload.details];
95
103
  for (const candidate of messageCandidates) {
96
- if (typeof candidate === "string" && candidate.trim().length > 0) {
97
- return candidate.trim();
98
- }
104
+ const resolved = nonEmptyString(candidate);
105
+ if (resolved) return resolved;
99
106
  }
100
107
  }
101
- if (typeof payload === "string" && payload.trim().length > 0) {
102
- return payload.trim();
103
- }
108
+ const rawMessage = nonEmptyString(payload);
109
+ if (rawMessage) return rawMessage;
104
110
  return fallback;
105
111
  }
112
+ function resolveErrorHint(payload) {
113
+ const structuredPayload = resolveStructuredErrorPayload(payload);
114
+ return structuredPayload ? nonEmptyString(structuredPayload.hint) : void 0;
115
+ }
116
+ function resolveStatusText(response, payload) {
117
+ const rawStatusText = nonEmptyString(response.statusText);
118
+ if (rawStatusText) return rawStatusText;
119
+ const payloadRecord = isRecord(payload) ? payload : null;
120
+ return payloadRecord ? nonEmptyString(payloadRecord.statusText) ?? null : null;
121
+ }
106
122
  function detailsFromError(error) {
107
123
  return error.toDetails();
108
124
  }
@@ -273,6 +289,7 @@ async function callAthena(config, endpoint, method, payload, options) {
273
289
  return {
274
290
  ok: false,
275
291
  status: response.status,
292
+ statusText: resolveStatusText(response, parsedBody.parsed),
276
293
  data: null,
277
294
  error: invalidJsonError.message,
278
295
  errorDetails: detailsFromError(invalidJsonError),
@@ -291,11 +308,13 @@ async function callAthena(config, endpoint, method, payload, options) {
291
308
  status: response.status,
292
309
  endpoint,
293
310
  method,
294
- requestId
311
+ requestId,
312
+ hint: resolveErrorHint(parsed)
295
313
  });
296
314
  return {
297
315
  ok: false,
298
316
  status: response.status,
317
+ statusText: resolveStatusText(response, parsed),
299
318
  data: null,
300
319
  error: httpError.message,
301
320
  errorDetails: detailsFromError(httpError),
@@ -307,6 +326,7 @@ async function callAthena(config, endpoint, method, payload, options) {
307
326
  return {
308
327
  ok: true,
309
328
  status: response.status,
329
+ statusText: resolveStatusText(response, parsed),
310
330
  data: payloadData ?? null,
311
331
  count: payloadCount,
312
332
  error: void 0,
@@ -326,6 +346,7 @@ async function callAthena(config, endpoint, method, payload, options) {
326
346
  return {
327
347
  ok: false,
328
348
  status: 0,
349
+ statusText: null,
329
350
  data: null,
330
351
  error: networkError.message,
331
352
  errorDetails: detailsFromError(networkError),
@@ -367,10 +388,29 @@ function createAthenaGatewayClient(config = {}) {
367
388
  // src/sql-identifiers.ts
368
389
  var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
369
390
  var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
370
- var ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
391
+ var SQL_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
392
+ var RESPONSE_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_.]*)$/i;
371
393
  function quoteIdentifierSegment(identifier2) {
372
394
  return `"${identifier2.replace(/"/g, '""')}"`;
373
395
  }
396
+ function parseAliasedIdentifierToken(token) {
397
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(token);
398
+ if (responseAliasMatch) {
399
+ const [, aliasIdentifier2, baseIdentifier2] = responseAliasMatch;
400
+ if (COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier2) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier2)) {
401
+ return { baseIdentifier: baseIdentifier2, aliasIdentifier: aliasIdentifier2 };
402
+ }
403
+ }
404
+ const sqlAliasMatch = SQL_ALIAS_PATTERN.exec(token);
405
+ if (!sqlAliasMatch) {
406
+ return null;
407
+ }
408
+ const [, baseIdentifier, aliasIdentifier] = sqlAliasMatch;
409
+ if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
410
+ return null;
411
+ }
412
+ return { baseIdentifier, aliasIdentifier };
413
+ }
374
414
  function quoteQualifiedIdentifier(identifier2) {
375
415
  return identifier2.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
376
416
  }
@@ -379,23 +419,27 @@ function quoteSelectToken(token) {
379
419
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
380
420
  return quoteQualifiedIdentifier(token);
381
421
  }
382
- const aliasMatch = ALIAS_PATTERN.exec(token);
383
- if (!aliasMatch) {
384
- return token;
385
- }
386
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
387
- if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
422
+ const aliasedIdentifier = parseAliasedIdentifierToken(token);
423
+ if (!aliasedIdentifier) {
388
424
  return token;
389
425
  }
426
+ const { baseIdentifier, aliasIdentifier } = aliasedIdentifier;
390
427
  return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
391
428
  }
429
+ function quoteSelectColumnToken(token) {
430
+ const trimmed = token.trim();
431
+ if (!trimmed || trimmed === "*") return trimmed || "*";
432
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(trimmed);
433
+ if (responseAliasMatch) {
434
+ const [, aliasIdentifier, baseIdentifier] = responseAliasMatch;
435
+ return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
436
+ }
437
+ return quoteQualifiedIdentifier(trimmed);
438
+ }
392
439
  function canAutoQuoteToken(token) {
393
440
  if (token === "*") return true;
394
441
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
395
- const aliasMatch = ALIAS_PATTERN.exec(token);
396
- if (!aliasMatch) return false;
397
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
398
- return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
442
+ return parseAliasedIdentifierToken(token) != null;
399
443
  }
400
444
  function splitTopLevelCommaSeparated(input) {
401
445
  const parts = [];
@@ -495,6 +539,231 @@ function identifier(...segments) {
495
539
  return new SqlIdentifierPath(expandedSegments);
496
540
  }
497
541
 
542
+ // src/auth/react-email.ts
543
+ var reactEmailRenderModulePromise;
544
+ function isRecord2(value) {
545
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
546
+ }
547
+ function isFunction(value) {
548
+ return typeof value === "function";
549
+ }
550
+ function toStringOrUndefined(value) {
551
+ if (typeof value !== "string") return void 0;
552
+ return value;
553
+ }
554
+ function nowIsoString() {
555
+ return (/* @__PURE__ */ new Date()).toISOString();
556
+ }
557
+ function emitReactEmailEvent(observe, phase, input = {}) {
558
+ if (!observe) return;
559
+ try {
560
+ observe({
561
+ phase,
562
+ timestamp: nowIsoString(),
563
+ ...input
564
+ });
565
+ } catch {
566
+ }
567
+ }
568
+ function mergeRenderDefaults(input, defaults) {
569
+ return {
570
+ ...input,
571
+ pretty: input.pretty ?? defaults?.pretty,
572
+ includePlainText: input.includePlainText ?? defaults?.includePlainText
573
+ };
574
+ }
575
+ function mergeRuntimeOptions(options) {
576
+ if (!options) return void 0;
577
+ return {
578
+ defaults: options.defaults,
579
+ observe: options.observe,
580
+ route: "route" in options ? options.route : void 0
581
+ };
582
+ }
583
+ async function resolveReactEmailRenderModule() {
584
+ if (!reactEmailRenderModulePromise) {
585
+ reactEmailRenderModulePromise = (async () => {
586
+ try {
587
+ const loaded = await import('@react-email/render');
588
+ if (!isFunction(loaded.render)) {
589
+ throw new Error("missing render(...) export");
590
+ }
591
+ return {
592
+ render: loaded.render,
593
+ toPlainText: isFunction(loaded.toPlainText) ? loaded.toPlainText : void 0,
594
+ pretty: isFunction(loaded.pretty) ? loaded.pretty : void 0
595
+ };
596
+ } catch (error) {
597
+ const message = error instanceof Error ? error.message : String(error);
598
+ throw new Error(
599
+ `React Email rendering requires @react-email/render. Install it in your project (for example: pnpm add @react-email/render). Loader error: ${message}`
600
+ );
601
+ }
602
+ })();
603
+ }
604
+ if (!reactEmailRenderModulePromise) {
605
+ throw new Error("React Email renderer module failed to initialize");
606
+ }
607
+ return reactEmailRenderModulePromise;
608
+ }
609
+ async function resolveReactEmailElement(input) {
610
+ if (input.element != null) {
611
+ return input.element;
612
+ }
613
+ if (!input.component) {
614
+ throw new Error("react email payload requires either `element` or `component`");
615
+ }
616
+ try {
617
+ const reactModule = await import('react');
618
+ if (typeof reactModule.createElement !== "function") {
619
+ throw new Error("react createElement(...) export is unavailable");
620
+ }
621
+ return reactModule.createElement(
622
+ input.component,
623
+ input.props ?? {}
624
+ );
625
+ } catch (error) {
626
+ const message = error instanceof Error ? error.message : String(error);
627
+ throw new Error(
628
+ `React Email component rendering requires react runtime support. Install react in your project. Loader error: ${message}`
629
+ );
630
+ }
631
+ }
632
+ function createAuthReactEmailInput(component, props, overrides = {}) {
633
+ return {
634
+ ...overrides,
635
+ component,
636
+ props
637
+ };
638
+ }
639
+ function defineAuthEmailTemplate(definition) {
640
+ const react = (props, overrides) => createAuthReactEmailInput(definition.component, props, {
641
+ ...definition.defaults,
642
+ ...overrides
643
+ });
644
+ return {
645
+ component: definition.component,
646
+ react,
647
+ toTemplateCreate: (input) => {
648
+ const templateKey = input.templateKey ?? definition.templateKey;
649
+ const subjectTemplate = input.subjectTemplate ?? definition.subjectTemplate;
650
+ if (!templateKey) {
651
+ throw new Error("defineAuthEmailTemplate.toTemplateCreate requires templateKey");
652
+ }
653
+ if (!subjectTemplate) {
654
+ throw new Error("defineAuthEmailTemplate.toTemplateCreate requires subjectTemplate");
655
+ }
656
+ const { props, react: reactOverrides, ...rest } = input;
657
+ return {
658
+ ...rest,
659
+ templateKey,
660
+ subjectTemplate,
661
+ react: react(props, reactOverrides)
662
+ };
663
+ },
664
+ toTemplateUpdate: (input) => {
665
+ const { props, react: reactOverrides, ...rest } = input;
666
+ return {
667
+ ...rest,
668
+ react: react(props, reactOverrides)
669
+ };
670
+ }
671
+ };
672
+ }
673
+ async function renderAthenaReactEmail(input, options) {
674
+ if (!isRecord2(input)) {
675
+ throw new Error("react email payload must be an object");
676
+ }
677
+ const runtimeOptions = mergeRuntimeOptions(options);
678
+ const start = Date.now();
679
+ emitReactEmailEvent(runtimeOptions?.observe, "render:start", {
680
+ route: runtimeOptions?.route,
681
+ message: "Rendering react email payload"
682
+ });
683
+ try {
684
+ const normalizedInput = mergeRenderDefaults(input, runtimeOptions?.defaults);
685
+ const element = await resolveReactEmailElement(normalizedInput);
686
+ const renderModule = await resolveReactEmailRenderModule();
687
+ const htmlValue = await renderModule.render(element);
688
+ const renderedHtml = typeof htmlValue === "string" ? htmlValue : String(htmlValue ?? "");
689
+ if (!renderedHtml.trim()) {
690
+ throw new Error("react email renderer returned an empty HTML string");
691
+ }
692
+ let html = renderedHtml;
693
+ if (normalizedInput.pretty && renderModule.pretty) {
694
+ const prettyValue = await renderModule.pretty(renderedHtml);
695
+ if (typeof prettyValue === "string" && prettyValue.trim().length > 0) {
696
+ html = prettyValue;
697
+ }
698
+ }
699
+ const explicitText = toStringOrUndefined(normalizedInput.text);
700
+ if (explicitText !== void 0) {
701
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
702
+ route: runtimeOptions?.route,
703
+ durationMs: Date.now() - start,
704
+ message: "Rendered react email with explicit text"
705
+ });
706
+ return {
707
+ html,
708
+ text: explicitText
709
+ };
710
+ }
711
+ if (normalizedInput.includePlainText === false || !renderModule.toPlainText) {
712
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
713
+ route: runtimeOptions?.route,
714
+ durationMs: Date.now() - start,
715
+ message: "Rendered react email without plain-text derivation"
716
+ });
717
+ return { html };
718
+ }
719
+ const plainTextValue = await renderModule.toPlainText(html);
720
+ const plainText = toStringOrUndefined(plainTextValue);
721
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
722
+ route: runtimeOptions?.route,
723
+ durationMs: Date.now() - start,
724
+ message: plainText ? "Rendered react email with derived plain text" : "Rendered react email HTML only"
725
+ });
726
+ if (plainText === void 0) {
727
+ return { html };
728
+ }
729
+ return {
730
+ html,
731
+ text: plainText
732
+ };
733
+ } catch (error) {
734
+ const message = error instanceof Error ? error.message : String(error);
735
+ emitReactEmailEvent(runtimeOptions?.observe, "render:error", {
736
+ route: runtimeOptions?.route,
737
+ durationMs: Date.now() - start,
738
+ error: message,
739
+ message: "Failed to render react email payload"
740
+ });
741
+ throw error;
742
+ }
743
+ }
744
+ async function resolveReactEmailPayloadFields(input, fields, options) {
745
+ const { react, ...payloadWithoutReact } = input;
746
+ if (!react) {
747
+ return payloadWithoutReact;
748
+ }
749
+ const rendered = await renderAthenaReactEmail(react, options);
750
+ const payload = {
751
+ ...payloadWithoutReact
752
+ };
753
+ payload[fields.htmlField] = rendered.html;
754
+ const currentTextValue = payload[fields.textField];
755
+ if (rendered.text !== void 0 && (currentTextValue === void 0 || currentTextValue === null || currentTextValue === "")) {
756
+ payload[fields.textField] = rendered.text;
757
+ }
758
+ if (fields.variablesField && (payload[fields.variablesField] === void 0 || payload[fields.variablesField] === null) && isRecord2(react.props)) {
759
+ const derivedVariables = Object.keys(react.props);
760
+ if (derivedVariables.length > 0) {
761
+ payload[fields.variablesField] = derivedVariables;
762
+ }
763
+ }
764
+ return payload;
765
+ }
766
+
498
767
  // src/auth/client.ts
499
768
  var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
500
769
  var FALLBACK_SDK_VERSION2 = "1.0.0";
@@ -504,7 +773,7 @@ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
504
773
  function normalizeBaseUrl(baseUrl) {
505
774
  return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
506
775
  }
507
- function isRecord2(value) {
776
+ function isRecord3(value) {
508
777
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
509
778
  }
510
779
  function normalizeHeaderValue2(value) {
@@ -529,7 +798,7 @@ function resolveRequestId2(headers) {
529
798
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
530
799
  }
531
800
  function resolveErrorMessage2(payload, fallback) {
532
- if (isRecord2(payload)) {
801
+ if (isRecord3(payload)) {
533
802
  const messageCandidates = [payload.error, payload.message, payload.details];
534
803
  for (const candidate of messageCandidates) {
535
804
  if (typeof candidate === "string" && candidate.trim().length > 0) {
@@ -855,6 +1124,19 @@ function createAuthClient(config = {}) {
855
1124
  options
856
1125
  );
857
1126
  };
1127
+ const withReactEmailRoute = (route) => ({
1128
+ ...resolvedConfig.reactEmail,
1129
+ route
1130
+ });
1131
+ const resolveAdminEmailPayload = (route, input) => resolveReactEmailPayloadFields(input, {
1132
+ htmlField: "htmlBody",
1133
+ textField: "textBody"
1134
+ }, withReactEmailRoute(route));
1135
+ const resolveAdminEmailTemplatePayload = (route, input) => resolveReactEmailPayloadFields(input, {
1136
+ htmlField: "htmlTemplate",
1137
+ textField: "textTemplate",
1138
+ variablesField: "variables"
1139
+ }, withReactEmailRoute(route));
858
1140
  const listUserEmailsWithFallback = async (input, options) => {
859
1141
  const primary = await getWithQuery(
860
1142
  "/email/list",
@@ -882,7 +1164,7 @@ function createAuthClient(config = {}) {
882
1164
  data: null
883
1165
  };
884
1166
  }
885
- const fallbackStatus = isRecord2(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
1167
+ const fallbackStatus = isRecord3(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
886
1168
  return {
887
1169
  ...fallback,
888
1170
  data: {
@@ -1318,8 +1600,16 @@ function createAuthClient(config = {}) {
1318
1600
  email: {
1319
1601
  list: (input, options) => getWithQuery("/admin/email/list", input, options),
1320
1602
  get: (input, options) => getWithQuery("/admin/email/get", input, options),
1321
- create: (input, options) => postGeneric("/admin/email/create", input, options),
1322
- update: (input, options) => postGeneric("/admin/email/update", input, options),
1603
+ create: async (input, options) => postGeneric(
1604
+ "/admin/email/create",
1605
+ await resolveAdminEmailPayload("/admin/email/create", input),
1606
+ options
1607
+ ),
1608
+ update: async (input, options) => postGeneric(
1609
+ "/admin/email/update",
1610
+ await resolveAdminEmailPayload("/admin/email/update", input),
1611
+ options
1612
+ ),
1323
1613
  delete: (input, options) => postGeneric("/admin/email/delete", input, options),
1324
1614
  failure: {
1325
1615
  list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
@@ -1331,17 +1621,33 @@ function createAuthClient(config = {}) {
1331
1621
  template: {
1332
1622
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
1333
1623
  get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
1334
- create: (input, options) => postGeneric("/admin/email-template/create", input, options),
1335
- update: (input, options) => postGeneric("/admin/email-template/update", input, options),
1624
+ create: async (input, options) => postGeneric(
1625
+ "/admin/email-template/create",
1626
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
1627
+ options
1628
+ ),
1629
+ update: async (input, options) => postGeneric(
1630
+ "/admin/email-template/update",
1631
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
1632
+ options
1633
+ ),
1336
1634
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
1337
1635
  }
1338
1636
  },
1339
1637
  emailTemplate: {
1340
1638
  get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
1341
- create: (input, options) => postGeneric("/admin/email-template/create", input, options),
1639
+ create: async (input, options) => postGeneric(
1640
+ "/admin/email-template/create",
1641
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
1642
+ options
1643
+ ),
1342
1644
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
1343
1645
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
1344
- update: (input, options) => postGeneric("/admin/email-template/update", input, options)
1646
+ update: async (input, options) => postGeneric(
1647
+ "/admin/email-template/update",
1648
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
1649
+ options
1650
+ )
1345
1651
  }
1346
1652
  },
1347
1653
  apiKey: {
@@ -1533,6 +1839,19 @@ function createAuthClient(config = {}) {
1533
1839
  };
1534
1840
  }
1535
1841
 
1842
+ // src/utils/parse-boolean-flag.ts
1843
+ function parseBooleanFlag(rawValue, fallback) {
1844
+ if (!rawValue) return fallback;
1845
+ const normalized = rawValue.trim().toLowerCase();
1846
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
1847
+ return true;
1848
+ }
1849
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
1850
+ return false;
1851
+ }
1852
+ return fallback;
1853
+ }
1854
+
1536
1855
  // src/auxiliaries.ts
1537
1856
  var AthenaErrorKind = {
1538
1857
  UniqueViolation: "unique_violation",
@@ -1562,16 +1881,8 @@ var AthenaErrorCategory = {
1562
1881
  Database: "database",
1563
1882
  Unknown: "unknown"
1564
1883
  };
1565
- function parseBooleanFlag(rawValue, fallback) {
1566
- if (!rawValue) return fallback;
1567
- const normalized = rawValue.trim().toLowerCase();
1568
- if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
1569
- return true;
1570
- }
1571
- if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
1572
- return false;
1573
- }
1574
- return fallback;
1884
+ function parseBooleanFlag2(rawValue, fallback) {
1885
+ return parseBooleanFlag(rawValue, fallback);
1575
1886
  }
1576
1887
  var AthenaError = class extends Error {
1577
1888
  code;
@@ -1595,9 +1906,38 @@ var AthenaError = class extends Error {
1595
1906
  this.raw = input.raw;
1596
1907
  }
1597
1908
  };
1598
- function isRecord3(value) {
1909
+ function isRecord4(value) {
1599
1910
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1600
1911
  }
1912
+ function firstNonEmptyString(...values) {
1913
+ for (const value of values) {
1914
+ if (typeof value === "string" && value.trim().length > 0) {
1915
+ return value.trim();
1916
+ }
1917
+ }
1918
+ return void 0;
1919
+ }
1920
+ function messageFromUnknownError(error) {
1921
+ if (typeof error === "string" && error.trim().length > 0) {
1922
+ return error.trim();
1923
+ }
1924
+ if (error instanceof Error && error.message.trim().length > 0) {
1925
+ return error.message.trim();
1926
+ }
1927
+ if (!isRecord4(error)) {
1928
+ return void 0;
1929
+ }
1930
+ return firstNonEmptyString(error.message, error.error, error.details);
1931
+ }
1932
+ function gatewayCodeFromUnknownError(error) {
1933
+ if (!isRecord4(error) || typeof error.gatewayCode !== "string") {
1934
+ return void 0;
1935
+ }
1936
+ return error.gatewayCode;
1937
+ }
1938
+ function isAthenaResultErrorLike(value) {
1939
+ return isRecord4(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");
1940
+ }
1601
1941
  function isAthenaErrorKind(value) {
1602
1942
  return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
1603
1943
  }
@@ -1608,7 +1948,7 @@ function isAthenaErrorCategory(value) {
1608
1948
  return value === "transport" || value === "client" || value === "server" || value === "database" || value === "unknown";
1609
1949
  }
1610
1950
  function isNormalizedAthenaError(value) {
1611
- return isRecord3(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
1951
+ return isRecord4(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
1612
1952
  }
1613
1953
  function withContextOverrides(normalized, context) {
1614
1954
  if (!context?.table && !context?.operation) {
@@ -1621,7 +1961,7 @@ function withContextOverrides(normalized, context) {
1621
1961
  };
1622
1962
  }
1623
1963
  function resolveAttachedNormalizedError(resultOrError) {
1624
- if (!isRecord3(resultOrError)) return void 0;
1964
+ if (!isRecord4(resultOrError)) return void 0;
1625
1965
  if (!("__athenaNormalizedError" in resultOrError)) return void 0;
1626
1966
  const candidate = resultOrError.__athenaNormalizedError;
1627
1967
  return isNormalizedAthenaError(candidate) ? candidate : void 0;
@@ -1640,7 +1980,7 @@ function contextHint(context) {
1640
1980
  return `Identity: ${identity}`;
1641
1981
  }
1642
1982
  function isAthenaResultLike(value) {
1643
- return isRecord3(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
1983
+ return isRecord4(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
1644
1984
  }
1645
1985
  function operationFromDetails(details) {
1646
1986
  if (!details?.endpoint) return void 0;
@@ -1737,15 +2077,16 @@ function toAthenaGatewayError(source, fallbackMessage, context) {
1737
2077
  return source;
1738
2078
  }
1739
2079
  if (isAthenaResultLike(source) && source.errorDetails) {
2080
+ const message2 = messageFromUnknownError(source.error) ?? source.errorDetails.message ?? fallbackMessage;
1740
2081
  return new AthenaGatewayError({
1741
2082
  code: source.errorDetails.code,
1742
- message: source.error ?? source.errorDetails.message,
2083
+ message: message2,
1743
2084
  status: source.status,
1744
2085
  endpoint: source.errorDetails.endpoint,
1745
2086
  method: source.errorDetails.method,
1746
2087
  requestId: source.errorDetails.requestId,
1747
- hint: source.errorDetails.hint,
1748
- cause: source.errorDetails.cause
2088
+ hint: (isRecord4(source.error) ? firstNonEmptyString(source.error.hint) : void 0) ?? source.errorDetails.hint,
2089
+ cause: (isRecord4(source.error) ? firstNonEmptyString(source.error.cause) : void 0) ?? source.errorDetails.cause
1749
2090
  });
1750
2091
  }
1751
2092
  const normalized = normalizeAthenaError(source, context);
@@ -1767,13 +2108,50 @@ function normalizeAthenaError(resultOrError, context) {
1767
2108
  return withContextOverrides(attached, context);
1768
2109
  }
1769
2110
  if (isAthenaResultLike(resultOrError)) {
2111
+ if (isAthenaResultErrorLike(resultOrError.error)) {
2112
+ return {
2113
+ kind: resultOrError.error.kind ?? classifyKind(resultOrError.status, gatewayCodeFromUnknownError(resultOrError.error), resultOrError.error.message),
2114
+ code: resultOrError.error.athenaCode ?? toAthenaErrorCode(
2115
+ resultOrError.error.kind ?? classifyKind(
2116
+ resultOrError.status,
2117
+ gatewayCodeFromUnknownError(resultOrError.error),
2118
+ resultOrError.error.message
2119
+ ),
2120
+ resultOrError.error.status ?? resultOrError.status,
2121
+ gatewayCodeFromUnknownError(resultOrError.error)
2122
+ ),
2123
+ category: resultOrError.error.category ?? toAthenaErrorCategory(
2124
+ resultOrError.error.kind ?? classifyKind(
2125
+ resultOrError.status,
2126
+ gatewayCodeFromUnknownError(resultOrError.error),
2127
+ resultOrError.error.message
2128
+ ),
2129
+ resultOrError.error.status ?? resultOrError.status
2130
+ ),
2131
+ retryable: resultOrError.error.retryable ?? isRetryable(
2132
+ resultOrError.error.kind ?? classifyKind(
2133
+ resultOrError.status,
2134
+ gatewayCodeFromUnknownError(resultOrError.error),
2135
+ resultOrError.error.message
2136
+ ),
2137
+ resultOrError.error.status ?? resultOrError.status
2138
+ ),
2139
+ status: resultOrError.error.status ?? resultOrError.status,
2140
+ constraint: resultOrError.error.constraint,
2141
+ table: context?.table ?? resultOrError.error.table,
2142
+ operation: context?.operation ?? resultOrError.error.operation,
2143
+ message: resultOrError.error.message,
2144
+ raw: resultOrError.error.raw ?? resultOrError.raw
2145
+ };
2146
+ }
1770
2147
  const details = resultOrError.errorDetails;
1771
- const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
2148
+ const message2 = messageFromUnknownError(resultOrError.error) ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
1772
2149
  const operation = context?.operation ?? operationFromDetails(details);
1773
2150
  const table = context?.table ?? extractTable(message2);
1774
2151
  const constraint = extractConstraint(message2);
1775
- const kind2 = classifyKind(resultOrError.status, details?.code, message2);
1776
- const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
2152
+ const gatewayCode = details?.code ?? gatewayCodeFromUnknownError(resultOrError.error);
2153
+ const kind2 = classifyKind(resultOrError.status, gatewayCode, message2);
2154
+ const code = toAthenaErrorCode(kind2, resultOrError.status, gatewayCode);
1777
2155
  const category = toAthenaErrorCategory(kind2, resultOrError.status);
1778
2156
  return {
1779
2157
  kind: kind2,
@@ -1810,7 +2188,7 @@ function normalizeAthenaError(resultOrError, context) {
1810
2188
  };
1811
2189
  }
1812
2190
  if (resultOrError instanceof Error) {
1813
- const maybeStatus = isRecord3(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
2191
+ const maybeStatus = isRecord4(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
1814
2192
  const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
1815
2193
  return {
1816
2194
  kind: kind2,
@@ -2027,17 +2405,282 @@ function createDbModule(input) {
2027
2405
  return db;
2028
2406
  }
2029
2407
 
2408
+ // src/query-ast.ts
2409
+ 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;
2410
+ var FILTER_OPERATORS = /* @__PURE__ */ new Set([
2411
+ "eq",
2412
+ "neq",
2413
+ "gt",
2414
+ "gte",
2415
+ "lt",
2416
+ "lte",
2417
+ "like",
2418
+ "ilike",
2419
+ "is",
2420
+ "in",
2421
+ "contains",
2422
+ "containedBy"
2423
+ ]);
2424
+ var BOOLEAN_SAFE_OPERATORS = /* @__PURE__ */ new Set([
2425
+ "eq",
2426
+ "neq",
2427
+ "gt",
2428
+ "gte",
2429
+ "lt",
2430
+ "lte",
2431
+ "like",
2432
+ "ilike",
2433
+ "is"
2434
+ ]);
2435
+ function isRecord5(value) {
2436
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2437
+ }
2438
+ function isUuidString(value) {
2439
+ return UUID_PATTERN.test(value.trim());
2440
+ }
2441
+ function isUuidIdentifierColumn(column) {
2442
+ return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
2443
+ }
2444
+ function shouldUseUuidTextComparison(column, value) {
2445
+ return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
2446
+ }
2447
+ function isRelationSelectNode(value) {
2448
+ return isRecord5(value) && isRecord5(value.select);
2449
+ }
2450
+ function normalizeIdentifier(value, label) {
2451
+ const normalized = value.trim();
2452
+ if (!normalized) {
2453
+ throw new Error(`${label} must be a non-empty string`);
2454
+ }
2455
+ return normalized;
2456
+ }
2457
+ function stringifyFilterValue(value) {
2458
+ if (Array.isArray(value)) {
2459
+ return value.join(",");
2460
+ }
2461
+ return String(value);
2462
+ }
2463
+ function buildGatewayCondition(operator, column, value) {
2464
+ const condition = { operator };
2465
+ if (column) {
2466
+ condition.column = column;
2467
+ if (operator === "eq") {
2468
+ condition.eq_column = column;
2469
+ }
2470
+ }
2471
+ if (value !== void 0) {
2472
+ condition.value = value;
2473
+ if (operator === "eq") {
2474
+ condition.eq_value = value;
2475
+ }
2476
+ }
2477
+ if (operator === "eq" && column && value !== void 0 && shouldUseUuidTextComparison(column, value)) {
2478
+ condition.column_cast = "text";
2479
+ condition.eq_column_cast = "text";
2480
+ }
2481
+ return condition;
2482
+ }
2483
+ function compileRelationToken(key, node) {
2484
+ const nested = compileSelectShape(node.select);
2485
+ const propertyKey = normalizeIdentifier(key, "select relation key");
2486
+ const relationToken = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
2487
+ const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
2488
+ const prefix = alias ? `${alias}:` : "";
2489
+ return `${prefix}${relationToken}(${nested})`;
2490
+ }
2491
+ function compileSelectShape(select) {
2492
+ if (!isRecord5(select)) {
2493
+ throw new Error("findMany select must be an object");
2494
+ }
2495
+ const tokens = [];
2496
+ for (const [rawKey, rawValue] of Object.entries(select)) {
2497
+ if (rawValue === void 0) {
2498
+ continue;
2499
+ }
2500
+ if (rawValue === true) {
2501
+ tokens.push(normalizeIdentifier(rawKey, "select column"));
2502
+ continue;
2503
+ }
2504
+ if (isRelationSelectNode(rawValue)) {
2505
+ tokens.push(compileRelationToken(rawKey, rawValue));
2506
+ continue;
2507
+ }
2508
+ throw new Error(`Unsupported select node for "${rawKey}"`);
2509
+ }
2510
+ if (tokens.length === 0) {
2511
+ throw new Error("findMany select requires at least one field");
2512
+ }
2513
+ return tokens.join(",");
2514
+ }
2515
+ function compileColumnWhere(column, input) {
2516
+ const normalizedColumn = normalizeIdentifier(column, "where column");
2517
+ if (!isRecord5(input)) {
2518
+ return [buildGatewayCondition("eq", normalizedColumn, input)];
2519
+ }
2520
+ const conditions = [];
2521
+ for (const [rawOperator, rawValue] of Object.entries(input)) {
2522
+ if (rawValue === void 0) {
2523
+ continue;
2524
+ }
2525
+ if (!FILTER_OPERATORS.has(rawOperator)) {
2526
+ throw new Error(`Unsupported where operator "${rawOperator}" on "${normalizedColumn}"`);
2527
+ }
2528
+ if ((rawOperator === "in" || rawOperator === "contains" || rawOperator === "containedBy") && !Array.isArray(rawValue)) {
2529
+ throw new Error(`where.${normalizedColumn}.${rawOperator} requires an array value`);
2530
+ }
2531
+ conditions.push(
2532
+ buildGatewayCondition(
2533
+ rawOperator,
2534
+ normalizedColumn,
2535
+ rawValue
2536
+ )
2537
+ );
2538
+ }
2539
+ if (conditions.length === 0) {
2540
+ throw new Error(`where.${normalizedColumn} requires at least one operator`);
2541
+ }
2542
+ return conditions;
2543
+ }
2544
+ function compileBooleanExpressionTerms(clause, label) {
2545
+ if (!isRecord5(clause)) {
2546
+ throw new Error(`findMany where.${label} clauses must be objects`);
2547
+ }
2548
+ const entries = Object.entries(clause).filter(([, value]) => value !== void 0);
2549
+ if (entries.length !== 1) {
2550
+ throw new Error(`findMany where.${label} clauses must target exactly one column`);
2551
+ }
2552
+ const [rawColumn, rawValue] = entries[0];
2553
+ const column = normalizeIdentifier(rawColumn, `where.${label} column`);
2554
+ if (!isRecord5(rawValue)) {
2555
+ return [`${column}.eq.${stringifyFilterValue(rawValue)}`];
2556
+ }
2557
+ const operatorEntries = Object.entries(rawValue).filter(([, value]) => value !== void 0);
2558
+ if (operatorEntries.length === 0) {
2559
+ throw new Error(`findMany where.${label}.${column} requires at least one operator`);
2560
+ }
2561
+ if (label === "not" && operatorEntries.length > 1) {
2562
+ throw new Error("findMany where.not only supports a single lossless operator expression");
2563
+ }
2564
+ return operatorEntries.map(([rawOperator, rawOperand]) => {
2565
+ if (!BOOLEAN_SAFE_OPERATORS.has(rawOperator)) {
2566
+ throw new Error(`findMany where.${label} only supports lossless scalar operators`);
2567
+ }
2568
+ if (Array.isArray(rawOperand)) {
2569
+ throw new Error(`findMany where.${label} does not support array-valued operators`);
2570
+ }
2571
+ return `${column}.${rawOperator}.${stringifyFilterValue(rawOperand)}`;
2572
+ });
2573
+ }
2574
+ function compileWhere(where) {
2575
+ if (where === void 0) {
2576
+ return void 0;
2577
+ }
2578
+ if (!isRecord5(where)) {
2579
+ throw new Error("findMany where must be an object");
2580
+ }
2581
+ const conditions = [];
2582
+ for (const [rawKey, rawValue] of Object.entries(where)) {
2583
+ if (rawValue === void 0) {
2584
+ continue;
2585
+ }
2586
+ if (rawKey === "or") {
2587
+ if (!Array.isArray(rawValue) || rawValue.length === 0) {
2588
+ throw new Error("findMany where.or must be a non-empty array");
2589
+ }
2590
+ const expressions = rawValue.flatMap(
2591
+ (value) => compileBooleanExpressionTerms(value, "or")
2592
+ );
2593
+ conditions.push(buildGatewayCondition("or", void 0, expressions.join(",")));
2594
+ continue;
2595
+ }
2596
+ if (rawKey === "not") {
2597
+ const expressions = compileBooleanExpressionTerms(rawValue, "not");
2598
+ if (expressions.length !== 1) {
2599
+ throw new Error("findMany where.not must compile to exactly one lossless expression");
2600
+ }
2601
+ conditions.push(buildGatewayCondition("not", void 0, expressions[0]));
2602
+ continue;
2603
+ }
2604
+ conditions.push(...compileColumnWhere(rawKey, rawValue));
2605
+ }
2606
+ return conditions.length > 0 ? conditions : void 0;
2607
+ }
2608
+ function resolveOrderDirection(input) {
2609
+ if (typeof input === "boolean") {
2610
+ return input === false ? "descending" : "ascending";
2611
+ }
2612
+ if (typeof input === "string") {
2613
+ const normalized = input.trim().toLowerCase();
2614
+ if (normalized === "asc" || normalized === "ascending") {
2615
+ return "ascending";
2616
+ }
2617
+ if (normalized === "desc" || normalized === "descending") {
2618
+ return "descending";
2619
+ }
2620
+ throw new Error(`Unsupported orderBy direction "${input}"`);
2621
+ }
2622
+ return input.ascending === false ? "descending" : "ascending";
2623
+ }
2624
+ function compileOrderBy(orderBy) {
2625
+ if (orderBy === void 0) {
2626
+ return void 0;
2627
+ }
2628
+ if (!isRecord5(orderBy)) {
2629
+ throw new Error("findMany orderBy must be an object");
2630
+ }
2631
+ if ("column" in orderBy) {
2632
+ return {
2633
+ field: normalizeIdentifier(String(orderBy.column), "orderBy column"),
2634
+ direction: orderBy.ascending === false ? "descending" : "ascending"
2635
+ };
2636
+ }
2637
+ const entries = Object.entries(orderBy).filter(([, value]) => value !== void 0);
2638
+ if (entries.length === 0) {
2639
+ return void 0;
2640
+ }
2641
+ if (entries.length > 1) {
2642
+ throw new Error("findMany orderBy only supports a single column in v1");
2643
+ }
2644
+ const [column, input] = entries[0];
2645
+ return {
2646
+ field: normalizeIdentifier(column, "orderBy column"),
2647
+ direction: resolveOrderDirection(input)
2648
+ };
2649
+ }
2650
+
2030
2651
  // src/client.ts
2031
2652
  var DEFAULT_COLUMNS = "*";
2032
- 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;
2033
2653
  var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
2034
2654
  var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
2655
+ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
2656
+ "src\\client.ts",
2657
+ "src/client.ts",
2658
+ "dist\\client.",
2659
+ "dist/client.",
2660
+ "node_modules\\@xylex-group\\athena",
2661
+ "node_modules/@xylex-group/athena",
2662
+ "node:internal",
2663
+ "internal/process"
2664
+ ];
2665
+ function canUseFindManyAstTransport(state) {
2666
+ return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
2667
+ }
2668
+ function toFindManyAstOrder(order) {
2669
+ if (!order) {
2670
+ return void 0;
2671
+ }
2672
+ return {
2673
+ column: order.field,
2674
+ ascending: order.direction !== "descending"
2675
+ };
2676
+ }
2035
2677
  function formatResult(response) {
2036
2678
  const result = {
2037
2679
  data: response.data ?? null,
2038
- error: response.error ?? null,
2680
+ error: null,
2039
2681
  errorDetails: response.errorDetails ?? null,
2040
2682
  status: response.status,
2683
+ statusText: response.statusText ?? null,
2041
2684
  raw: response.raw
2042
2685
  };
2043
2686
  if (response.count !== void 0) {
@@ -2054,22 +2697,239 @@ function attachNormalizedError(result, normalizedError) {
2054
2697
  });
2055
2698
  }
2056
2699
  function createResultFormatter(experimental) {
2057
- if (!experimental?.enableErrorNormalization) {
2058
- return formatResult;
2059
- }
2060
2700
  return (response, context) => {
2061
2701
  const result = formatResult(response);
2062
- if (result.error == null) {
2702
+ if (response.error == null && response.errorDetails == null) {
2063
2703
  return result;
2064
2704
  }
2065
- const normalizedError = normalizeAthenaError(result, context);
2705
+ const normalizedError = normalizeAthenaError(
2706
+ {
2707
+ ...result,
2708
+ error: response.error ?? response.errorDetails?.message ?? null
2709
+ },
2710
+ context
2711
+ );
2712
+ result.error = createResultError(response, result, normalizedError);
2066
2713
  attachNormalizedError(result, normalizedError);
2067
2714
  return result;
2068
2715
  };
2069
2716
  }
2070
- function toSingleResult(response) {
2071
- const payload = response.data;
2072
- const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
2717
+ function isRecord6(value) {
2718
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2719
+ }
2720
+ function firstNonEmptyString2(...values) {
2721
+ for (const value of values) {
2722
+ if (typeof value === "string" && value.trim().length > 0) {
2723
+ return value.trim();
2724
+ }
2725
+ }
2726
+ return void 0;
2727
+ }
2728
+ function resolveStructuredErrorPayload2(raw) {
2729
+ if (!isRecord6(raw)) return null;
2730
+ return isRecord6(raw.error) ? raw.error : raw;
2731
+ }
2732
+ function resolveStructuredErrorDetails(payload, message) {
2733
+ if (!payload || !("details" in payload)) {
2734
+ return null;
2735
+ }
2736
+ const details = payload.details;
2737
+ if (details == null) {
2738
+ return null;
2739
+ }
2740
+ if (typeof details === "string" && details.trim() === message.trim()) {
2741
+ return null;
2742
+ }
2743
+ return details;
2744
+ }
2745
+ function createResultError(response, result, normalized) {
2746
+ const rawRecord = isRecord6(response.raw) ? response.raw : null;
2747
+ const payload = resolveStructuredErrorPayload2(response.raw);
2748
+ const message = firstNonEmptyString2(
2749
+ response.error,
2750
+ payload?.message,
2751
+ payload?.error,
2752
+ payload?.details,
2753
+ response.errorDetails?.message,
2754
+ normalized.message
2755
+ ) ?? normalized.message;
2756
+ const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
2757
+ const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
2758
+ const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
2759
+ const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
2760
+ return {
2761
+ message,
2762
+ code,
2763
+ athenaCode: normalized.code,
2764
+ gatewayCode: response.errorDetails?.code ?? null,
2765
+ kind: normalized.kind,
2766
+ category: normalized.category,
2767
+ retryable: normalized.retryable,
2768
+ details,
2769
+ hint,
2770
+ status: result.status,
2771
+ statusText,
2772
+ constraint: normalized.constraint,
2773
+ table: normalized.table,
2774
+ operation: normalized.operation,
2775
+ endpoint: response.errorDetails?.endpoint,
2776
+ method: response.errorDetails?.method,
2777
+ requestId: response.errorDetails?.requestId,
2778
+ cause: response.errorDetails?.cause,
2779
+ raw: result.raw
2780
+ };
2781
+ }
2782
+ function parseQueryTraceCallsiteFrame(frame) {
2783
+ const trimmed = frame.trim();
2784
+ if (!trimmed) {
2785
+ return null;
2786
+ }
2787
+ let body = trimmed.replace(/^at\s+/, "");
2788
+ if (body.startsWith("async ")) {
2789
+ body = body.slice(6);
2790
+ }
2791
+ let functionName;
2792
+ let location = body;
2793
+ const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
2794
+ if (wrappedMatch) {
2795
+ functionName = wrappedMatch[1].trim() || void 0;
2796
+ location = wrappedMatch[2].trim();
2797
+ }
2798
+ const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
2799
+ if (!locationMatch) {
2800
+ return null;
2801
+ }
2802
+ const filePath = locationMatch[1].replace(/^file:\/\//, "");
2803
+ const line = Number(locationMatch[2]);
2804
+ const column = Number(locationMatch[3]);
2805
+ if (!Number.isFinite(line) || !Number.isFinite(column)) {
2806
+ return null;
2807
+ }
2808
+ const normalizedPath = filePath.replace(/\\/g, "/");
2809
+ const fileName = normalizedPath.split("/").at(-1) ?? filePath;
2810
+ return {
2811
+ filePath,
2812
+ fileName,
2813
+ line,
2814
+ column,
2815
+ frame: trimmed,
2816
+ functionName
2817
+ };
2818
+ }
2819
+ function captureQueryTraceCallsite() {
2820
+ const stack = new Error().stack;
2821
+ if (!stack) return null;
2822
+ const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
2823
+ for (const frame of frames) {
2824
+ if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
2825
+ continue;
2826
+ }
2827
+ const callsite = parseQueryTraceCallsiteFrame(frame);
2828
+ if (callsite) return callsite;
2829
+ }
2830
+ const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
2831
+ return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
2832
+ }
2833
+ function defaultQueryTraceLogger(event) {
2834
+ const target = event.table ?? event.functionName ?? "gateway";
2835
+ const outcomeState = event.outcome?.error ? "error" : "ok";
2836
+ const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
2837
+ console.info(banner, event);
2838
+ }
2839
+ function captureTraceCallsite(tracer) {
2840
+ return tracer?.captureCallsite() ?? null;
2841
+ }
2842
+ function createTraceCallsiteStore(tracer, initialCallsite) {
2843
+ let storedCallsite = initialCallsite ?? void 0;
2844
+ return {
2845
+ resolve(callsite) {
2846
+ if (callsite) {
2847
+ storedCallsite = callsite;
2848
+ return callsite;
2849
+ }
2850
+ if (storedCallsite !== void 0) {
2851
+ return storedCallsite;
2852
+ }
2853
+ const capturedCallsite = captureTraceCallsite(tracer);
2854
+ if (capturedCallsite) {
2855
+ storedCallsite = capturedCallsite;
2856
+ }
2857
+ return capturedCallsite;
2858
+ }
2859
+ };
2860
+ }
2861
+ function createQueryTracer(experimental) {
2862
+ const traceOption = experimental?.traceQueries;
2863
+ if (!traceOption) {
2864
+ return void 0;
2865
+ }
2866
+ const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
2867
+ const emit = (event) => {
2868
+ try {
2869
+ logger(event);
2870
+ } catch (error) {
2871
+ console.warn("[athena-js][trace] logger failed", error);
2872
+ }
2873
+ };
2874
+ return {
2875
+ captureCallsite: captureQueryTraceCallsite,
2876
+ publishSuccess(context, result, durationMs, callsite) {
2877
+ emit({
2878
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2879
+ durationMs,
2880
+ operation: context.operation,
2881
+ endpoint: context.endpoint,
2882
+ table: context.table,
2883
+ functionName: context.functionName,
2884
+ sql: context.sql,
2885
+ payload: context.payload,
2886
+ options: context.options,
2887
+ callsite,
2888
+ outcome: {
2889
+ status: result.status,
2890
+ error: result.error,
2891
+ errorDetails: result.errorDetails ?? null,
2892
+ count: result.count ?? null,
2893
+ data: result.data,
2894
+ raw: result.raw
2895
+ }
2896
+ });
2897
+ },
2898
+ publishFailure(context, error, durationMs, callsite) {
2899
+ emit({
2900
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2901
+ durationMs,
2902
+ operation: context.operation,
2903
+ endpoint: context.endpoint,
2904
+ table: context.table,
2905
+ functionName: context.functionName,
2906
+ sql: context.sql,
2907
+ payload: context.payload,
2908
+ options: context.options,
2909
+ callsite,
2910
+ thrownError: error
2911
+ });
2912
+ }
2913
+ };
2914
+ }
2915
+ async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
2916
+ if (!tracer) {
2917
+ return runner();
2918
+ }
2919
+ const callsite = callsiteOverride ?? tracer.captureCallsite();
2920
+ const startedAt = Date.now();
2921
+ try {
2922
+ const result = await runner();
2923
+ tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
2924
+ return result;
2925
+ } catch (error) {
2926
+ tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
2927
+ throw error;
2928
+ }
2929
+ }
2930
+ function toSingleResult(response) {
2931
+ const payload = response.data;
2932
+ const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
2073
2933
  return {
2074
2934
  ...response,
2075
2935
  data: singleData
@@ -2087,15 +2947,16 @@ function asAthenaJsonObject(value) {
2087
2947
  function asAthenaJsonObjectArray(values) {
2088
2948
  return values;
2089
2949
  }
2090
- function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2950
+ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
2091
2951
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
2092
2952
  let selectedOptions;
2093
2953
  let promise = null;
2094
- const run = (columns, options) => {
2954
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
2955
+ const run = (columns, options, callsite) => {
2095
2956
  const payloadColumns = columns ?? selectedColumns;
2096
2957
  const payloadOptions = options ?? selectedOptions;
2097
2958
  if (!promise) {
2098
- promise = executor(payloadColumns, payloadOptions);
2959
+ promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
2099
2960
  }
2100
2961
  return promise;
2101
2962
  };
@@ -2103,7 +2964,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2103
2964
  select(columns = selectedColumns, options) {
2104
2965
  selectedColumns = columns;
2105
2966
  selectedOptions = options ?? selectedOptions;
2106
- return run(columns, options);
2967
+ return run(columns, options, captureTraceCallsite(tracer));
2107
2968
  },
2108
2969
  returning(columns = selectedColumns, options) {
2109
2970
  return mutationQuery.select(columns, options);
@@ -2111,7 +2972,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2111
2972
  single(columns = selectedColumns, options) {
2112
2973
  selectedColumns = columns;
2113
2974
  selectedOptions = options ?? selectedOptions;
2114
- return run(columns, options).then(toSingleResult);
2975
+ return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
2115
2976
  },
2116
2977
  maybeSingle(columns = selectedColumns, options) {
2117
2978
  return mutationQuery.single(columns, options);
@@ -2134,21 +2995,12 @@ function getResourceId(state) {
2134
2995
  );
2135
2996
  return candidate?.value?.toString();
2136
2997
  }
2137
- function stringifyFilterValue(value) {
2998
+ function stringifyFilterValue2(value) {
2138
2999
  if (Array.isArray(value)) {
2139
3000
  return value.join(",");
2140
3001
  }
2141
3002
  return String(value);
2142
3003
  }
2143
- function isUuidString(value) {
2144
- return UUID_PATTERN.test(value.trim());
2145
- }
2146
- function isUuidIdentifierColumn(column) {
2147
- return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
2148
- }
2149
- function shouldUseUuidTextComparison(column, value) {
2150
- return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
2151
- }
2152
3004
  function normalizeCast(cast) {
2153
3005
  const normalized = cast.trim().toLowerCase();
2154
3006
  if (!SAFE_CAST_PATTERN.test(normalized)) {
@@ -2171,25 +3023,92 @@ function withCast(expression, cast) {
2171
3023
  }
2172
3024
  function buildSelectColumnsClause(columns) {
2173
3025
  if (Array.isArray(columns)) {
2174
- return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
3026
+ return columns.map((column) => quoteSelectColumnToken(column)).join(", ");
2175
3027
  }
2176
3028
  return quoteSelectColumnsExpression(columns);
2177
3029
  }
3030
+ function parseIdentifierSegment(input) {
3031
+ const trimmed = input.trim();
3032
+ if (!trimmed) return null;
3033
+ if (!trimmed.startsWith('"')) {
3034
+ return {
3035
+ normalizedValue: trimmed.toLowerCase()
3036
+ };
3037
+ }
3038
+ let value = "";
3039
+ let index = 1;
3040
+ let closed = false;
3041
+ while (index < trimmed.length) {
3042
+ const char = trimmed[index];
3043
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
3044
+ if (char === '"' && next === '"') {
3045
+ value += '"';
3046
+ index += 2;
3047
+ continue;
3048
+ }
3049
+ if (char === '"') {
3050
+ closed = true;
3051
+ index += 1;
3052
+ break;
3053
+ }
3054
+ value += char;
3055
+ index += 1;
3056
+ }
3057
+ if (!closed || trimmed.slice(index).trim().length > 0 || !value.trim()) {
3058
+ return null;
3059
+ }
3060
+ return {
3061
+ normalizedValue: value
3062
+ };
3063
+ }
3064
+ function splitQualifiedTableName(tableName) {
3065
+ const trimmed = tableName.trim();
3066
+ let inQuotes = false;
3067
+ for (let index = 0; index < trimmed.length; index += 1) {
3068
+ const char = trimmed[index];
3069
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
3070
+ if (char === '"') {
3071
+ if (inQuotes && next === '"') {
3072
+ index += 1;
3073
+ continue;
3074
+ }
3075
+ inQuotes = !inQuotes;
3076
+ continue;
3077
+ }
3078
+ if (char === "." && !inQuotes) {
3079
+ const schemaSegment = trimmed.slice(0, index).trim();
3080
+ const tableSegment = trimmed.slice(index + 1).trim();
3081
+ if (!schemaSegment || !tableSegment) {
3082
+ return null;
3083
+ }
3084
+ return { schemaSegment };
3085
+ }
3086
+ }
3087
+ return null;
3088
+ }
2178
3089
  function resolveTableNameForCall(tableName, schema) {
2179
3090
  if (!schema) return tableName;
2180
3091
  const normalizedSchema = schema.trim();
2181
3092
  if (!normalizedSchema) {
2182
3093
  throw new Error("schema option must be a non-empty string");
2183
3094
  }
2184
- if (tableName.includes(".")) {
2185
- if (tableName.startsWith(`${normalizedSchema}.`)) {
2186
- return tableName;
3095
+ const normalizedTableName = tableName.trim();
3096
+ const parsedSchema = parseIdentifierSegment(normalizedSchema);
3097
+ if (!parsedSchema) {
3098
+ throw new Error("schema option must be a non-empty string");
3099
+ }
3100
+ const qualified = splitQualifiedTableName(normalizedTableName);
3101
+ if (qualified) {
3102
+ const parsedTableSchema = parseIdentifierSegment(qualified.schemaSegment);
3103
+ const sameSchema = parsedTableSchema ? parsedTableSchema.normalizedValue === parsedSchema.normalizedValue : normalizedTableName.startsWith(`${normalizedSchema}.`);
3104
+ if (sameSchema) {
3105
+ return normalizedTableName;
2187
3106
  }
2188
3107
  throw new Error(
2189
- `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
3108
+ `schema option "${normalizedSchema}" conflicts with schema-qualified table "${normalizedTableName}"`
2190
3109
  );
2191
3110
  }
2192
- return `${normalizedSchema}.${tableName}`;
3111
+ return `${normalizedSchema}.${normalizedTableName}`;
2193
3112
  }
2194
3113
  function conditionToSqlClause(condition) {
2195
3114
  if (!condition.column) return null;
@@ -2267,6 +3186,237 @@ function buildTypedSelectQuery(input) {
2267
3186
  }
2268
3187
  return `${sqlParts.join(" ")};`;
2269
3188
  }
3189
+ function sanitizeSqlComment(comment) {
3190
+ return comment.replace(/\*\//g, "* /");
3191
+ }
3192
+ function toSqlJsonLiteral(value) {
3193
+ if (value === void 0) return "DEFAULT";
3194
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3195
+ return toSqlLiteral(value);
3196
+ }
3197
+ return `'${escapeSqlStringLiteral(JSON.stringify(value))}'::jsonb`;
3198
+ }
3199
+ function conditionToDebugSqlClause(condition) {
3200
+ const exact = conditionToSqlClause(condition);
3201
+ if (exact) return exact;
3202
+ const rawCondition = sanitizeSqlComment(JSON.stringify(condition));
3203
+ if (!condition.column) {
3204
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
3205
+ }
3206
+ const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
3207
+ const value = condition.value;
3208
+ const rhs = withCast(toSqlJsonLiteral(value), condition.value_cast);
3209
+ switch (condition.operator) {
3210
+ case "contains":
3211
+ return `${column} @> ${rhs}`;
3212
+ case "containedBy":
3213
+ return `${column} <@ ${rhs}`;
3214
+ case "not":
3215
+ return `TRUE /* NOT expression passthrough: ${rawCondition} */`;
3216
+ case "or":
3217
+ return `TRUE /* OR expression passthrough: ${rawCondition} */`;
3218
+ default:
3219
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
3220
+ }
3221
+ }
3222
+ function resolvePagination(input) {
3223
+ let limit = input.limit;
3224
+ let offset = input.offset;
3225
+ if (limit === void 0 && input.pageSize !== void 0) {
3226
+ limit = input.pageSize;
3227
+ }
3228
+ if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
3229
+ offset = (input.currentPage - 1) * input.pageSize;
3230
+ }
3231
+ return { limit, offset };
3232
+ }
3233
+ function appendOrderLimitOffset(sqlParts, order, limit, offset) {
3234
+ if (order?.field) {
3235
+ const direction = order.direction === "descending" ? "DESC" : "ASC";
3236
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(order.field)} ${direction}`);
3237
+ }
3238
+ if (limit !== void 0) {
3239
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
3240
+ }
3241
+ if (offset !== void 0) {
3242
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
3243
+ }
3244
+ }
3245
+ function buildDebugSelectQuery(input) {
3246
+ const sqlParts = [
3247
+ `SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
3248
+ ];
3249
+ if (input.conditions?.length) {
3250
+ const whereClauses = input.conditions.map(conditionToDebugSqlClause);
3251
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
3252
+ }
3253
+ const pagination = resolvePagination(input);
3254
+ appendOrderLimitOffset(sqlParts, input.order, pagination.limit, pagination.offset);
3255
+ return `${sqlParts.join(" ")};`;
3256
+ }
3257
+ function resolveDebugTableIdentifier(tableName) {
3258
+ if (!tableName?.trim()) {
3259
+ return '"__unknown_table__"';
3260
+ }
3261
+ return quoteQualifiedIdentifier(tableName);
3262
+ }
3263
+ function buildInsertDebugSql(payload) {
3264
+ const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
3265
+ const columns = [];
3266
+ const seen = /* @__PURE__ */ new Set();
3267
+ for (const row of rows) {
3268
+ for (const column of Object.keys(row)) {
3269
+ if (seen.has(column)) continue;
3270
+ seen.add(column);
3271
+ columns.push(column);
3272
+ }
3273
+ }
3274
+ const sqlParts = [`INSERT INTO ${quoteQualifiedIdentifier(payload.table_name)}`];
3275
+ if (!rows.length || !columns.length) {
3276
+ sqlParts.push("DEFAULT VALUES");
3277
+ if (rows.length > 1) {
3278
+ sqlParts.push(`/* trace: ${rows.length} rows collapsed to DEFAULT VALUES */`);
3279
+ }
3280
+ } else {
3281
+ const valuesClause = rows.map((row) => {
3282
+ const values = columns.map((column) => {
3283
+ const hasColumn = Object.prototype.hasOwnProperty.call(row, column);
3284
+ if (!hasColumn) {
3285
+ return payload.default_to_null ? "NULL" : "DEFAULT";
3286
+ }
3287
+ const rowValue = row[column];
3288
+ return toSqlJsonLiteral(rowValue);
3289
+ });
3290
+ return `(${values.join(", ")})`;
3291
+ }).join(", ");
3292
+ const columnClause = columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
3293
+ sqlParts.push(`(${columnClause})`);
3294
+ sqlParts.push(`VALUES ${valuesClause}`);
3295
+ }
3296
+ if (payload.on_conflict) {
3297
+ const conflictColumns = Array.isArray(payload.on_conflict) ? payload.on_conflict.map((column) => quoteQualifiedIdentifier(column)).join(", ") : payload.on_conflict;
3298
+ if (payload.update_body && Object.keys(payload.update_body).length > 0) {
3299
+ const assignments = Object.entries(payload.update_body).map(
3300
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
3301
+ );
3302
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO UPDATE SET ${assignments.join(", ")}`);
3303
+ } else {
3304
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO NOTHING`);
3305
+ }
3306
+ }
3307
+ if (payload.columns) {
3308
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
3309
+ }
3310
+ return `${sqlParts.join(" ")};`;
3311
+ }
3312
+ function buildUpdateDebugSql(payload) {
3313
+ const set = payload.set ?? payload.data ?? {};
3314
+ const assignments = Object.entries(set).map(
3315
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
3316
+ );
3317
+ const sqlParts = [
3318
+ `UPDATE ${resolveDebugTableIdentifier(payload.table_name)} SET ${assignments.length ? assignments.join(", ") : "/* empty set */"}`
3319
+ ];
3320
+ if (payload.conditions?.length) {
3321
+ const whereClauses = payload.conditions.map(conditionToDebugSqlClause);
3322
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
3323
+ }
3324
+ const pagination = resolvePagination({
3325
+ currentPage: payload.current_page,
3326
+ pageSize: payload.page_size
3327
+ });
3328
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
3329
+ if (payload.columns) {
3330
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
3331
+ }
3332
+ return `${sqlParts.join(" ")};`;
3333
+ }
3334
+ function buildDeleteDebugSql(payload) {
3335
+ const sqlParts = [`DELETE FROM ${quoteQualifiedIdentifier(payload.table_name)}`];
3336
+ const whereClauses = [];
3337
+ if (payload.resource_id) {
3338
+ whereClauses.push(`"resource_id" = ${toSqlLiteral(payload.resource_id)}`);
3339
+ }
3340
+ if (payload.conditions?.length) {
3341
+ whereClauses.push(...payload.conditions.map(conditionToDebugSqlClause));
3342
+ }
3343
+ if (whereClauses.length) {
3344
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
3345
+ }
3346
+ const pagination = resolvePagination({
3347
+ currentPage: payload.current_page,
3348
+ pageSize: payload.page_size
3349
+ });
3350
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
3351
+ if (payload.columns) {
3352
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
3353
+ }
3354
+ return `${sqlParts.join(" ")};`;
3355
+ }
3356
+ function rpcFilterToSqlClause(filter) {
3357
+ const column = quoteQualifiedIdentifier(filter.column);
3358
+ const value = filter.value;
3359
+ switch (filter.operator) {
3360
+ case "eq":
3361
+ case "neq":
3362
+ case "gt":
3363
+ case "gte":
3364
+ case "lt":
3365
+ case "lte":
3366
+ case "like":
3367
+ case "ilike": {
3368
+ if (value === void 0 || Array.isArray(value)) {
3369
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
3370
+ }
3371
+ const operatorMap = {
3372
+ eq: "=",
3373
+ neq: "!=",
3374
+ gt: ">",
3375
+ gte: ">=",
3376
+ lt: "<",
3377
+ lte: "<=",
3378
+ like: "LIKE",
3379
+ ilike: "ILIKE"
3380
+ };
3381
+ return `${column} ${operatorMap[filter.operator]} ${toSqlLiteral(value)}`;
3382
+ }
3383
+ case "is":
3384
+ if (value === null) return `${column} IS NULL`;
3385
+ if (value === true) return `${column} IS TRUE`;
3386
+ if (value === false) return `${column} IS FALSE`;
3387
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
3388
+ case "in":
3389
+ if (!Array.isArray(value)) {
3390
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
3391
+ }
3392
+ if (value.length === 0) return "FALSE";
3393
+ return `${column} IN (${value.map((item) => toSqlLiteral(item)).join(", ")})`;
3394
+ default:
3395
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
3396
+ }
3397
+ }
3398
+ function buildRpcDebugSql(payload) {
3399
+ const argsEntries = payload.args ? Object.entries(payload.args) : [];
3400
+ const argsClause = argsEntries.map(([key, value]) => `${quoteQualifiedIdentifier(key)} => ${toSqlJsonLiteral(value)}`).join(", ");
3401
+ const functionRef = payload.schema ? `${quoteQualifiedIdentifier(payload.schema)}.${quoteQualifiedIdentifier(payload.function)}` : quoteQualifiedIdentifier(payload.function);
3402
+ const sqlParts = [
3403
+ `SELECT ${payload.select ? quoteSelectColumnsExpression(payload.select) : "*"} FROM ${functionRef}(${argsClause})`
3404
+ ];
3405
+ if (payload.filters?.length) {
3406
+ sqlParts.push(`WHERE ${payload.filters.map(rpcFilterToSqlClause).join(" AND ")}`);
3407
+ }
3408
+ if (payload.order?.column) {
3409
+ const direction = payload.order.ascending === false ? "DESC" : "ASC";
3410
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(payload.order.column)} ${direction}`);
3411
+ }
3412
+ if (payload.limit !== void 0) {
3413
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(payload.limit))}`);
3414
+ }
3415
+ if (payload.offset !== void 0) {
3416
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(payload.offset))}`);
3417
+ }
3418
+ return `${sqlParts.join(" ")};`;
3419
+ }
2270
3420
  function createFilterMethods(state, addCondition, self) {
2271
3421
  return {
2272
3422
  eq(column, value) {
@@ -2378,7 +3528,7 @@ function createFilterMethods(state, addCondition, self) {
2378
3528
  not(columnOrExpression, operator, value) {
2379
3529
  const expression = String(columnOrExpression);
2380
3530
  if (operator != null && value !== void 0) {
2381
- addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
3531
+ addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue2(value)}`);
2382
3532
  } else {
2383
3533
  addCondition("not", void 0, expression);
2384
3534
  }
@@ -2441,14 +3591,15 @@ function createRpcFilterMethods(filters, self) {
2441
3591
  }
2442
3592
  };
2443
3593
  }
2444
- function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
3594
+ function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
2445
3595
  const state = {
2446
3596
  filters: []
2447
3597
  };
2448
3598
  let selectedColumns;
2449
3599
  let selectedOptions;
2450
3600
  let promise = null;
2451
- const executeRpc = async (columns, options) => {
3601
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
3602
+ const executeRpc = async (columns, options, callsite) => {
2452
3603
  const mergedOptions = mergeOptions(baseOptions, options);
2453
3604
  const payload = {
2454
3605
  function: functionName,
@@ -2462,14 +3613,30 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
2462
3613
  offset: state.offset,
2463
3614
  order: state.order
2464
3615
  };
2465
- const response = await client.rpcGateway(payload, mergedOptions);
2466
- return formatGatewayResult(response, { operation: "rpc" });
3616
+ const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
3617
+ const sql = buildRpcDebugSql(payload);
3618
+ return executeWithQueryTrace(
3619
+ tracer,
3620
+ {
3621
+ operation: "rpc",
3622
+ endpoint,
3623
+ functionName,
3624
+ sql,
3625
+ payload,
3626
+ options: mergedOptions
3627
+ },
3628
+ async () => {
3629
+ const response = await client.rpcGateway(payload, mergedOptions);
3630
+ return formatGatewayResult(response, { operation: "rpc" });
3631
+ },
3632
+ callsite
3633
+ );
2467
3634
  };
2468
- const run = (columns, options) => {
3635
+ const run = (columns, options, callsite) => {
2469
3636
  const payloadColumns = columns ?? selectedColumns;
2470
3637
  const payloadOptions = options ?? selectedOptions;
2471
3638
  if (!promise) {
2472
- promise = executeRpc(payloadColumns, payloadOptions);
3639
+ promise = executeRpc(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
2473
3640
  }
2474
3641
  return promise;
2475
3642
  };
@@ -2479,10 +3646,10 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
2479
3646
  select(columns = selectedColumns, options) {
2480
3647
  selectedColumns = columns;
2481
3648
  selectedOptions = options ?? selectedOptions;
2482
- return run(columns, options);
3649
+ return run(columns, options, captureTraceCallsite(tracer));
2483
3650
  },
2484
3651
  async single(columns, options) {
2485
- const result = await run(columns, options);
3652
+ const result = await run(columns, options, captureTraceCallsite(tracer));
2486
3653
  return toSingleResult(result);
2487
3654
  },
2488
3655
  maybeSingle(columns, options) {
@@ -2517,7 +3684,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
2517
3684
  });
2518
3685
  return builder;
2519
3686
  }
2520
- function createTableBuilder(tableName, client, formatGatewayResult) {
3687
+ function createTableBuilder(tableName, client, formatGatewayResult, tracer, experimental) {
2521
3688
  const state = {
2522
3689
  conditions: []
2523
3690
  };
@@ -2549,15 +3716,24 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2549
3716
  }
2550
3717
  state.conditions.push(condition);
2551
3718
  };
3719
+ const snapshotState = () => ({
3720
+ conditions: state.conditions.map((condition) => ({ ...condition })),
3721
+ limit: state.limit,
3722
+ offset: state.offset,
3723
+ order: state.order ? { ...state.order } : void 0,
3724
+ currentPage: state.currentPage,
3725
+ pageSize: state.pageSize,
3726
+ totalPages: state.totalPages
3727
+ });
2552
3728
  const builder = {};
2553
3729
  const filterMethods = createFilterMethods(
2554
3730
  state,
2555
3731
  addCondition,
2556
3732
  builder
2557
3733
  );
2558
- const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
3734
+ const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
2559
3735
  const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
2560
- const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
3736
+ const conditions = executionState.conditions.length ? executionState.conditions.map((condition) => ({ ...condition })) : void 0;
2561
3737
  const hasTypedEqualityComparison = conditions?.some(
2562
3738
  (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
2563
3739
  ) ?? false;
@@ -2566,53 +3742,107 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2566
3742
  tableName: resolvedTableName,
2567
3743
  columns,
2568
3744
  conditions,
2569
- limit: state.limit,
2570
- offset: state.offset,
2571
- currentPage: state.currentPage,
2572
- pageSize: state.pageSize,
2573
- order: state.order
3745
+ limit: executionState.limit,
3746
+ offset: executionState.offset,
3747
+ currentPage: executionState.currentPage,
3748
+ pageSize: executionState.pageSize,
3749
+ order: executionState.order
2574
3750
  });
2575
3751
  if (query) {
2576
- const queryResponse = await client.queryGateway({ query }, options);
2577
- return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
3752
+ const payload2 = { query };
3753
+ return executeWithQueryTrace(
3754
+ tracer,
3755
+ {
3756
+ operation: "select",
3757
+ endpoint: "/gateway/query",
3758
+ table: resolvedTableName,
3759
+ sql: query,
3760
+ payload: payload2,
3761
+ options
3762
+ },
3763
+ async () => {
3764
+ const queryResponse = await client.queryGateway(payload2, options);
3765
+ return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
3766
+ },
3767
+ callsite
3768
+ );
2578
3769
  }
2579
3770
  }
2580
3771
  const payload = {
2581
3772
  table_name: resolvedTableName,
2582
3773
  columns,
2583
3774
  conditions,
2584
- limit: state.limit,
2585
- offset: state.offset,
2586
- current_page: state.currentPage,
2587
- page_size: state.pageSize,
2588
- total_pages: state.totalPages,
2589
- sort_by: state.order,
3775
+ limit: executionState.limit,
3776
+ offset: executionState.offset,
3777
+ current_page: executionState.currentPage,
3778
+ page_size: executionState.pageSize,
3779
+ total_pages: executionState.totalPages,
3780
+ sort_by: executionState.order,
2590
3781
  strip_nulls: options?.stripNulls ?? true,
2591
3782
  count: options?.count,
2592
3783
  head: options?.head
2593
3784
  };
2594
- const response = await client.fetchGateway(payload, options);
2595
- return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3785
+ const sql = buildDebugSelectQuery({
3786
+ tableName: resolvedTableName,
3787
+ columns,
3788
+ conditions,
3789
+ limit: executionState.limit,
3790
+ offset: executionState.offset,
3791
+ currentPage: executionState.currentPage,
3792
+ pageSize: executionState.pageSize,
3793
+ order: executionState.order
3794
+ });
3795
+ return executeWithQueryTrace(
3796
+ tracer,
3797
+ {
3798
+ operation: "select",
3799
+ endpoint: "/gateway/fetch",
3800
+ table: resolvedTableName,
3801
+ sql,
3802
+ payload,
3803
+ options
3804
+ },
3805
+ async () => {
3806
+ const response = await client.fetchGateway(payload, options);
3807
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3808
+ },
3809
+ callsite
3810
+ );
2596
3811
  };
2597
- const createSelectChain = (columns, options) => {
3812
+ const createSelectChain = (columns, options, initialCallsite) => {
2598
3813
  const chain = {};
3814
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
2599
3815
  const filterMethods2 = createFilterMethods(state, addCondition, chain);
2600
3816
  Object.assign(chain, filterMethods2, {
2601
3817
  async single(cols, opts) {
2602
- const r = await runSelect(cols ?? columns, opts ?? options);
3818
+ const r = await runSelect(
3819
+ cols ?? columns,
3820
+ opts ?? options,
3821
+ snapshotState(),
3822
+ callsiteStore.resolve(captureTraceCallsite(tracer))
3823
+ );
2603
3824
  return toSingleResult(r);
2604
3825
  },
2605
3826
  maybeSingle(cols, opts) {
2606
3827
  return chain.single(cols, opts);
2607
3828
  },
2608
3829
  then(onfulfilled, onrejected) {
2609
- return runSelect(columns, options).then(onfulfilled, onrejected);
3830
+ return runSelect(
3831
+ columns,
3832
+ options,
3833
+ snapshotState(),
3834
+ callsiteStore.resolve()
3835
+ ).then(onfulfilled, onrejected);
2610
3836
  },
2611
3837
  catch(onrejected) {
2612
- return runSelect(columns, options).catch(onrejected);
3838
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).catch(
3839
+ onrejected
3840
+ );
2613
3841
  },
2614
3842
  finally(onfinally) {
2615
- return runSelect(columns, options).finally(onfinally);
3843
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).finally(
3844
+ onfinally
3845
+ );
2616
3846
  }
2617
3847
  });
2618
3848
  return chain;
@@ -2629,11 +3859,75 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2629
3859
  return builder;
2630
3860
  },
2631
3861
  select(columns = DEFAULT_COLUMNS, options) {
2632
- return createSelectChain(columns, options);
3862
+ return createSelectChain(columns, options, captureTraceCallsite(tracer));
3863
+ },
3864
+ async findMany(options) {
3865
+ const columns = compileSelectShape(options.select);
3866
+ const baseState = snapshotState();
3867
+ const executionState = snapshotState();
3868
+ const callsite = captureTraceCallsite(tracer);
3869
+ const compiledWhere = compileWhere(options.where);
3870
+ if (compiledWhere?.length) {
3871
+ executionState.conditions.push(...compiledWhere);
3872
+ }
3873
+ if (options.orderBy !== void 0) {
3874
+ executionState.order = compileOrderBy(options.orderBy);
3875
+ }
3876
+ if (options.limit !== void 0) {
3877
+ executionState.limit = options.limit;
3878
+ }
3879
+ if (experimental?.findManyAst && canUseFindManyAstTransport(baseState)) {
3880
+ const resolvedTableName = resolveTableNameForCall(tableName, void 0);
3881
+ const payload = {
3882
+ table_name: resolvedTableName,
3883
+ select: options.select
3884
+ };
3885
+ if (options.where !== void 0) {
3886
+ payload.where = options.where;
3887
+ }
3888
+ const astOrder = toFindManyAstOrder(executionState.order);
3889
+ if (astOrder !== void 0) {
3890
+ payload.orderBy = astOrder;
3891
+ }
3892
+ if (executionState.limit !== void 0) {
3893
+ payload.limit = executionState.limit;
3894
+ }
3895
+ const sql = buildDebugSelectQuery({
3896
+ tableName: resolvedTableName,
3897
+ columns,
3898
+ conditions: executionState.conditions,
3899
+ limit: executionState.limit,
3900
+ order: executionState.order
3901
+ });
3902
+ return executeWithQueryTrace(
3903
+ tracer,
3904
+ {
3905
+ operation: "select",
3906
+ endpoint: "/gateway/fetch",
3907
+ table: resolvedTableName,
3908
+ sql,
3909
+ payload
3910
+ },
3911
+ async () => {
3912
+ const response = await client.fetchGateway(
3913
+ payload
3914
+ );
3915
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3916
+ },
3917
+ callsite
3918
+ );
3919
+ }
3920
+ return runSelect(
3921
+ columns,
3922
+ void 0,
3923
+ executionState,
3924
+ callsite
3925
+ );
2633
3926
  },
2634
3927
  insert(values, options) {
3928
+ const mutationCallsite = captureTraceCallsite(tracer);
2635
3929
  if (Array.isArray(values)) {
2636
- const executeInsertMany = async (columns, selectOptions) => {
3930
+ const executeInsertMany = async (columns, selectOptions, callsite) => {
2637
3931
  const mergedOptions = mergeOptions(options, selectOptions);
2638
3932
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2639
3933
  const payload = {
@@ -2646,12 +3940,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2646
3940
  if (mergedOptions?.defaultToNull !== void 0) {
2647
3941
  payload.default_to_null = mergedOptions.defaultToNull;
2648
3942
  }
2649
- const response = await client.insertGateway(payload, mergedOptions);
2650
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
3943
+ const sql = buildInsertDebugSql(payload);
3944
+ return executeWithQueryTrace(
3945
+ tracer,
3946
+ {
3947
+ operation: "insert",
3948
+ endpoint: "/gateway/insert",
3949
+ table: resolvedTableName,
3950
+ sql,
3951
+ payload,
3952
+ options: mergedOptions
3953
+ },
3954
+ async () => {
3955
+ const response = await client.insertGateway(payload, mergedOptions);
3956
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
3957
+ },
3958
+ callsite
3959
+ );
2651
3960
  };
2652
- return createMutationQuery(executeInsertMany);
3961
+ return createMutationQuery(executeInsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
2653
3962
  }
2654
- const executeInsertOne = async (columns, selectOptions) => {
3963
+ const executeInsertOne = async (columns, selectOptions, callsite) => {
2655
3964
  const mergedOptions = mergeOptions(options, selectOptions);
2656
3965
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2657
3966
  const payload = {
@@ -2664,14 +3973,30 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2664
3973
  if (mergedOptions?.defaultToNull !== void 0) {
2665
3974
  payload.default_to_null = mergedOptions.defaultToNull;
2666
3975
  }
2667
- const response = await client.insertGateway(payload, mergedOptions);
2668
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
3976
+ const sql = buildInsertDebugSql(payload);
3977
+ return executeWithQueryTrace(
3978
+ tracer,
3979
+ {
3980
+ operation: "insert",
3981
+ endpoint: "/gateway/insert",
3982
+ table: resolvedTableName,
3983
+ sql,
3984
+ payload,
3985
+ options: mergedOptions
3986
+ },
3987
+ async () => {
3988
+ const response = await client.insertGateway(payload, mergedOptions);
3989
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
3990
+ },
3991
+ callsite
3992
+ );
2669
3993
  };
2670
- return createMutationQuery(executeInsertOne);
3994
+ return createMutationQuery(executeInsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
2671
3995
  },
2672
3996
  upsert(values, options) {
3997
+ const mutationCallsite = captureTraceCallsite(tracer);
2673
3998
  if (Array.isArray(values)) {
2674
- const executeUpsertMany = async (columns, selectOptions) => {
3999
+ const executeUpsertMany = async (columns, selectOptions, callsite) => {
2675
4000
  const mergedOptions = mergeOptions(options, selectOptions);
2676
4001
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2677
4002
  const payload = {
@@ -2686,12 +4011,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2686
4011
  if (mergedOptions?.defaultToNull !== void 0) {
2687
4012
  payload.default_to_null = mergedOptions.defaultToNull;
2688
4013
  }
2689
- const response = await client.insertGateway(payload, mergedOptions);
2690
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4014
+ const sql = buildInsertDebugSql(payload);
4015
+ return executeWithQueryTrace(
4016
+ tracer,
4017
+ {
4018
+ operation: "upsert",
4019
+ endpoint: "/gateway/insert",
4020
+ table: resolvedTableName,
4021
+ sql,
4022
+ payload,
4023
+ options: mergedOptions
4024
+ },
4025
+ async () => {
4026
+ const response = await client.insertGateway(payload, mergedOptions);
4027
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4028
+ },
4029
+ callsite
4030
+ );
2691
4031
  };
2692
- return createMutationQuery(executeUpsertMany);
4032
+ return createMutationQuery(executeUpsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
2693
4033
  }
2694
- const executeUpsertOne = async (columns, selectOptions) => {
4034
+ const executeUpsertOne = async (columns, selectOptions, callsite) => {
2695
4035
  const mergedOptions = mergeOptions(options, selectOptions);
2696
4036
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2697
4037
  const payload = {
@@ -2706,13 +4046,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2706
4046
  if (mergedOptions?.defaultToNull !== void 0) {
2707
4047
  payload.default_to_null = mergedOptions.defaultToNull;
2708
4048
  }
2709
- const response = await client.insertGateway(payload, mergedOptions);
2710
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4049
+ const sql = buildInsertDebugSql(payload);
4050
+ return executeWithQueryTrace(
4051
+ tracer,
4052
+ {
4053
+ operation: "upsert",
4054
+ endpoint: "/gateway/insert",
4055
+ table: resolvedTableName,
4056
+ sql,
4057
+ payload,
4058
+ options: mergedOptions
4059
+ },
4060
+ async () => {
4061
+ const response = await client.insertGateway(payload, mergedOptions);
4062
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4063
+ },
4064
+ callsite
4065
+ );
2711
4066
  };
2712
- return createMutationQuery(executeUpsertOne);
4067
+ return createMutationQuery(executeUpsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
2713
4068
  },
2714
4069
  update(values, options) {
2715
- const executeUpdate = async (columns, selectOptions) => {
4070
+ const mutationCallsite = captureTraceCallsite(tracer);
4071
+ const executeUpdate = async (columns, selectOptions, callsite) => {
2716
4072
  const filters = state.conditions.length ? [...state.conditions] : void 0;
2717
4073
  const mergedOptions = mergeOptions(options, selectOptions);
2718
4074
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
@@ -2727,10 +4083,25 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2727
4083
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
2728
4084
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
2729
4085
  if (columns) payload.columns = columns;
2730
- const response = await client.updateGateway(payload, mergedOptions);
2731
- return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
4086
+ const sql = buildUpdateDebugSql(payload);
4087
+ return executeWithQueryTrace(
4088
+ tracer,
4089
+ {
4090
+ operation: "update",
4091
+ endpoint: "/gateway/update",
4092
+ table: resolvedTableName,
4093
+ sql,
4094
+ payload,
4095
+ options: mergedOptions
4096
+ },
4097
+ async () => {
4098
+ const response = await client.updateGateway(payload, mergedOptions);
4099
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
4100
+ },
4101
+ callsite
4102
+ );
2732
4103
  };
2733
- const mutation = createMutationQuery(executeUpdate, null);
4104
+ const mutation = createMutationQuery(executeUpdate, null, tracer, mutationCallsite);
2734
4105
  const updateChain = {};
2735
4106
  const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
2736
4107
  Object.assign(updateChain, filterMethods2, mutation);
@@ -2742,7 +4113,8 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2742
4113
  if (!resourceId && !filters?.length) {
2743
4114
  throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
2744
4115
  }
2745
- const executeDelete = async (columns, selectOptions) => {
4116
+ const mutationCallsite = captureTraceCallsite(tracer);
4117
+ const executeDelete = async (columns, selectOptions, callsite) => {
2746
4118
  const mergedOptions = mergeOptions(options, selectOptions);
2747
4119
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2748
4120
  const payload = {
@@ -2755,13 +4127,33 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2755
4127
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
2756
4128
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
2757
4129
  if (columns) payload.columns = columns;
2758
- const response = await client.deleteGateway(payload, mergedOptions);
2759
- return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
4130
+ const sql = buildDeleteDebugSql(payload);
4131
+ return executeWithQueryTrace(
4132
+ tracer,
4133
+ {
4134
+ operation: "delete",
4135
+ endpoint: "/gateway/delete",
4136
+ table: resolvedTableName,
4137
+ sql,
4138
+ payload,
4139
+ options: mergedOptions
4140
+ },
4141
+ async () => {
4142
+ const response = await client.deleteGateway(payload, mergedOptions);
4143
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
4144
+ },
4145
+ callsite
4146
+ );
2760
4147
  };
2761
- return createMutationQuery(executeDelete, null);
4148
+ return createMutationQuery(executeDelete, null, tracer, mutationCallsite);
2762
4149
  },
2763
4150
  async single(columns, options) {
2764
- const response = await builder.select(columns, options);
4151
+ const response = await runSelect(
4152
+ columns ?? DEFAULT_COLUMNS,
4153
+ options,
4154
+ snapshotState(),
4155
+ captureTraceCallsite(tracer)
4156
+ );
2765
4157
  return toSingleResult(response);
2766
4158
  },
2767
4159
  async maybeSingle(columns, options) {
@@ -2770,14 +4162,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2770
4162
  });
2771
4163
  return builder;
2772
4164
  }
2773
- function createQueryBuilder(client, formatGatewayResult) {
4165
+ function createQueryBuilder(client, formatGatewayResult, tracer) {
2774
4166
  return async function query(query, options) {
2775
4167
  const normalizedQuery = query.trim();
2776
4168
  if (!normalizedQuery) {
2777
4169
  throw new Error("query requires a non-empty string");
2778
4170
  }
2779
- const response = await client.queryGateway({ query: normalizedQuery }, options);
2780
- return formatGatewayResult(response, { operation: "query" });
4171
+ const payload = { query: normalizedQuery };
4172
+ const callsite = captureTraceCallsite(tracer);
4173
+ return executeWithQueryTrace(
4174
+ tracer,
4175
+ {
4176
+ operation: "query",
4177
+ endpoint: "/gateway/query",
4178
+ sql: normalizedQuery,
4179
+ payload,
4180
+ options
4181
+ },
4182
+ async () => {
4183
+ const response = await client.queryGateway(payload, options);
4184
+ return formatGatewayResult(response, { operation: "query" });
4185
+ },
4186
+ callsite
4187
+ );
2781
4188
  };
2782
4189
  }
2783
4190
  function createClientFromConfig(config) {
@@ -2789,8 +4196,9 @@ function createClientFromConfig(config) {
2789
4196
  headers: config.headers
2790
4197
  });
2791
4198
  const formatGatewayResult = createResultFormatter(config.experimental);
4199
+ const queryTracer = createQueryTracer(config.experimental);
2792
4200
  const auth = createAuthClient(config.auth);
2793
- const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
4201
+ const from = (table) => createTableBuilder(table, gateway, formatGatewayResult, queryTracer, config.experimental);
2794
4202
  const rpc = (fn, args, options) => {
2795
4203
  const normalizedFn = fn.trim();
2796
4204
  if (!normalizedFn) {
@@ -2801,10 +4209,12 @@ function createClientFromConfig(config) {
2801
4209
  args,
2802
4210
  options,
2803
4211
  gateway,
2804
- formatGatewayResult
4212
+ formatGatewayResult,
4213
+ queryTracer,
4214
+ captureTraceCallsite(queryTracer)
2805
4215
  );
2806
4216
  };
2807
- const query = createQueryBuilder(gateway, formatGatewayResult);
4217
+ const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
2808
4218
  const db = createDbModule({ from, rpc, query });
2809
4219
  return {
2810
4220
  from,
@@ -2819,12 +4229,40 @@ function toBackendConfig(b) {
2819
4229
  if (!b) return DEFAULT_BACKEND;
2820
4230
  return typeof b === "string" ? { type: b } : b;
2821
4231
  }
4232
+ function mergeAuthClientConfig(current, next) {
4233
+ const merged = {
4234
+ ...current ?? {},
4235
+ ...next
4236
+ };
4237
+ if (current?.headers || next.headers) {
4238
+ merged.headers = {
4239
+ ...current?.headers ?? {},
4240
+ ...next.headers ?? {}
4241
+ };
4242
+ }
4243
+ return merged;
4244
+ }
4245
+ function mergeExperimentalOptions(current, next) {
4246
+ const merged = {
4247
+ ...current ?? {},
4248
+ ...next
4249
+ };
4250
+ if (current?.traceQueries && typeof current.traceQueries === "object" && next.traceQueries && typeof next.traceQueries === "object") {
4251
+ merged.traceQueries = {
4252
+ ...current.traceQueries,
4253
+ ...next.traceQueries
4254
+ };
4255
+ }
4256
+ return merged;
4257
+ }
2822
4258
  var AthenaClientBuilderImpl = class {
2823
4259
  baseUrl;
2824
4260
  apiKey;
2825
4261
  backendConfig = DEFAULT_BACKEND;
2826
4262
  clientName;
2827
4263
  defaultHeaders;
4264
+ authConfig;
4265
+ experimentalOptions;
2828
4266
  isHealthTrackingEnabled = false;
2829
4267
  url(url) {
2830
4268
  this.baseUrl = url;
@@ -2846,6 +4284,35 @@ var AthenaClientBuilderImpl = class {
2846
4284
  this.defaultHeaders = headers;
2847
4285
  return this;
2848
4286
  }
4287
+ auth(config) {
4288
+ this.authConfig = mergeAuthClientConfig(this.authConfig, config);
4289
+ return this;
4290
+ }
4291
+ experimental(options) {
4292
+ this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options);
4293
+ return this;
4294
+ }
4295
+ options(options) {
4296
+ if (options.client !== void 0) {
4297
+ this.clientName = options.client;
4298
+ }
4299
+ if (options.backend !== void 0) {
4300
+ this.backendConfig = toBackendConfig(options.backend);
4301
+ }
4302
+ if (options.headers !== void 0) {
4303
+ this.defaultHeaders = {
4304
+ ...this.defaultHeaders ?? {},
4305
+ ...options.headers
4306
+ };
4307
+ }
4308
+ if (options.auth !== void 0) {
4309
+ this.authConfig = mergeAuthClientConfig(this.authConfig, options.auth);
4310
+ }
4311
+ if (options.experimental !== void 0) {
4312
+ this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options.experimental);
4313
+ }
4314
+ return this;
4315
+ }
2849
4316
  healthTracking(enabled) {
2850
4317
  this.isHealthTrackingEnabled = enabled;
2851
4318
  return this;
@@ -2860,7 +4327,9 @@ var AthenaClientBuilderImpl = class {
2860
4327
  client: this.clientName,
2861
4328
  backend: this.backendConfig,
2862
4329
  headers: this.defaultHeaders,
2863
- healthTracking: this.isHealthTrackingEnabled
4330
+ healthTracking: this.isHealthTrackingEnabled,
4331
+ auth: this.authConfig,
4332
+ experimental: this.experimentalOptions
2864
4333
  });
2865
4334
  }
2866
4335
  };
@@ -3040,7 +4509,7 @@ function resolveNullishValue(mode) {
3040
4509
  if (mode === "null") return null;
3041
4510
  return "";
3042
4511
  }
3043
- function isRecord4(value) {
4512
+ function isRecord7(value) {
3044
4513
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3045
4514
  }
3046
4515
  function isNullableColumn(model, key) {
@@ -3049,7 +4518,7 @@ function isNullableColumn(model, key) {
3049
4518
  }
3050
4519
  function toModelFormDefaults(model, values, options) {
3051
4520
  const source = values;
3052
- if (!isRecord4(source)) {
4521
+ if (!isRecord7(source)) {
3053
4522
  return {};
3054
4523
  }
3055
4524
  const mode = options?.nullishMode ?? "empty-string";
@@ -3246,31 +4715,31 @@ function throwBrowserUnsupported(apiName) {
3246
4715
  `@xylex-group/athena: ${apiName} is not available in browser bundles. Use this API in a Node.js runtime.`
3247
4716
  );
3248
4717
  }
3249
- function createPostgresIntrospectionProvider(_options) {
4718
+ function createPostgresIntrospectionProvider(options) {
3250
4719
  return throwBrowserUnsupported("createPostgresIntrospectionProvider");
3251
4720
  }
3252
4721
  function defineGeneratorConfig(config) {
3253
4722
  return config;
3254
4723
  }
3255
- function findGeneratorConfigPath(_cwd) {
4724
+ function findGeneratorConfigPath(cwd) {
3256
4725
  return throwBrowserUnsupported("findGeneratorConfigPath");
3257
4726
  }
3258
- async function loadGeneratorConfig(_options = {}) {
4727
+ async function loadGeneratorConfig(options = {}) {
3259
4728
  return throwBrowserUnsupported("loadGeneratorConfig");
3260
4729
  }
3261
- function normalizeGeneratorConfig(_input) {
4730
+ function normalizeGeneratorConfig(input) {
3262
4731
  return throwBrowserUnsupported("normalizeGeneratorConfig");
3263
4732
  }
3264
- function generateArtifactsFromSnapshot(_snapshot, _config) {
4733
+ function generateArtifactsFromSnapshot(snapshot, config) {
3265
4734
  return throwBrowserUnsupported("generateArtifactsFromSnapshot");
3266
4735
  }
3267
- function resolveGeneratorProvider(_providerConfig, _experimentalFlags) {
4736
+ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
3268
4737
  return throwBrowserUnsupported("resolveGeneratorProvider");
3269
4738
  }
3270
- async function runSchemaGenerator(_options = {}) {
4739
+ async function runSchemaGenerator(options = {}) {
3271
4740
  return throwBrowserUnsupported("runSchemaGenerator");
3272
4741
  }
3273
4742
 
3274
- export { AthenaClient, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, Backend, DEFAULT_POSTGRES_SCHEMAS, assertInt, coerceInt, createAuthClient, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createTypedClient, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, findGeneratorConfigPath, generateArtifactsFromSnapshot, identifier, isAthenaGatewayError, isOk, loadGeneratorConfig, normalizeAthenaError, normalizeGeneratorConfig, normalizeSchemaSelection, parseBooleanFlag, requireAffected, requireSuccess, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, runSchemaGenerator, toModelFormDefaults, toModelPayload, unwrap, unwrapOne, unwrapRows, withRetry };
4743
+ export { AthenaClient, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, Backend, DEFAULT_POSTGRES_SCHEMAS, assertInt, coerceInt, createAuthClient, createAuthReactEmailInput, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createTypedClient, defineAuthEmailTemplate, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, findGeneratorConfigPath, generateArtifactsFromSnapshot, identifier, isAthenaGatewayError, isOk, loadGeneratorConfig, normalizeAthenaError, normalizeGeneratorConfig, normalizeSchemaSelection, parseBooleanFlag2 as parseBooleanFlag, renderAthenaReactEmail, requireAffected, requireSuccess, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, runSchemaGenerator, toModelFormDefaults, toModelPayload, unwrap, unwrapOne, unwrapRows, withRetry };
3275
4744
  //# sourceMappingURL=browser.js.map
3276
4745
  //# sourceMappingURL=browser.js.map