@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/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'fs';
2
2
  import { resolve, dirname, posix } from 'path';
3
3
  import { pathToFileURL } from 'url';
4
- import { mkdir, writeFile } from 'fs/promises';
4
+ import { mkdir, writeFile, stat } from 'fs/promises';
5
5
 
6
6
  // src/gateway/errors.ts
7
7
  var AthenaGatewayError = class _AthenaGatewayError extends Error {
@@ -91,23 +91,39 @@ function normalizeHeaderValue(value) {
91
91
  function isRecord(value) {
92
92
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
93
93
  }
94
+ function nonEmptyString(value) {
95
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
96
+ }
97
+ function resolveStructuredErrorPayload(payload) {
98
+ if (!isRecord(payload)) return null;
99
+ return isRecord(payload.error) ? payload.error : payload;
100
+ }
94
101
  function resolveRequestId(headers) {
95
102
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
96
103
  }
97
104
  function resolveErrorMessage(payload, fallback) {
98
- if (isRecord(payload)) {
99
- const messageCandidates = [payload.error, payload.message, payload.details];
105
+ const structuredPayload = resolveStructuredErrorPayload(payload);
106
+ if (structuredPayload) {
107
+ const messageCandidates = [structuredPayload.message, structuredPayload.error, structuredPayload.details];
100
108
  for (const candidate of messageCandidates) {
101
- if (typeof candidate === "string" && candidate.trim().length > 0) {
102
- return candidate.trim();
103
- }
109
+ const resolved = nonEmptyString(candidate);
110
+ if (resolved) return resolved;
104
111
  }
105
112
  }
106
- if (typeof payload === "string" && payload.trim().length > 0) {
107
- return payload.trim();
108
- }
113
+ const rawMessage = nonEmptyString(payload);
114
+ if (rawMessage) return rawMessage;
109
115
  return fallback;
110
116
  }
117
+ function resolveErrorHint(payload) {
118
+ const structuredPayload = resolveStructuredErrorPayload(payload);
119
+ return structuredPayload ? nonEmptyString(structuredPayload.hint) : void 0;
120
+ }
121
+ function resolveStatusText(response, payload) {
122
+ const rawStatusText = nonEmptyString(response.statusText);
123
+ if (rawStatusText) return rawStatusText;
124
+ const payloadRecord = isRecord(payload) ? payload : null;
125
+ return payloadRecord ? nonEmptyString(payloadRecord.statusText) ?? null : null;
126
+ }
111
127
  function detailsFromError(error) {
112
128
  return error.toDetails();
113
129
  }
@@ -278,6 +294,7 @@ async function callAthena(config, endpoint, method, payload, options) {
278
294
  return {
279
295
  ok: false,
280
296
  status: response.status,
297
+ statusText: resolveStatusText(response, parsedBody.parsed),
281
298
  data: null,
282
299
  error: invalidJsonError.message,
283
300
  errorDetails: detailsFromError(invalidJsonError),
@@ -296,11 +313,13 @@ async function callAthena(config, endpoint, method, payload, options) {
296
313
  status: response.status,
297
314
  endpoint,
298
315
  method,
299
- requestId
316
+ requestId,
317
+ hint: resolveErrorHint(parsed)
300
318
  });
301
319
  return {
302
320
  ok: false,
303
321
  status: response.status,
322
+ statusText: resolveStatusText(response, parsed),
304
323
  data: null,
305
324
  error: httpError.message,
306
325
  errorDetails: detailsFromError(httpError),
@@ -312,6 +331,7 @@ async function callAthena(config, endpoint, method, payload, options) {
312
331
  return {
313
332
  ok: true,
314
333
  status: response.status,
334
+ statusText: resolveStatusText(response, parsed),
315
335
  data: payloadData ?? null,
316
336
  count: payloadCount,
317
337
  error: void 0,
@@ -331,6 +351,7 @@ async function callAthena(config, endpoint, method, payload, options) {
331
351
  return {
332
352
  ok: false,
333
353
  status: 0,
354
+ statusText: null,
334
355
  data: null,
335
356
  error: networkError.message,
336
357
  errorDetails: detailsFromError(networkError),
@@ -372,10 +393,29 @@ function createAthenaGatewayClient(config = {}) {
372
393
  // src/sql-identifiers.ts
373
394
  var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
374
395
  var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
375
- var ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
396
+ var SQL_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
397
+ var RESPONSE_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_.]*)$/i;
376
398
  function quoteIdentifierSegment(identifier2) {
377
399
  return `"${identifier2.replace(/"/g, '""')}"`;
378
400
  }
401
+ function parseAliasedIdentifierToken(token) {
402
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(token);
403
+ if (responseAliasMatch) {
404
+ const [, aliasIdentifier2, baseIdentifier2] = responseAliasMatch;
405
+ if (COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier2) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier2)) {
406
+ return { baseIdentifier: baseIdentifier2, aliasIdentifier: aliasIdentifier2 };
407
+ }
408
+ }
409
+ const sqlAliasMatch = SQL_ALIAS_PATTERN.exec(token);
410
+ if (!sqlAliasMatch) {
411
+ return null;
412
+ }
413
+ const [, baseIdentifier, aliasIdentifier] = sqlAliasMatch;
414
+ if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
415
+ return null;
416
+ }
417
+ return { baseIdentifier, aliasIdentifier };
418
+ }
379
419
  function quoteQualifiedIdentifier(identifier2) {
380
420
  return identifier2.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
381
421
  }
@@ -384,23 +424,27 @@ function quoteSelectToken(token) {
384
424
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
385
425
  return quoteQualifiedIdentifier(token);
386
426
  }
387
- const aliasMatch = ALIAS_PATTERN.exec(token);
388
- if (!aliasMatch) {
389
- return token;
390
- }
391
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
392
- if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
427
+ const aliasedIdentifier = parseAliasedIdentifierToken(token);
428
+ if (!aliasedIdentifier) {
393
429
  return token;
394
430
  }
431
+ const { baseIdentifier, aliasIdentifier } = aliasedIdentifier;
395
432
  return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
396
433
  }
434
+ function quoteSelectColumnToken(token) {
435
+ const trimmed = token.trim();
436
+ if (!trimmed || trimmed === "*") return trimmed || "*";
437
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(trimmed);
438
+ if (responseAliasMatch) {
439
+ const [, aliasIdentifier, baseIdentifier] = responseAliasMatch;
440
+ return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
441
+ }
442
+ return quoteQualifiedIdentifier(trimmed);
443
+ }
397
444
  function canAutoQuoteToken(token) {
398
445
  if (token === "*") return true;
399
446
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
400
- const aliasMatch = ALIAS_PATTERN.exec(token);
401
- if (!aliasMatch) return false;
402
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
403
- return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
447
+ return parseAliasedIdentifierToken(token) != null;
404
448
  }
405
449
  function splitTopLevelCommaSeparated(input) {
406
450
  const parts = [];
@@ -500,6 +544,231 @@ function identifier(...segments) {
500
544
  return new SqlIdentifierPath(expandedSegments);
501
545
  }
502
546
 
547
+ // src/auth/react-email.ts
548
+ var reactEmailRenderModulePromise;
549
+ function isRecord2(value) {
550
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
551
+ }
552
+ function isFunction(value) {
553
+ return typeof value === "function";
554
+ }
555
+ function toStringOrUndefined(value) {
556
+ if (typeof value !== "string") return void 0;
557
+ return value;
558
+ }
559
+ function nowIsoString() {
560
+ return (/* @__PURE__ */ new Date()).toISOString();
561
+ }
562
+ function emitReactEmailEvent(observe, phase, input = {}) {
563
+ if (!observe) return;
564
+ try {
565
+ observe({
566
+ phase,
567
+ timestamp: nowIsoString(),
568
+ ...input
569
+ });
570
+ } catch {
571
+ }
572
+ }
573
+ function mergeRenderDefaults(input, defaults) {
574
+ return {
575
+ ...input,
576
+ pretty: input.pretty ?? defaults?.pretty,
577
+ includePlainText: input.includePlainText ?? defaults?.includePlainText
578
+ };
579
+ }
580
+ function mergeRuntimeOptions(options) {
581
+ if (!options) return void 0;
582
+ return {
583
+ defaults: options.defaults,
584
+ observe: options.observe,
585
+ route: "route" in options ? options.route : void 0
586
+ };
587
+ }
588
+ async function resolveReactEmailRenderModule() {
589
+ if (!reactEmailRenderModulePromise) {
590
+ reactEmailRenderModulePromise = (async () => {
591
+ try {
592
+ const loaded = await import('@react-email/render');
593
+ if (!isFunction(loaded.render)) {
594
+ throw new Error("missing render(...) export");
595
+ }
596
+ return {
597
+ render: loaded.render,
598
+ toPlainText: isFunction(loaded.toPlainText) ? loaded.toPlainText : void 0,
599
+ pretty: isFunction(loaded.pretty) ? loaded.pretty : void 0
600
+ };
601
+ } catch (error) {
602
+ const message = error instanceof Error ? error.message : String(error);
603
+ throw new Error(
604
+ `React Email rendering requires @react-email/render. Install it in your project (for example: pnpm add @react-email/render). Loader error: ${message}`
605
+ );
606
+ }
607
+ })();
608
+ }
609
+ if (!reactEmailRenderModulePromise) {
610
+ throw new Error("React Email renderer module failed to initialize");
611
+ }
612
+ return reactEmailRenderModulePromise;
613
+ }
614
+ async function resolveReactEmailElement(input) {
615
+ if (input.element != null) {
616
+ return input.element;
617
+ }
618
+ if (!input.component) {
619
+ throw new Error("react email payload requires either `element` or `component`");
620
+ }
621
+ try {
622
+ const reactModule = await import('react');
623
+ if (typeof reactModule.createElement !== "function") {
624
+ throw new Error("react createElement(...) export is unavailable");
625
+ }
626
+ return reactModule.createElement(
627
+ input.component,
628
+ input.props ?? {}
629
+ );
630
+ } catch (error) {
631
+ const message = error instanceof Error ? error.message : String(error);
632
+ throw new Error(
633
+ `React Email component rendering requires react runtime support. Install react in your project. Loader error: ${message}`
634
+ );
635
+ }
636
+ }
637
+ function createAuthReactEmailInput(component, props, overrides = {}) {
638
+ return {
639
+ ...overrides,
640
+ component,
641
+ props
642
+ };
643
+ }
644
+ function defineAuthEmailTemplate(definition) {
645
+ const react = (props, overrides) => createAuthReactEmailInput(definition.component, props, {
646
+ ...definition.defaults,
647
+ ...overrides
648
+ });
649
+ return {
650
+ component: definition.component,
651
+ react,
652
+ toTemplateCreate: (input) => {
653
+ const templateKey = input.templateKey ?? definition.templateKey;
654
+ const subjectTemplate = input.subjectTemplate ?? definition.subjectTemplate;
655
+ if (!templateKey) {
656
+ throw new Error("defineAuthEmailTemplate.toTemplateCreate requires templateKey");
657
+ }
658
+ if (!subjectTemplate) {
659
+ throw new Error("defineAuthEmailTemplate.toTemplateCreate requires subjectTemplate");
660
+ }
661
+ const { props, react: reactOverrides, ...rest } = input;
662
+ return {
663
+ ...rest,
664
+ templateKey,
665
+ subjectTemplate,
666
+ react: react(props, reactOverrides)
667
+ };
668
+ },
669
+ toTemplateUpdate: (input) => {
670
+ const { props, react: reactOverrides, ...rest } = input;
671
+ return {
672
+ ...rest,
673
+ react: react(props, reactOverrides)
674
+ };
675
+ }
676
+ };
677
+ }
678
+ async function renderAthenaReactEmail(input, options) {
679
+ if (!isRecord2(input)) {
680
+ throw new Error("react email payload must be an object");
681
+ }
682
+ const runtimeOptions = mergeRuntimeOptions(options);
683
+ const start = Date.now();
684
+ emitReactEmailEvent(runtimeOptions?.observe, "render:start", {
685
+ route: runtimeOptions?.route,
686
+ message: "Rendering react email payload"
687
+ });
688
+ try {
689
+ const normalizedInput = mergeRenderDefaults(input, runtimeOptions?.defaults);
690
+ const element = await resolveReactEmailElement(normalizedInput);
691
+ const renderModule = await resolveReactEmailRenderModule();
692
+ const htmlValue = await renderModule.render(element);
693
+ const renderedHtml = typeof htmlValue === "string" ? htmlValue : String(htmlValue ?? "");
694
+ if (!renderedHtml.trim()) {
695
+ throw new Error("react email renderer returned an empty HTML string");
696
+ }
697
+ let html = renderedHtml;
698
+ if (normalizedInput.pretty && renderModule.pretty) {
699
+ const prettyValue = await renderModule.pretty(renderedHtml);
700
+ if (typeof prettyValue === "string" && prettyValue.trim().length > 0) {
701
+ html = prettyValue;
702
+ }
703
+ }
704
+ const explicitText = toStringOrUndefined(normalizedInput.text);
705
+ if (explicitText !== void 0) {
706
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
707
+ route: runtimeOptions?.route,
708
+ durationMs: Date.now() - start,
709
+ message: "Rendered react email with explicit text"
710
+ });
711
+ return {
712
+ html,
713
+ text: explicitText
714
+ };
715
+ }
716
+ if (normalizedInput.includePlainText === false || !renderModule.toPlainText) {
717
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
718
+ route: runtimeOptions?.route,
719
+ durationMs: Date.now() - start,
720
+ message: "Rendered react email without plain-text derivation"
721
+ });
722
+ return { html };
723
+ }
724
+ const plainTextValue = await renderModule.toPlainText(html);
725
+ const plainText = toStringOrUndefined(plainTextValue);
726
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
727
+ route: runtimeOptions?.route,
728
+ durationMs: Date.now() - start,
729
+ message: plainText ? "Rendered react email with derived plain text" : "Rendered react email HTML only"
730
+ });
731
+ if (plainText === void 0) {
732
+ return { html };
733
+ }
734
+ return {
735
+ html,
736
+ text: plainText
737
+ };
738
+ } catch (error) {
739
+ const message = error instanceof Error ? error.message : String(error);
740
+ emitReactEmailEvent(runtimeOptions?.observe, "render:error", {
741
+ route: runtimeOptions?.route,
742
+ durationMs: Date.now() - start,
743
+ error: message,
744
+ message: "Failed to render react email payload"
745
+ });
746
+ throw error;
747
+ }
748
+ }
749
+ async function resolveReactEmailPayloadFields(input, fields, options) {
750
+ const { react, ...payloadWithoutReact } = input;
751
+ if (!react) {
752
+ return payloadWithoutReact;
753
+ }
754
+ const rendered = await renderAthenaReactEmail(react, options);
755
+ const payload = {
756
+ ...payloadWithoutReact
757
+ };
758
+ payload[fields.htmlField] = rendered.html;
759
+ const currentTextValue = payload[fields.textField];
760
+ if (rendered.text !== void 0 && (currentTextValue === void 0 || currentTextValue === null || currentTextValue === "")) {
761
+ payload[fields.textField] = rendered.text;
762
+ }
763
+ if (fields.variablesField && (payload[fields.variablesField] === void 0 || payload[fields.variablesField] === null) && isRecord2(react.props)) {
764
+ const derivedVariables = Object.keys(react.props);
765
+ if (derivedVariables.length > 0) {
766
+ payload[fields.variablesField] = derivedVariables;
767
+ }
768
+ }
769
+ return payload;
770
+ }
771
+
503
772
  // src/auth/client.ts
504
773
  var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
505
774
  var FALLBACK_SDK_VERSION2 = "1.0.0";
@@ -509,7 +778,7 @@ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
509
778
  function normalizeBaseUrl(baseUrl) {
510
779
  return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
511
780
  }
512
- function isRecord2(value) {
781
+ function isRecord3(value) {
513
782
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
514
783
  }
515
784
  function normalizeHeaderValue2(value) {
@@ -534,7 +803,7 @@ function resolveRequestId2(headers) {
534
803
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
535
804
  }
536
805
  function resolveErrorMessage2(payload, fallback) {
537
- if (isRecord2(payload)) {
806
+ if (isRecord3(payload)) {
538
807
  const messageCandidates = [payload.error, payload.message, payload.details];
539
808
  for (const candidate of messageCandidates) {
540
809
  if (typeof candidate === "string" && candidate.trim().length > 0) {
@@ -860,6 +1129,19 @@ function createAuthClient(config = {}) {
860
1129
  options
861
1130
  );
862
1131
  };
1132
+ const withReactEmailRoute = (route) => ({
1133
+ ...resolvedConfig.reactEmail,
1134
+ route
1135
+ });
1136
+ const resolveAdminEmailPayload = (route, input) => resolveReactEmailPayloadFields(input, {
1137
+ htmlField: "htmlBody",
1138
+ textField: "textBody"
1139
+ }, withReactEmailRoute(route));
1140
+ const resolveAdminEmailTemplatePayload = (route, input) => resolveReactEmailPayloadFields(input, {
1141
+ htmlField: "htmlTemplate",
1142
+ textField: "textTemplate",
1143
+ variablesField: "variables"
1144
+ }, withReactEmailRoute(route));
863
1145
  const listUserEmailsWithFallback = async (input, options) => {
864
1146
  const primary = await getWithQuery(
865
1147
  "/email/list",
@@ -887,7 +1169,7 @@ function createAuthClient(config = {}) {
887
1169
  data: null
888
1170
  };
889
1171
  }
890
- const fallbackStatus = isRecord2(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
1172
+ const fallbackStatus = isRecord3(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
891
1173
  return {
892
1174
  ...fallback,
893
1175
  data: {
@@ -1323,8 +1605,16 @@ function createAuthClient(config = {}) {
1323
1605
  email: {
1324
1606
  list: (input, options) => getWithQuery("/admin/email/list", input, options),
1325
1607
  get: (input, options) => getWithQuery("/admin/email/get", input, options),
1326
- create: (input, options) => postGeneric("/admin/email/create", input, options),
1327
- update: (input, options) => postGeneric("/admin/email/update", input, options),
1608
+ create: async (input, options) => postGeneric(
1609
+ "/admin/email/create",
1610
+ await resolveAdminEmailPayload("/admin/email/create", input),
1611
+ options
1612
+ ),
1613
+ update: async (input, options) => postGeneric(
1614
+ "/admin/email/update",
1615
+ await resolveAdminEmailPayload("/admin/email/update", input),
1616
+ options
1617
+ ),
1328
1618
  delete: (input, options) => postGeneric("/admin/email/delete", input, options),
1329
1619
  failure: {
1330
1620
  list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
@@ -1336,17 +1626,33 @@ function createAuthClient(config = {}) {
1336
1626
  template: {
1337
1627
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
1338
1628
  get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
1339
- create: (input, options) => postGeneric("/admin/email-template/create", input, options),
1340
- update: (input, options) => postGeneric("/admin/email-template/update", input, options),
1629
+ create: async (input, options) => postGeneric(
1630
+ "/admin/email-template/create",
1631
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
1632
+ options
1633
+ ),
1634
+ update: async (input, options) => postGeneric(
1635
+ "/admin/email-template/update",
1636
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
1637
+ options
1638
+ ),
1341
1639
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
1342
1640
  }
1343
1641
  },
1344
1642
  emailTemplate: {
1345
1643
  get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
1346
- create: (input, options) => postGeneric("/admin/email-template/create", input, options),
1644
+ create: async (input, options) => postGeneric(
1645
+ "/admin/email-template/create",
1646
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
1647
+ options
1648
+ ),
1347
1649
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
1348
1650
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
1349
- update: (input, options) => postGeneric("/admin/email-template/update", input, options)
1651
+ update: async (input, options) => postGeneric(
1652
+ "/admin/email-template/update",
1653
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
1654
+ options
1655
+ )
1350
1656
  }
1351
1657
  },
1352
1658
  apiKey: {
@@ -1538,6 +1844,19 @@ function createAuthClient(config = {}) {
1538
1844
  };
1539
1845
  }
1540
1846
 
1847
+ // src/utils/parse-boolean-flag.ts
1848
+ function parseBooleanFlag(rawValue, fallback) {
1849
+ if (!rawValue) return fallback;
1850
+ const normalized = rawValue.trim().toLowerCase();
1851
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
1852
+ return true;
1853
+ }
1854
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
1855
+ return false;
1856
+ }
1857
+ return fallback;
1858
+ }
1859
+
1541
1860
  // src/auxiliaries.ts
1542
1861
  var AthenaErrorKind = {
1543
1862
  UniqueViolation: "unique_violation",
@@ -1567,16 +1886,8 @@ var AthenaErrorCategory = {
1567
1886
  Database: "database",
1568
1887
  Unknown: "unknown"
1569
1888
  };
1570
- function parseBooleanFlag(rawValue, fallback) {
1571
- if (!rawValue) return fallback;
1572
- const normalized = rawValue.trim().toLowerCase();
1573
- if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
1574
- return true;
1575
- }
1576
- if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
1577
- return false;
1578
- }
1579
- return fallback;
1889
+ function parseBooleanFlag2(rawValue, fallback) {
1890
+ return parseBooleanFlag(rawValue, fallback);
1580
1891
  }
1581
1892
  var AthenaError = class extends Error {
1582
1893
  code;
@@ -1600,9 +1911,38 @@ var AthenaError = class extends Error {
1600
1911
  this.raw = input.raw;
1601
1912
  }
1602
1913
  };
1603
- function isRecord3(value) {
1914
+ function isRecord4(value) {
1604
1915
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1605
1916
  }
1917
+ function firstNonEmptyString(...values) {
1918
+ for (const value of values) {
1919
+ if (typeof value === "string" && value.trim().length > 0) {
1920
+ return value.trim();
1921
+ }
1922
+ }
1923
+ return void 0;
1924
+ }
1925
+ function messageFromUnknownError(error) {
1926
+ if (typeof error === "string" && error.trim().length > 0) {
1927
+ return error.trim();
1928
+ }
1929
+ if (error instanceof Error && error.message.trim().length > 0) {
1930
+ return error.message.trim();
1931
+ }
1932
+ if (!isRecord4(error)) {
1933
+ return void 0;
1934
+ }
1935
+ return firstNonEmptyString(error.message, error.error, error.details);
1936
+ }
1937
+ function gatewayCodeFromUnknownError(error) {
1938
+ if (!isRecord4(error) || typeof error.gatewayCode !== "string") {
1939
+ return void 0;
1940
+ }
1941
+ return error.gatewayCode;
1942
+ }
1943
+ function isAthenaResultErrorLike(value) {
1944
+ 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");
1945
+ }
1606
1946
  function isAthenaErrorKind(value) {
1607
1947
  return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
1608
1948
  }
@@ -1613,7 +1953,7 @@ function isAthenaErrorCategory(value) {
1613
1953
  return value === "transport" || value === "client" || value === "server" || value === "database" || value === "unknown";
1614
1954
  }
1615
1955
  function isNormalizedAthenaError(value) {
1616
- return isRecord3(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
1956
+ return isRecord4(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
1617
1957
  }
1618
1958
  function withContextOverrides(normalized, context) {
1619
1959
  if (!context?.table && !context?.operation) {
@@ -1626,7 +1966,7 @@ function withContextOverrides(normalized, context) {
1626
1966
  };
1627
1967
  }
1628
1968
  function resolveAttachedNormalizedError(resultOrError) {
1629
- if (!isRecord3(resultOrError)) return void 0;
1969
+ if (!isRecord4(resultOrError)) return void 0;
1630
1970
  if (!("__athenaNormalizedError" in resultOrError)) return void 0;
1631
1971
  const candidate = resultOrError.__athenaNormalizedError;
1632
1972
  return isNormalizedAthenaError(candidate) ? candidate : void 0;
@@ -1645,7 +1985,7 @@ function contextHint(context) {
1645
1985
  return `Identity: ${identity}`;
1646
1986
  }
1647
1987
  function isAthenaResultLike(value) {
1648
- return isRecord3(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
1988
+ return isRecord4(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
1649
1989
  }
1650
1990
  function operationFromDetails(details) {
1651
1991
  if (!details?.endpoint) return void 0;
@@ -1742,15 +2082,16 @@ function toAthenaGatewayError(source, fallbackMessage, context) {
1742
2082
  return source;
1743
2083
  }
1744
2084
  if (isAthenaResultLike(source) && source.errorDetails) {
2085
+ const message2 = messageFromUnknownError(source.error) ?? source.errorDetails.message ?? fallbackMessage;
1745
2086
  return new AthenaGatewayError({
1746
2087
  code: source.errorDetails.code,
1747
- message: source.error ?? source.errorDetails.message,
2088
+ message: message2,
1748
2089
  status: source.status,
1749
2090
  endpoint: source.errorDetails.endpoint,
1750
2091
  method: source.errorDetails.method,
1751
2092
  requestId: source.errorDetails.requestId,
1752
- hint: source.errorDetails.hint,
1753
- cause: source.errorDetails.cause
2093
+ hint: (isRecord4(source.error) ? firstNonEmptyString(source.error.hint) : void 0) ?? source.errorDetails.hint,
2094
+ cause: (isRecord4(source.error) ? firstNonEmptyString(source.error.cause) : void 0) ?? source.errorDetails.cause
1754
2095
  });
1755
2096
  }
1756
2097
  const normalized = normalizeAthenaError(source, context);
@@ -1772,13 +2113,50 @@ function normalizeAthenaError(resultOrError, context) {
1772
2113
  return withContextOverrides(attached, context);
1773
2114
  }
1774
2115
  if (isAthenaResultLike(resultOrError)) {
2116
+ if (isAthenaResultErrorLike(resultOrError.error)) {
2117
+ return {
2118
+ kind: resultOrError.error.kind ?? classifyKind(resultOrError.status, gatewayCodeFromUnknownError(resultOrError.error), resultOrError.error.message),
2119
+ code: resultOrError.error.athenaCode ?? toAthenaErrorCode(
2120
+ resultOrError.error.kind ?? classifyKind(
2121
+ resultOrError.status,
2122
+ gatewayCodeFromUnknownError(resultOrError.error),
2123
+ resultOrError.error.message
2124
+ ),
2125
+ resultOrError.error.status ?? resultOrError.status,
2126
+ gatewayCodeFromUnknownError(resultOrError.error)
2127
+ ),
2128
+ category: resultOrError.error.category ?? toAthenaErrorCategory(
2129
+ resultOrError.error.kind ?? classifyKind(
2130
+ resultOrError.status,
2131
+ gatewayCodeFromUnknownError(resultOrError.error),
2132
+ resultOrError.error.message
2133
+ ),
2134
+ resultOrError.error.status ?? resultOrError.status
2135
+ ),
2136
+ retryable: resultOrError.error.retryable ?? isRetryable(
2137
+ resultOrError.error.kind ?? classifyKind(
2138
+ resultOrError.status,
2139
+ gatewayCodeFromUnknownError(resultOrError.error),
2140
+ resultOrError.error.message
2141
+ ),
2142
+ resultOrError.error.status ?? resultOrError.status
2143
+ ),
2144
+ status: resultOrError.error.status ?? resultOrError.status,
2145
+ constraint: resultOrError.error.constraint,
2146
+ table: context?.table ?? resultOrError.error.table,
2147
+ operation: context?.operation ?? resultOrError.error.operation,
2148
+ message: resultOrError.error.message,
2149
+ raw: resultOrError.error.raw ?? resultOrError.raw
2150
+ };
2151
+ }
1775
2152
  const details = resultOrError.errorDetails;
1776
- const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
2153
+ const message2 = messageFromUnknownError(resultOrError.error) ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
1777
2154
  const operation = context?.operation ?? operationFromDetails(details);
1778
2155
  const table = context?.table ?? extractTable(message2);
1779
2156
  const constraint = extractConstraint(message2);
1780
- const kind2 = classifyKind(resultOrError.status, details?.code, message2);
1781
- const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
2157
+ const gatewayCode = details?.code ?? gatewayCodeFromUnknownError(resultOrError.error);
2158
+ const kind2 = classifyKind(resultOrError.status, gatewayCode, message2);
2159
+ const code = toAthenaErrorCode(kind2, resultOrError.status, gatewayCode);
1782
2160
  const category = toAthenaErrorCategory(kind2, resultOrError.status);
1783
2161
  return {
1784
2162
  kind: kind2,
@@ -1815,7 +2193,7 @@ function normalizeAthenaError(resultOrError, context) {
1815
2193
  };
1816
2194
  }
1817
2195
  if (resultOrError instanceof Error) {
1818
- const maybeStatus = isRecord3(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
2196
+ const maybeStatus = isRecord4(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
1819
2197
  const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
1820
2198
  return {
1821
2199
  kind: kind2,
@@ -2032,45 +2410,527 @@ function createDbModule(input) {
2032
2410
  return db;
2033
2411
  }
2034
2412
 
2413
+ // src/query-ast.ts
2414
+ 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;
2415
+ var FILTER_OPERATORS = /* @__PURE__ */ new Set([
2416
+ "eq",
2417
+ "neq",
2418
+ "gt",
2419
+ "gte",
2420
+ "lt",
2421
+ "lte",
2422
+ "like",
2423
+ "ilike",
2424
+ "is",
2425
+ "in",
2426
+ "contains",
2427
+ "containedBy"
2428
+ ]);
2429
+ var BOOLEAN_SAFE_OPERATORS = /* @__PURE__ */ new Set([
2430
+ "eq",
2431
+ "neq",
2432
+ "gt",
2433
+ "gte",
2434
+ "lt",
2435
+ "lte",
2436
+ "like",
2437
+ "ilike",
2438
+ "is"
2439
+ ]);
2440
+ function isRecord5(value) {
2441
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2442
+ }
2443
+ function isUuidString(value) {
2444
+ return UUID_PATTERN.test(value.trim());
2445
+ }
2446
+ function isUuidIdentifierColumn(column) {
2447
+ return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
2448
+ }
2449
+ function shouldUseUuidTextComparison(column, value) {
2450
+ return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
2451
+ }
2452
+ function isRelationSelectNode(value) {
2453
+ return isRecord5(value) && isRecord5(value.select);
2454
+ }
2455
+ function normalizeIdentifier(value, label) {
2456
+ const normalized = value.trim();
2457
+ if (!normalized) {
2458
+ throw new Error(`${label} must be a non-empty string`);
2459
+ }
2460
+ return normalized;
2461
+ }
2462
+ function stringifyFilterValue(value) {
2463
+ if (Array.isArray(value)) {
2464
+ return value.join(",");
2465
+ }
2466
+ return String(value);
2467
+ }
2468
+ function buildGatewayCondition(operator, column, value) {
2469
+ const condition = { operator };
2470
+ if (column) {
2471
+ condition.column = column;
2472
+ if (operator === "eq") {
2473
+ condition.eq_column = column;
2474
+ }
2475
+ }
2476
+ if (value !== void 0) {
2477
+ condition.value = value;
2478
+ if (operator === "eq") {
2479
+ condition.eq_value = value;
2480
+ }
2481
+ }
2482
+ if (operator === "eq" && column && value !== void 0 && shouldUseUuidTextComparison(column, value)) {
2483
+ condition.column_cast = "text";
2484
+ condition.eq_column_cast = "text";
2485
+ }
2486
+ return condition;
2487
+ }
2488
+ function compileRelationToken(key, node) {
2489
+ const nested = compileSelectShape(node.select);
2490
+ const propertyKey = normalizeIdentifier(key, "select relation key");
2491
+ const relationToken = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
2492
+ const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
2493
+ const prefix = alias ? `${alias}:` : "";
2494
+ return `${prefix}${relationToken}(${nested})`;
2495
+ }
2496
+ function compileSelectShape(select) {
2497
+ if (!isRecord5(select)) {
2498
+ throw new Error("findMany select must be an object");
2499
+ }
2500
+ const tokens = [];
2501
+ for (const [rawKey, rawValue] of Object.entries(select)) {
2502
+ if (rawValue === void 0) {
2503
+ continue;
2504
+ }
2505
+ if (rawValue === true) {
2506
+ tokens.push(normalizeIdentifier(rawKey, "select column"));
2507
+ continue;
2508
+ }
2509
+ if (isRelationSelectNode(rawValue)) {
2510
+ tokens.push(compileRelationToken(rawKey, rawValue));
2511
+ continue;
2512
+ }
2513
+ throw new Error(`Unsupported select node for "${rawKey}"`);
2514
+ }
2515
+ if (tokens.length === 0) {
2516
+ throw new Error("findMany select requires at least one field");
2517
+ }
2518
+ return tokens.join(",");
2519
+ }
2520
+ function compileColumnWhere(column, input) {
2521
+ const normalizedColumn = normalizeIdentifier(column, "where column");
2522
+ if (!isRecord5(input)) {
2523
+ return [buildGatewayCondition("eq", normalizedColumn, input)];
2524
+ }
2525
+ const conditions = [];
2526
+ for (const [rawOperator, rawValue] of Object.entries(input)) {
2527
+ if (rawValue === void 0) {
2528
+ continue;
2529
+ }
2530
+ if (!FILTER_OPERATORS.has(rawOperator)) {
2531
+ throw new Error(`Unsupported where operator "${rawOperator}" on "${normalizedColumn}"`);
2532
+ }
2533
+ if ((rawOperator === "in" || rawOperator === "contains" || rawOperator === "containedBy") && !Array.isArray(rawValue)) {
2534
+ throw new Error(`where.${normalizedColumn}.${rawOperator} requires an array value`);
2535
+ }
2536
+ conditions.push(
2537
+ buildGatewayCondition(
2538
+ rawOperator,
2539
+ normalizedColumn,
2540
+ rawValue
2541
+ )
2542
+ );
2543
+ }
2544
+ if (conditions.length === 0) {
2545
+ throw new Error(`where.${normalizedColumn} requires at least one operator`);
2546
+ }
2547
+ return conditions;
2548
+ }
2549
+ function compileBooleanExpressionTerms(clause, label) {
2550
+ if (!isRecord5(clause)) {
2551
+ throw new Error(`findMany where.${label} clauses must be objects`);
2552
+ }
2553
+ const entries = Object.entries(clause).filter(([, value]) => value !== void 0);
2554
+ if (entries.length !== 1) {
2555
+ throw new Error(`findMany where.${label} clauses must target exactly one column`);
2556
+ }
2557
+ const [rawColumn, rawValue] = entries[0];
2558
+ const column = normalizeIdentifier(rawColumn, `where.${label} column`);
2559
+ if (!isRecord5(rawValue)) {
2560
+ return [`${column}.eq.${stringifyFilterValue(rawValue)}`];
2561
+ }
2562
+ const operatorEntries = Object.entries(rawValue).filter(([, value]) => value !== void 0);
2563
+ if (operatorEntries.length === 0) {
2564
+ throw new Error(`findMany where.${label}.${column} requires at least one operator`);
2565
+ }
2566
+ if (label === "not" && operatorEntries.length > 1) {
2567
+ throw new Error("findMany where.not only supports a single lossless operator expression");
2568
+ }
2569
+ return operatorEntries.map(([rawOperator, rawOperand]) => {
2570
+ if (!BOOLEAN_SAFE_OPERATORS.has(rawOperator)) {
2571
+ throw new Error(`findMany where.${label} only supports lossless scalar operators`);
2572
+ }
2573
+ if (Array.isArray(rawOperand)) {
2574
+ throw new Error(`findMany where.${label} does not support array-valued operators`);
2575
+ }
2576
+ return `${column}.${rawOperator}.${stringifyFilterValue(rawOperand)}`;
2577
+ });
2578
+ }
2579
+ function compileWhere(where) {
2580
+ if (where === void 0) {
2581
+ return void 0;
2582
+ }
2583
+ if (!isRecord5(where)) {
2584
+ throw new Error("findMany where must be an object");
2585
+ }
2586
+ const conditions = [];
2587
+ for (const [rawKey, rawValue] of Object.entries(where)) {
2588
+ if (rawValue === void 0) {
2589
+ continue;
2590
+ }
2591
+ if (rawKey === "or") {
2592
+ if (!Array.isArray(rawValue) || rawValue.length === 0) {
2593
+ throw new Error("findMany where.or must be a non-empty array");
2594
+ }
2595
+ const expressions = rawValue.flatMap(
2596
+ (value) => compileBooleanExpressionTerms(value, "or")
2597
+ );
2598
+ conditions.push(buildGatewayCondition("or", void 0, expressions.join(",")));
2599
+ continue;
2600
+ }
2601
+ if (rawKey === "not") {
2602
+ const expressions = compileBooleanExpressionTerms(rawValue, "not");
2603
+ if (expressions.length !== 1) {
2604
+ throw new Error("findMany where.not must compile to exactly one lossless expression");
2605
+ }
2606
+ conditions.push(buildGatewayCondition("not", void 0, expressions[0]));
2607
+ continue;
2608
+ }
2609
+ conditions.push(...compileColumnWhere(rawKey, rawValue));
2610
+ }
2611
+ return conditions.length > 0 ? conditions : void 0;
2612
+ }
2613
+ function resolveOrderDirection(input) {
2614
+ if (typeof input === "boolean") {
2615
+ return input === false ? "descending" : "ascending";
2616
+ }
2617
+ if (typeof input === "string") {
2618
+ const normalized = input.trim().toLowerCase();
2619
+ if (normalized === "asc" || normalized === "ascending") {
2620
+ return "ascending";
2621
+ }
2622
+ if (normalized === "desc" || normalized === "descending") {
2623
+ return "descending";
2624
+ }
2625
+ throw new Error(`Unsupported orderBy direction "${input}"`);
2626
+ }
2627
+ return input.ascending === false ? "descending" : "ascending";
2628
+ }
2629
+ function compileOrderBy(orderBy) {
2630
+ if (orderBy === void 0) {
2631
+ return void 0;
2632
+ }
2633
+ if (!isRecord5(orderBy)) {
2634
+ throw new Error("findMany orderBy must be an object");
2635
+ }
2636
+ if ("column" in orderBy) {
2637
+ return {
2638
+ field: normalizeIdentifier(String(orderBy.column), "orderBy column"),
2639
+ direction: orderBy.ascending === false ? "descending" : "ascending"
2640
+ };
2641
+ }
2642
+ const entries = Object.entries(orderBy).filter(([, value]) => value !== void 0);
2643
+ if (entries.length === 0) {
2644
+ return void 0;
2645
+ }
2646
+ if (entries.length > 1) {
2647
+ throw new Error("findMany orderBy only supports a single column in v1");
2648
+ }
2649
+ const [column, input] = entries[0];
2650
+ return {
2651
+ field: normalizeIdentifier(column, "orderBy column"),
2652
+ direction: resolveOrderDirection(input)
2653
+ };
2654
+ }
2655
+
2035
2656
  // src/client.ts
2036
2657
  var DEFAULT_COLUMNS = "*";
2037
- 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;
2038
2658
  var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
2039
2659
  var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
2660
+ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
2661
+ "src\\client.ts",
2662
+ "src/client.ts",
2663
+ "dist\\client.",
2664
+ "dist/client.",
2665
+ "node_modules\\@xylex-group\\athena",
2666
+ "node_modules/@xylex-group/athena",
2667
+ "node:internal",
2668
+ "internal/process"
2669
+ ];
2670
+ function canUseFindManyAstTransport(state) {
2671
+ return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
2672
+ }
2673
+ function toFindManyAstOrder(order) {
2674
+ if (!order) {
2675
+ return void 0;
2676
+ }
2677
+ return {
2678
+ column: order.field,
2679
+ ascending: order.direction !== "descending"
2680
+ };
2681
+ }
2040
2682
  function formatResult(response) {
2041
2683
  const result = {
2042
2684
  data: response.data ?? null,
2043
- error: response.error ?? null,
2685
+ error: null,
2044
2686
  errorDetails: response.errorDetails ?? null,
2045
2687
  status: response.status,
2688
+ statusText: response.statusText ?? null,
2046
2689
  raw: response.raw
2047
2690
  };
2048
- if (response.count !== void 0) {
2049
- result.count = response.count;
2050
- }
2051
- return result;
2052
- }
2053
- function attachNormalizedError(result, normalizedError) {
2054
- Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
2055
- value: normalizedError,
2056
- enumerable: false,
2057
- configurable: true,
2058
- writable: false
2059
- });
2691
+ if (response.count !== void 0) {
2692
+ result.count = response.count;
2693
+ }
2694
+ return result;
2695
+ }
2696
+ function attachNormalizedError(result, normalizedError) {
2697
+ Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
2698
+ value: normalizedError,
2699
+ enumerable: false,
2700
+ configurable: true,
2701
+ writable: false
2702
+ });
2703
+ }
2704
+ function createResultFormatter(experimental) {
2705
+ return (response, context) => {
2706
+ const result = formatResult(response);
2707
+ if (response.error == null && response.errorDetails == null) {
2708
+ return result;
2709
+ }
2710
+ const normalizedError = normalizeAthenaError(
2711
+ {
2712
+ ...result,
2713
+ error: response.error ?? response.errorDetails?.message ?? null
2714
+ },
2715
+ context
2716
+ );
2717
+ result.error = createResultError(response, result, normalizedError);
2718
+ attachNormalizedError(result, normalizedError);
2719
+ return result;
2720
+ };
2721
+ }
2722
+ function isRecord6(value) {
2723
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2724
+ }
2725
+ function firstNonEmptyString2(...values) {
2726
+ for (const value of values) {
2727
+ if (typeof value === "string" && value.trim().length > 0) {
2728
+ return value.trim();
2729
+ }
2730
+ }
2731
+ return void 0;
2732
+ }
2733
+ function resolveStructuredErrorPayload2(raw) {
2734
+ if (!isRecord6(raw)) return null;
2735
+ return isRecord6(raw.error) ? raw.error : raw;
2736
+ }
2737
+ function resolveStructuredErrorDetails(payload, message) {
2738
+ if (!payload || !("details" in payload)) {
2739
+ return null;
2740
+ }
2741
+ const details = payload.details;
2742
+ if (details == null) {
2743
+ return null;
2744
+ }
2745
+ if (typeof details === "string" && details.trim() === message.trim()) {
2746
+ return null;
2747
+ }
2748
+ return details;
2749
+ }
2750
+ function createResultError(response, result, normalized) {
2751
+ const rawRecord = isRecord6(response.raw) ? response.raw : null;
2752
+ const payload = resolveStructuredErrorPayload2(response.raw);
2753
+ const message = firstNonEmptyString2(
2754
+ response.error,
2755
+ payload?.message,
2756
+ payload?.error,
2757
+ payload?.details,
2758
+ response.errorDetails?.message,
2759
+ normalized.message
2760
+ ) ?? normalized.message;
2761
+ const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
2762
+ const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
2763
+ const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
2764
+ const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
2765
+ return {
2766
+ message,
2767
+ code,
2768
+ athenaCode: normalized.code,
2769
+ gatewayCode: response.errorDetails?.code ?? null,
2770
+ kind: normalized.kind,
2771
+ category: normalized.category,
2772
+ retryable: normalized.retryable,
2773
+ details,
2774
+ hint,
2775
+ status: result.status,
2776
+ statusText,
2777
+ constraint: normalized.constraint,
2778
+ table: normalized.table,
2779
+ operation: normalized.operation,
2780
+ endpoint: response.errorDetails?.endpoint,
2781
+ method: response.errorDetails?.method,
2782
+ requestId: response.errorDetails?.requestId,
2783
+ cause: response.errorDetails?.cause,
2784
+ raw: result.raw
2785
+ };
2786
+ }
2787
+ function parseQueryTraceCallsiteFrame(frame) {
2788
+ const trimmed = frame.trim();
2789
+ if (!trimmed) {
2790
+ return null;
2791
+ }
2792
+ let body = trimmed.replace(/^at\s+/, "");
2793
+ if (body.startsWith("async ")) {
2794
+ body = body.slice(6);
2795
+ }
2796
+ let functionName;
2797
+ let location = body;
2798
+ const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
2799
+ if (wrappedMatch) {
2800
+ functionName = wrappedMatch[1].trim() || void 0;
2801
+ location = wrappedMatch[2].trim();
2802
+ }
2803
+ const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
2804
+ if (!locationMatch) {
2805
+ return null;
2806
+ }
2807
+ const filePath = locationMatch[1].replace(/^file:\/\//, "");
2808
+ const line = Number(locationMatch[2]);
2809
+ const column = Number(locationMatch[3]);
2810
+ if (!Number.isFinite(line) || !Number.isFinite(column)) {
2811
+ return null;
2812
+ }
2813
+ const normalizedPath = filePath.replace(/\\/g, "/");
2814
+ const fileName = normalizedPath.split("/").at(-1) ?? filePath;
2815
+ return {
2816
+ filePath,
2817
+ fileName,
2818
+ line,
2819
+ column,
2820
+ frame: trimmed,
2821
+ functionName
2822
+ };
2823
+ }
2824
+ function captureQueryTraceCallsite() {
2825
+ const stack = new Error().stack;
2826
+ if (!stack) return null;
2827
+ const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
2828
+ for (const frame of frames) {
2829
+ if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
2830
+ continue;
2831
+ }
2832
+ const callsite = parseQueryTraceCallsiteFrame(frame);
2833
+ if (callsite) return callsite;
2834
+ }
2835
+ const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
2836
+ return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
2837
+ }
2838
+ function defaultQueryTraceLogger(event) {
2839
+ const target = event.table ?? event.functionName ?? "gateway";
2840
+ const outcomeState = event.outcome?.error ? "error" : "ok";
2841
+ const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
2842
+ console.info(banner, event);
2843
+ }
2844
+ function captureTraceCallsite(tracer) {
2845
+ return tracer?.captureCallsite() ?? null;
2846
+ }
2847
+ function createTraceCallsiteStore(tracer, initialCallsite) {
2848
+ let storedCallsite = initialCallsite ?? void 0;
2849
+ return {
2850
+ resolve(callsite) {
2851
+ if (callsite) {
2852
+ storedCallsite = callsite;
2853
+ return callsite;
2854
+ }
2855
+ if (storedCallsite !== void 0) {
2856
+ return storedCallsite;
2857
+ }
2858
+ const capturedCallsite = captureTraceCallsite(tracer);
2859
+ if (capturedCallsite) {
2860
+ storedCallsite = capturedCallsite;
2861
+ }
2862
+ return capturedCallsite;
2863
+ }
2864
+ };
2865
+ }
2866
+ function createQueryTracer(experimental) {
2867
+ const traceOption = experimental?.traceQueries;
2868
+ if (!traceOption) {
2869
+ return void 0;
2870
+ }
2871
+ const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
2872
+ const emit = (event) => {
2873
+ try {
2874
+ logger(event);
2875
+ } catch (error) {
2876
+ console.warn("[athena-js][trace] logger failed", error);
2877
+ }
2878
+ };
2879
+ return {
2880
+ captureCallsite: captureQueryTraceCallsite,
2881
+ publishSuccess(context, result, durationMs, callsite) {
2882
+ emit({
2883
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2884
+ durationMs,
2885
+ operation: context.operation,
2886
+ endpoint: context.endpoint,
2887
+ table: context.table,
2888
+ functionName: context.functionName,
2889
+ sql: context.sql,
2890
+ payload: context.payload,
2891
+ options: context.options,
2892
+ callsite,
2893
+ outcome: {
2894
+ status: result.status,
2895
+ error: result.error,
2896
+ errorDetails: result.errorDetails ?? null,
2897
+ count: result.count ?? null,
2898
+ data: result.data,
2899
+ raw: result.raw
2900
+ }
2901
+ });
2902
+ },
2903
+ publishFailure(context, error, durationMs, callsite) {
2904
+ emit({
2905
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2906
+ durationMs,
2907
+ operation: context.operation,
2908
+ endpoint: context.endpoint,
2909
+ table: context.table,
2910
+ functionName: context.functionName,
2911
+ sql: context.sql,
2912
+ payload: context.payload,
2913
+ options: context.options,
2914
+ callsite,
2915
+ thrownError: error
2916
+ });
2917
+ }
2918
+ };
2060
2919
  }
2061
- function createResultFormatter(experimental) {
2062
- if (!experimental?.enableErrorNormalization) {
2063
- return formatResult;
2920
+ async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
2921
+ if (!tracer) {
2922
+ return runner();
2064
2923
  }
2065
- return (response, context) => {
2066
- const result = formatResult(response);
2067
- if (result.error == null) {
2068
- return result;
2069
- }
2070
- const normalizedError = normalizeAthenaError(result, context);
2071
- attachNormalizedError(result, normalizedError);
2924
+ const callsite = callsiteOverride ?? tracer.captureCallsite();
2925
+ const startedAt = Date.now();
2926
+ try {
2927
+ const result = await runner();
2928
+ tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
2072
2929
  return result;
2073
- };
2930
+ } catch (error) {
2931
+ tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
2932
+ throw error;
2933
+ }
2074
2934
  }
2075
2935
  function toSingleResult(response) {
2076
2936
  const payload = response.data;
@@ -2092,15 +2952,16 @@ function asAthenaJsonObject(value) {
2092
2952
  function asAthenaJsonObjectArray(values) {
2093
2953
  return values;
2094
2954
  }
2095
- function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2955
+ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
2096
2956
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
2097
2957
  let selectedOptions;
2098
2958
  let promise = null;
2099
- const run = (columns, options) => {
2959
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
2960
+ const run = (columns, options, callsite) => {
2100
2961
  const payloadColumns = columns ?? selectedColumns;
2101
2962
  const payloadOptions = options ?? selectedOptions;
2102
2963
  if (!promise) {
2103
- promise = executor(payloadColumns, payloadOptions);
2964
+ promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
2104
2965
  }
2105
2966
  return promise;
2106
2967
  };
@@ -2108,7 +2969,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2108
2969
  select(columns = selectedColumns, options) {
2109
2970
  selectedColumns = columns;
2110
2971
  selectedOptions = options ?? selectedOptions;
2111
- return run(columns, options);
2972
+ return run(columns, options, captureTraceCallsite(tracer));
2112
2973
  },
2113
2974
  returning(columns = selectedColumns, options) {
2114
2975
  return mutationQuery.select(columns, options);
@@ -2116,7 +2977,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2116
2977
  single(columns = selectedColumns, options) {
2117
2978
  selectedColumns = columns;
2118
2979
  selectedOptions = options ?? selectedOptions;
2119
- return run(columns, options).then(toSingleResult);
2980
+ return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
2120
2981
  },
2121
2982
  maybeSingle(columns = selectedColumns, options) {
2122
2983
  return mutationQuery.single(columns, options);
@@ -2139,21 +3000,12 @@ function getResourceId(state) {
2139
3000
  );
2140
3001
  return candidate?.value?.toString();
2141
3002
  }
2142
- function stringifyFilterValue(value) {
3003
+ function stringifyFilterValue2(value) {
2143
3004
  if (Array.isArray(value)) {
2144
3005
  return value.join(",");
2145
3006
  }
2146
3007
  return String(value);
2147
3008
  }
2148
- function isUuidString(value) {
2149
- return UUID_PATTERN.test(value.trim());
2150
- }
2151
- function isUuidIdentifierColumn(column) {
2152
- return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
2153
- }
2154
- function shouldUseUuidTextComparison(column, value) {
2155
- return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
2156
- }
2157
3009
  function normalizeCast(cast) {
2158
3010
  const normalized = cast.trim().toLowerCase();
2159
3011
  if (!SAFE_CAST_PATTERN.test(normalized)) {
@@ -2176,25 +3028,92 @@ function withCast(expression, cast) {
2176
3028
  }
2177
3029
  function buildSelectColumnsClause(columns) {
2178
3030
  if (Array.isArray(columns)) {
2179
- return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
3031
+ return columns.map((column) => quoteSelectColumnToken(column)).join(", ");
2180
3032
  }
2181
3033
  return quoteSelectColumnsExpression(columns);
2182
3034
  }
3035
+ function parseIdentifierSegment(input) {
3036
+ const trimmed = input.trim();
3037
+ if (!trimmed) return null;
3038
+ if (!trimmed.startsWith('"')) {
3039
+ return {
3040
+ normalizedValue: trimmed.toLowerCase()
3041
+ };
3042
+ }
3043
+ let value = "";
3044
+ let index = 1;
3045
+ let closed = false;
3046
+ while (index < trimmed.length) {
3047
+ const char = trimmed[index];
3048
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
3049
+ if (char === '"' && next === '"') {
3050
+ value += '"';
3051
+ index += 2;
3052
+ continue;
3053
+ }
3054
+ if (char === '"') {
3055
+ closed = true;
3056
+ index += 1;
3057
+ break;
3058
+ }
3059
+ value += char;
3060
+ index += 1;
3061
+ }
3062
+ if (!closed || trimmed.slice(index).trim().length > 0 || !value.trim()) {
3063
+ return null;
3064
+ }
3065
+ return {
3066
+ normalizedValue: value
3067
+ };
3068
+ }
3069
+ function splitQualifiedTableName(tableName) {
3070
+ const trimmed = tableName.trim();
3071
+ let inQuotes = false;
3072
+ for (let index = 0; index < trimmed.length; index += 1) {
3073
+ const char = trimmed[index];
3074
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
3075
+ if (char === '"') {
3076
+ if (inQuotes && next === '"') {
3077
+ index += 1;
3078
+ continue;
3079
+ }
3080
+ inQuotes = !inQuotes;
3081
+ continue;
3082
+ }
3083
+ if (char === "." && !inQuotes) {
3084
+ const schemaSegment = trimmed.slice(0, index).trim();
3085
+ const tableSegment = trimmed.slice(index + 1).trim();
3086
+ if (!schemaSegment || !tableSegment) {
3087
+ return null;
3088
+ }
3089
+ return { schemaSegment };
3090
+ }
3091
+ }
3092
+ return null;
3093
+ }
2183
3094
  function resolveTableNameForCall(tableName, schema) {
2184
3095
  if (!schema) return tableName;
2185
3096
  const normalizedSchema = schema.trim();
2186
3097
  if (!normalizedSchema) {
2187
3098
  throw new Error("schema option must be a non-empty string");
2188
3099
  }
2189
- if (tableName.includes(".")) {
2190
- if (tableName.startsWith(`${normalizedSchema}.`)) {
2191
- return tableName;
3100
+ const normalizedTableName = tableName.trim();
3101
+ const parsedSchema = parseIdentifierSegment(normalizedSchema);
3102
+ if (!parsedSchema) {
3103
+ throw new Error("schema option must be a non-empty string");
3104
+ }
3105
+ const qualified = splitQualifiedTableName(normalizedTableName);
3106
+ if (qualified) {
3107
+ const parsedTableSchema = parseIdentifierSegment(qualified.schemaSegment);
3108
+ const sameSchema = parsedTableSchema ? parsedTableSchema.normalizedValue === parsedSchema.normalizedValue : normalizedTableName.startsWith(`${normalizedSchema}.`);
3109
+ if (sameSchema) {
3110
+ return normalizedTableName;
2192
3111
  }
2193
3112
  throw new Error(
2194
- `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
3113
+ `schema option "${normalizedSchema}" conflicts with schema-qualified table "${normalizedTableName}"`
2195
3114
  );
2196
3115
  }
2197
- return `${normalizedSchema}.${tableName}`;
3116
+ return `${normalizedSchema}.${normalizedTableName}`;
2198
3117
  }
2199
3118
  function conditionToSqlClause(condition) {
2200
3119
  if (!condition.column) return null;
@@ -2272,6 +3191,237 @@ function buildTypedSelectQuery(input) {
2272
3191
  }
2273
3192
  return `${sqlParts.join(" ")};`;
2274
3193
  }
3194
+ function sanitizeSqlComment(comment) {
3195
+ return comment.replace(/\*\//g, "* /");
3196
+ }
3197
+ function toSqlJsonLiteral(value) {
3198
+ if (value === void 0) return "DEFAULT";
3199
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3200
+ return toSqlLiteral(value);
3201
+ }
3202
+ return `'${escapeSqlStringLiteral(JSON.stringify(value))}'::jsonb`;
3203
+ }
3204
+ function conditionToDebugSqlClause(condition) {
3205
+ const exact = conditionToSqlClause(condition);
3206
+ if (exact) return exact;
3207
+ const rawCondition = sanitizeSqlComment(JSON.stringify(condition));
3208
+ if (!condition.column) {
3209
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
3210
+ }
3211
+ const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
3212
+ const value = condition.value;
3213
+ const rhs = withCast(toSqlJsonLiteral(value), condition.value_cast);
3214
+ switch (condition.operator) {
3215
+ case "contains":
3216
+ return `${column} @> ${rhs}`;
3217
+ case "containedBy":
3218
+ return `${column} <@ ${rhs}`;
3219
+ case "not":
3220
+ return `TRUE /* NOT expression passthrough: ${rawCondition} */`;
3221
+ case "or":
3222
+ return `TRUE /* OR expression passthrough: ${rawCondition} */`;
3223
+ default:
3224
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
3225
+ }
3226
+ }
3227
+ function resolvePagination(input) {
3228
+ let limit = input.limit;
3229
+ let offset = input.offset;
3230
+ if (limit === void 0 && input.pageSize !== void 0) {
3231
+ limit = input.pageSize;
3232
+ }
3233
+ if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
3234
+ offset = (input.currentPage - 1) * input.pageSize;
3235
+ }
3236
+ return { limit, offset };
3237
+ }
3238
+ function appendOrderLimitOffset(sqlParts, order, limit, offset) {
3239
+ if (order?.field) {
3240
+ const direction = order.direction === "descending" ? "DESC" : "ASC";
3241
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(order.field)} ${direction}`);
3242
+ }
3243
+ if (limit !== void 0) {
3244
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
3245
+ }
3246
+ if (offset !== void 0) {
3247
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
3248
+ }
3249
+ }
3250
+ function buildDebugSelectQuery(input) {
3251
+ const sqlParts = [
3252
+ `SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
3253
+ ];
3254
+ if (input.conditions?.length) {
3255
+ const whereClauses = input.conditions.map(conditionToDebugSqlClause);
3256
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
3257
+ }
3258
+ const pagination = resolvePagination(input);
3259
+ appendOrderLimitOffset(sqlParts, input.order, pagination.limit, pagination.offset);
3260
+ return `${sqlParts.join(" ")};`;
3261
+ }
3262
+ function resolveDebugTableIdentifier(tableName) {
3263
+ if (!tableName?.trim()) {
3264
+ return '"__unknown_table__"';
3265
+ }
3266
+ return quoteQualifiedIdentifier(tableName);
3267
+ }
3268
+ function buildInsertDebugSql(payload) {
3269
+ const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
3270
+ const columns = [];
3271
+ const seen = /* @__PURE__ */ new Set();
3272
+ for (const row of rows) {
3273
+ for (const column of Object.keys(row)) {
3274
+ if (seen.has(column)) continue;
3275
+ seen.add(column);
3276
+ columns.push(column);
3277
+ }
3278
+ }
3279
+ const sqlParts = [`INSERT INTO ${quoteQualifiedIdentifier(payload.table_name)}`];
3280
+ if (!rows.length || !columns.length) {
3281
+ sqlParts.push("DEFAULT VALUES");
3282
+ if (rows.length > 1) {
3283
+ sqlParts.push(`/* trace: ${rows.length} rows collapsed to DEFAULT VALUES */`);
3284
+ }
3285
+ } else {
3286
+ const valuesClause = rows.map((row) => {
3287
+ const values = columns.map((column) => {
3288
+ const hasColumn = Object.prototype.hasOwnProperty.call(row, column);
3289
+ if (!hasColumn) {
3290
+ return payload.default_to_null ? "NULL" : "DEFAULT";
3291
+ }
3292
+ const rowValue = row[column];
3293
+ return toSqlJsonLiteral(rowValue);
3294
+ });
3295
+ return `(${values.join(", ")})`;
3296
+ }).join(", ");
3297
+ const columnClause = columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
3298
+ sqlParts.push(`(${columnClause})`);
3299
+ sqlParts.push(`VALUES ${valuesClause}`);
3300
+ }
3301
+ if (payload.on_conflict) {
3302
+ const conflictColumns = Array.isArray(payload.on_conflict) ? payload.on_conflict.map((column) => quoteQualifiedIdentifier(column)).join(", ") : payload.on_conflict;
3303
+ if (payload.update_body && Object.keys(payload.update_body).length > 0) {
3304
+ const assignments = Object.entries(payload.update_body).map(
3305
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
3306
+ );
3307
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO UPDATE SET ${assignments.join(", ")}`);
3308
+ } else {
3309
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO NOTHING`);
3310
+ }
3311
+ }
3312
+ if (payload.columns) {
3313
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
3314
+ }
3315
+ return `${sqlParts.join(" ")};`;
3316
+ }
3317
+ function buildUpdateDebugSql(payload) {
3318
+ const set = payload.set ?? payload.data ?? {};
3319
+ const assignments = Object.entries(set).map(
3320
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
3321
+ );
3322
+ const sqlParts = [
3323
+ `UPDATE ${resolveDebugTableIdentifier(payload.table_name)} SET ${assignments.length ? assignments.join(", ") : "/* empty set */"}`
3324
+ ];
3325
+ if (payload.conditions?.length) {
3326
+ const whereClauses = payload.conditions.map(conditionToDebugSqlClause);
3327
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
3328
+ }
3329
+ const pagination = resolvePagination({
3330
+ currentPage: payload.current_page,
3331
+ pageSize: payload.page_size
3332
+ });
3333
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
3334
+ if (payload.columns) {
3335
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
3336
+ }
3337
+ return `${sqlParts.join(" ")};`;
3338
+ }
3339
+ function buildDeleteDebugSql(payload) {
3340
+ const sqlParts = [`DELETE FROM ${quoteQualifiedIdentifier(payload.table_name)}`];
3341
+ const whereClauses = [];
3342
+ if (payload.resource_id) {
3343
+ whereClauses.push(`"resource_id" = ${toSqlLiteral(payload.resource_id)}`);
3344
+ }
3345
+ if (payload.conditions?.length) {
3346
+ whereClauses.push(...payload.conditions.map(conditionToDebugSqlClause));
3347
+ }
3348
+ if (whereClauses.length) {
3349
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
3350
+ }
3351
+ const pagination = resolvePagination({
3352
+ currentPage: payload.current_page,
3353
+ pageSize: payload.page_size
3354
+ });
3355
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
3356
+ if (payload.columns) {
3357
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
3358
+ }
3359
+ return `${sqlParts.join(" ")};`;
3360
+ }
3361
+ function rpcFilterToSqlClause(filter) {
3362
+ const column = quoteQualifiedIdentifier(filter.column);
3363
+ const value = filter.value;
3364
+ switch (filter.operator) {
3365
+ case "eq":
3366
+ case "neq":
3367
+ case "gt":
3368
+ case "gte":
3369
+ case "lt":
3370
+ case "lte":
3371
+ case "like":
3372
+ case "ilike": {
3373
+ if (value === void 0 || Array.isArray(value)) {
3374
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
3375
+ }
3376
+ const operatorMap = {
3377
+ eq: "=",
3378
+ neq: "!=",
3379
+ gt: ">",
3380
+ gte: ">=",
3381
+ lt: "<",
3382
+ lte: "<=",
3383
+ like: "LIKE",
3384
+ ilike: "ILIKE"
3385
+ };
3386
+ return `${column} ${operatorMap[filter.operator]} ${toSqlLiteral(value)}`;
3387
+ }
3388
+ case "is":
3389
+ if (value === null) return `${column} IS NULL`;
3390
+ if (value === true) return `${column} IS TRUE`;
3391
+ if (value === false) return `${column} IS FALSE`;
3392
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
3393
+ case "in":
3394
+ if (!Array.isArray(value)) {
3395
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
3396
+ }
3397
+ if (value.length === 0) return "FALSE";
3398
+ return `${column} IN (${value.map((item) => toSqlLiteral(item)).join(", ")})`;
3399
+ default:
3400
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
3401
+ }
3402
+ }
3403
+ function buildRpcDebugSql(payload) {
3404
+ const argsEntries = payload.args ? Object.entries(payload.args) : [];
3405
+ const argsClause = argsEntries.map(([key, value]) => `${quoteQualifiedIdentifier(key)} => ${toSqlJsonLiteral(value)}`).join(", ");
3406
+ const functionRef = payload.schema ? `${quoteQualifiedIdentifier(payload.schema)}.${quoteQualifiedIdentifier(payload.function)}` : quoteQualifiedIdentifier(payload.function);
3407
+ const sqlParts = [
3408
+ `SELECT ${payload.select ? quoteSelectColumnsExpression(payload.select) : "*"} FROM ${functionRef}(${argsClause})`
3409
+ ];
3410
+ if (payload.filters?.length) {
3411
+ sqlParts.push(`WHERE ${payload.filters.map(rpcFilterToSqlClause).join(" AND ")}`);
3412
+ }
3413
+ if (payload.order?.column) {
3414
+ const direction = payload.order.ascending === false ? "DESC" : "ASC";
3415
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(payload.order.column)} ${direction}`);
3416
+ }
3417
+ if (payload.limit !== void 0) {
3418
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(payload.limit))}`);
3419
+ }
3420
+ if (payload.offset !== void 0) {
3421
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(payload.offset))}`);
3422
+ }
3423
+ return `${sqlParts.join(" ")};`;
3424
+ }
2275
3425
  function createFilterMethods(state, addCondition, self) {
2276
3426
  return {
2277
3427
  eq(column, value) {
@@ -2383,7 +3533,7 @@ function createFilterMethods(state, addCondition, self) {
2383
3533
  not(columnOrExpression, operator, value) {
2384
3534
  const expression = String(columnOrExpression);
2385
3535
  if (operator != null && value !== void 0) {
2386
- addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
3536
+ addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue2(value)}`);
2387
3537
  } else {
2388
3538
  addCondition("not", void 0, expression);
2389
3539
  }
@@ -2446,14 +3596,15 @@ function createRpcFilterMethods(filters, self) {
2446
3596
  }
2447
3597
  };
2448
3598
  }
2449
- function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
3599
+ function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
2450
3600
  const state = {
2451
3601
  filters: []
2452
3602
  };
2453
3603
  let selectedColumns;
2454
3604
  let selectedOptions;
2455
3605
  let promise = null;
2456
- const executeRpc = async (columns, options) => {
3606
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
3607
+ const executeRpc = async (columns, options, callsite) => {
2457
3608
  const mergedOptions = mergeOptions(baseOptions, options);
2458
3609
  const payload = {
2459
3610
  function: functionName,
@@ -2467,14 +3618,30 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
2467
3618
  offset: state.offset,
2468
3619
  order: state.order
2469
3620
  };
2470
- const response = await client.rpcGateway(payload, mergedOptions);
2471
- return formatGatewayResult(response, { operation: "rpc" });
3621
+ const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
3622
+ const sql = buildRpcDebugSql(payload);
3623
+ return executeWithQueryTrace(
3624
+ tracer,
3625
+ {
3626
+ operation: "rpc",
3627
+ endpoint,
3628
+ functionName,
3629
+ sql,
3630
+ payload,
3631
+ options: mergedOptions
3632
+ },
3633
+ async () => {
3634
+ const response = await client.rpcGateway(payload, mergedOptions);
3635
+ return formatGatewayResult(response, { operation: "rpc" });
3636
+ },
3637
+ callsite
3638
+ );
2472
3639
  };
2473
- const run = (columns, options) => {
3640
+ const run = (columns, options, callsite) => {
2474
3641
  const payloadColumns = columns ?? selectedColumns;
2475
3642
  const payloadOptions = options ?? selectedOptions;
2476
3643
  if (!promise) {
2477
- promise = executeRpc(payloadColumns, payloadOptions);
3644
+ promise = executeRpc(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
2478
3645
  }
2479
3646
  return promise;
2480
3647
  };
@@ -2484,10 +3651,10 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
2484
3651
  select(columns = selectedColumns, options) {
2485
3652
  selectedColumns = columns;
2486
3653
  selectedOptions = options ?? selectedOptions;
2487
- return run(columns, options);
3654
+ return run(columns, options, captureTraceCallsite(tracer));
2488
3655
  },
2489
3656
  async single(columns, options) {
2490
- const result = await run(columns, options);
3657
+ const result = await run(columns, options, captureTraceCallsite(tracer));
2491
3658
  return toSingleResult(result);
2492
3659
  },
2493
3660
  maybeSingle(columns, options) {
@@ -2522,7 +3689,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
2522
3689
  });
2523
3690
  return builder;
2524
3691
  }
2525
- function createTableBuilder(tableName, client, formatGatewayResult) {
3692
+ function createTableBuilder(tableName, client, formatGatewayResult, tracer, experimental) {
2526
3693
  const state = {
2527
3694
  conditions: []
2528
3695
  };
@@ -2554,15 +3721,24 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2554
3721
  }
2555
3722
  state.conditions.push(condition);
2556
3723
  };
3724
+ const snapshotState = () => ({
3725
+ conditions: state.conditions.map((condition) => ({ ...condition })),
3726
+ limit: state.limit,
3727
+ offset: state.offset,
3728
+ order: state.order ? { ...state.order } : void 0,
3729
+ currentPage: state.currentPage,
3730
+ pageSize: state.pageSize,
3731
+ totalPages: state.totalPages
3732
+ });
2557
3733
  const builder = {};
2558
3734
  const filterMethods = createFilterMethods(
2559
3735
  state,
2560
3736
  addCondition,
2561
3737
  builder
2562
3738
  );
2563
- const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
3739
+ const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
2564
3740
  const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
2565
- const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
3741
+ const conditions = executionState.conditions.length ? executionState.conditions.map((condition) => ({ ...condition })) : void 0;
2566
3742
  const hasTypedEqualityComparison = conditions?.some(
2567
3743
  (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
2568
3744
  ) ?? false;
@@ -2571,53 +3747,107 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2571
3747
  tableName: resolvedTableName,
2572
3748
  columns,
2573
3749
  conditions,
2574
- limit: state.limit,
2575
- offset: state.offset,
2576
- currentPage: state.currentPage,
2577
- pageSize: state.pageSize,
2578
- order: state.order
3750
+ limit: executionState.limit,
3751
+ offset: executionState.offset,
3752
+ currentPage: executionState.currentPage,
3753
+ pageSize: executionState.pageSize,
3754
+ order: executionState.order
2579
3755
  });
2580
3756
  if (query) {
2581
- const queryResponse = await client.queryGateway({ query }, options);
2582
- return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
3757
+ const payload2 = { query };
3758
+ return executeWithQueryTrace(
3759
+ tracer,
3760
+ {
3761
+ operation: "select",
3762
+ endpoint: "/gateway/query",
3763
+ table: resolvedTableName,
3764
+ sql: query,
3765
+ payload: payload2,
3766
+ options
3767
+ },
3768
+ async () => {
3769
+ const queryResponse = await client.queryGateway(payload2, options);
3770
+ return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
3771
+ },
3772
+ callsite
3773
+ );
2583
3774
  }
2584
3775
  }
2585
3776
  const payload = {
2586
3777
  table_name: resolvedTableName,
2587
3778
  columns,
2588
3779
  conditions,
2589
- limit: state.limit,
2590
- offset: state.offset,
2591
- current_page: state.currentPage,
2592
- page_size: state.pageSize,
2593
- total_pages: state.totalPages,
2594
- sort_by: state.order,
3780
+ limit: executionState.limit,
3781
+ offset: executionState.offset,
3782
+ current_page: executionState.currentPage,
3783
+ page_size: executionState.pageSize,
3784
+ total_pages: executionState.totalPages,
3785
+ sort_by: executionState.order,
2595
3786
  strip_nulls: options?.stripNulls ?? true,
2596
3787
  count: options?.count,
2597
3788
  head: options?.head
2598
3789
  };
2599
- const response = await client.fetchGateway(payload, options);
2600
- return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3790
+ const sql = buildDebugSelectQuery({
3791
+ tableName: resolvedTableName,
3792
+ columns,
3793
+ conditions,
3794
+ limit: executionState.limit,
3795
+ offset: executionState.offset,
3796
+ currentPage: executionState.currentPage,
3797
+ pageSize: executionState.pageSize,
3798
+ order: executionState.order
3799
+ });
3800
+ return executeWithQueryTrace(
3801
+ tracer,
3802
+ {
3803
+ operation: "select",
3804
+ endpoint: "/gateway/fetch",
3805
+ table: resolvedTableName,
3806
+ sql,
3807
+ payload,
3808
+ options
3809
+ },
3810
+ async () => {
3811
+ const response = await client.fetchGateway(payload, options);
3812
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3813
+ },
3814
+ callsite
3815
+ );
2601
3816
  };
2602
- const createSelectChain = (columns, options) => {
3817
+ const createSelectChain = (columns, options, initialCallsite) => {
2603
3818
  const chain = {};
3819
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
2604
3820
  const filterMethods2 = createFilterMethods(state, addCondition, chain);
2605
3821
  Object.assign(chain, filterMethods2, {
2606
3822
  async single(cols, opts) {
2607
- const r = await runSelect(cols ?? columns, opts ?? options);
3823
+ const r = await runSelect(
3824
+ cols ?? columns,
3825
+ opts ?? options,
3826
+ snapshotState(),
3827
+ callsiteStore.resolve(captureTraceCallsite(tracer))
3828
+ );
2608
3829
  return toSingleResult(r);
2609
3830
  },
2610
3831
  maybeSingle(cols, opts) {
2611
3832
  return chain.single(cols, opts);
2612
3833
  },
2613
3834
  then(onfulfilled, onrejected) {
2614
- return runSelect(columns, options).then(onfulfilled, onrejected);
3835
+ return runSelect(
3836
+ columns,
3837
+ options,
3838
+ snapshotState(),
3839
+ callsiteStore.resolve()
3840
+ ).then(onfulfilled, onrejected);
2615
3841
  },
2616
3842
  catch(onrejected) {
2617
- return runSelect(columns, options).catch(onrejected);
3843
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).catch(
3844
+ onrejected
3845
+ );
2618
3846
  },
2619
3847
  finally(onfinally) {
2620
- return runSelect(columns, options).finally(onfinally);
3848
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).finally(
3849
+ onfinally
3850
+ );
2621
3851
  }
2622
3852
  });
2623
3853
  return chain;
@@ -2634,11 +3864,75 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2634
3864
  return builder;
2635
3865
  },
2636
3866
  select(columns = DEFAULT_COLUMNS, options) {
2637
- return createSelectChain(columns, options);
3867
+ return createSelectChain(columns, options, captureTraceCallsite(tracer));
3868
+ },
3869
+ async findMany(options) {
3870
+ const columns = compileSelectShape(options.select);
3871
+ const baseState = snapshotState();
3872
+ const executionState = snapshotState();
3873
+ const callsite = captureTraceCallsite(tracer);
3874
+ const compiledWhere = compileWhere(options.where);
3875
+ if (compiledWhere?.length) {
3876
+ executionState.conditions.push(...compiledWhere);
3877
+ }
3878
+ if (options.orderBy !== void 0) {
3879
+ executionState.order = compileOrderBy(options.orderBy);
3880
+ }
3881
+ if (options.limit !== void 0) {
3882
+ executionState.limit = options.limit;
3883
+ }
3884
+ if (experimental?.findManyAst && canUseFindManyAstTransport(baseState)) {
3885
+ const resolvedTableName = resolveTableNameForCall(tableName, void 0);
3886
+ const payload = {
3887
+ table_name: resolvedTableName,
3888
+ select: options.select
3889
+ };
3890
+ if (options.where !== void 0) {
3891
+ payload.where = options.where;
3892
+ }
3893
+ const astOrder = toFindManyAstOrder(executionState.order);
3894
+ if (astOrder !== void 0) {
3895
+ payload.orderBy = astOrder;
3896
+ }
3897
+ if (executionState.limit !== void 0) {
3898
+ payload.limit = executionState.limit;
3899
+ }
3900
+ const sql = buildDebugSelectQuery({
3901
+ tableName: resolvedTableName,
3902
+ columns,
3903
+ conditions: executionState.conditions,
3904
+ limit: executionState.limit,
3905
+ order: executionState.order
3906
+ });
3907
+ return executeWithQueryTrace(
3908
+ tracer,
3909
+ {
3910
+ operation: "select",
3911
+ endpoint: "/gateway/fetch",
3912
+ table: resolvedTableName,
3913
+ sql,
3914
+ payload
3915
+ },
3916
+ async () => {
3917
+ const response = await client.fetchGateway(
3918
+ payload
3919
+ );
3920
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3921
+ },
3922
+ callsite
3923
+ );
3924
+ }
3925
+ return runSelect(
3926
+ columns,
3927
+ void 0,
3928
+ executionState,
3929
+ callsite
3930
+ );
2638
3931
  },
2639
3932
  insert(values, options) {
3933
+ const mutationCallsite = captureTraceCallsite(tracer);
2640
3934
  if (Array.isArray(values)) {
2641
- const executeInsertMany = async (columns, selectOptions) => {
3935
+ const executeInsertMany = async (columns, selectOptions, callsite) => {
2642
3936
  const mergedOptions = mergeOptions(options, selectOptions);
2643
3937
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2644
3938
  const payload = {
@@ -2651,12 +3945,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2651
3945
  if (mergedOptions?.defaultToNull !== void 0) {
2652
3946
  payload.default_to_null = mergedOptions.defaultToNull;
2653
3947
  }
2654
- const response = await client.insertGateway(payload, mergedOptions);
2655
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
3948
+ const sql = buildInsertDebugSql(payload);
3949
+ return executeWithQueryTrace(
3950
+ tracer,
3951
+ {
3952
+ operation: "insert",
3953
+ endpoint: "/gateway/insert",
3954
+ table: resolvedTableName,
3955
+ sql,
3956
+ payload,
3957
+ options: mergedOptions
3958
+ },
3959
+ async () => {
3960
+ const response = await client.insertGateway(payload, mergedOptions);
3961
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
3962
+ },
3963
+ callsite
3964
+ );
2656
3965
  };
2657
- return createMutationQuery(executeInsertMany);
3966
+ return createMutationQuery(executeInsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
2658
3967
  }
2659
- const executeInsertOne = async (columns, selectOptions) => {
3968
+ const executeInsertOne = async (columns, selectOptions, callsite) => {
2660
3969
  const mergedOptions = mergeOptions(options, selectOptions);
2661
3970
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2662
3971
  const payload = {
@@ -2669,14 +3978,30 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2669
3978
  if (mergedOptions?.defaultToNull !== void 0) {
2670
3979
  payload.default_to_null = mergedOptions.defaultToNull;
2671
3980
  }
2672
- const response = await client.insertGateway(payload, mergedOptions);
2673
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
3981
+ const sql = buildInsertDebugSql(payload);
3982
+ return executeWithQueryTrace(
3983
+ tracer,
3984
+ {
3985
+ operation: "insert",
3986
+ endpoint: "/gateway/insert",
3987
+ table: resolvedTableName,
3988
+ sql,
3989
+ payload,
3990
+ options: mergedOptions
3991
+ },
3992
+ async () => {
3993
+ const response = await client.insertGateway(payload, mergedOptions);
3994
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
3995
+ },
3996
+ callsite
3997
+ );
2674
3998
  };
2675
- return createMutationQuery(executeInsertOne);
3999
+ return createMutationQuery(executeInsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
2676
4000
  },
2677
4001
  upsert(values, options) {
4002
+ const mutationCallsite = captureTraceCallsite(tracer);
2678
4003
  if (Array.isArray(values)) {
2679
- const executeUpsertMany = async (columns, selectOptions) => {
4004
+ const executeUpsertMany = async (columns, selectOptions, callsite) => {
2680
4005
  const mergedOptions = mergeOptions(options, selectOptions);
2681
4006
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2682
4007
  const payload = {
@@ -2691,12 +4016,27 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2691
4016
  if (mergedOptions?.defaultToNull !== void 0) {
2692
4017
  payload.default_to_null = mergedOptions.defaultToNull;
2693
4018
  }
2694
- const response = await client.insertGateway(payload, mergedOptions);
2695
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4019
+ const sql = buildInsertDebugSql(payload);
4020
+ return executeWithQueryTrace(
4021
+ tracer,
4022
+ {
4023
+ operation: "upsert",
4024
+ endpoint: "/gateway/insert",
4025
+ table: resolvedTableName,
4026
+ sql,
4027
+ payload,
4028
+ options: mergedOptions
4029
+ },
4030
+ async () => {
4031
+ const response = await client.insertGateway(payload, mergedOptions);
4032
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4033
+ },
4034
+ callsite
4035
+ );
2696
4036
  };
2697
- return createMutationQuery(executeUpsertMany);
4037
+ return createMutationQuery(executeUpsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
2698
4038
  }
2699
- const executeUpsertOne = async (columns, selectOptions) => {
4039
+ const executeUpsertOne = async (columns, selectOptions, callsite) => {
2700
4040
  const mergedOptions = mergeOptions(options, selectOptions);
2701
4041
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2702
4042
  const payload = {
@@ -2711,13 +4051,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2711
4051
  if (mergedOptions?.defaultToNull !== void 0) {
2712
4052
  payload.default_to_null = mergedOptions.defaultToNull;
2713
4053
  }
2714
- const response = await client.insertGateway(payload, mergedOptions);
2715
- return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4054
+ const sql = buildInsertDebugSql(payload);
4055
+ return executeWithQueryTrace(
4056
+ tracer,
4057
+ {
4058
+ operation: "upsert",
4059
+ endpoint: "/gateway/insert",
4060
+ table: resolvedTableName,
4061
+ sql,
4062
+ payload,
4063
+ options: mergedOptions
4064
+ },
4065
+ async () => {
4066
+ const response = await client.insertGateway(payload, mergedOptions);
4067
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4068
+ },
4069
+ callsite
4070
+ );
2716
4071
  };
2717
- return createMutationQuery(executeUpsertOne);
4072
+ return createMutationQuery(executeUpsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
2718
4073
  },
2719
4074
  update(values, options) {
2720
- const executeUpdate = async (columns, selectOptions) => {
4075
+ const mutationCallsite = captureTraceCallsite(tracer);
4076
+ const executeUpdate = async (columns, selectOptions, callsite) => {
2721
4077
  const filters = state.conditions.length ? [...state.conditions] : void 0;
2722
4078
  const mergedOptions = mergeOptions(options, selectOptions);
2723
4079
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
@@ -2732,10 +4088,25 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2732
4088
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
2733
4089
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
2734
4090
  if (columns) payload.columns = columns;
2735
- const response = await client.updateGateway(payload, mergedOptions);
2736
- return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
4091
+ const sql = buildUpdateDebugSql(payload);
4092
+ return executeWithQueryTrace(
4093
+ tracer,
4094
+ {
4095
+ operation: "update",
4096
+ endpoint: "/gateway/update",
4097
+ table: resolvedTableName,
4098
+ sql,
4099
+ payload,
4100
+ options: mergedOptions
4101
+ },
4102
+ async () => {
4103
+ const response = await client.updateGateway(payload, mergedOptions);
4104
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
4105
+ },
4106
+ callsite
4107
+ );
2737
4108
  };
2738
- const mutation = createMutationQuery(executeUpdate, null);
4109
+ const mutation = createMutationQuery(executeUpdate, null, tracer, mutationCallsite);
2739
4110
  const updateChain = {};
2740
4111
  const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
2741
4112
  Object.assign(updateChain, filterMethods2, mutation);
@@ -2747,7 +4118,8 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2747
4118
  if (!resourceId && !filters?.length) {
2748
4119
  throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
2749
4120
  }
2750
- const executeDelete = async (columns, selectOptions) => {
4121
+ const mutationCallsite = captureTraceCallsite(tracer);
4122
+ const executeDelete = async (columns, selectOptions, callsite) => {
2751
4123
  const mergedOptions = mergeOptions(options, selectOptions);
2752
4124
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2753
4125
  const payload = {
@@ -2760,13 +4132,33 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2760
4132
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
2761
4133
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
2762
4134
  if (columns) payload.columns = columns;
2763
- const response = await client.deleteGateway(payload, mergedOptions);
2764
- return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
4135
+ const sql = buildDeleteDebugSql(payload);
4136
+ return executeWithQueryTrace(
4137
+ tracer,
4138
+ {
4139
+ operation: "delete",
4140
+ endpoint: "/gateway/delete",
4141
+ table: resolvedTableName,
4142
+ sql,
4143
+ payload,
4144
+ options: mergedOptions
4145
+ },
4146
+ async () => {
4147
+ const response = await client.deleteGateway(payload, mergedOptions);
4148
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
4149
+ },
4150
+ callsite
4151
+ );
2765
4152
  };
2766
- return createMutationQuery(executeDelete, null);
4153
+ return createMutationQuery(executeDelete, null, tracer, mutationCallsite);
2767
4154
  },
2768
4155
  async single(columns, options) {
2769
- const response = await builder.select(columns, options);
4156
+ const response = await runSelect(
4157
+ columns ?? DEFAULT_COLUMNS,
4158
+ options,
4159
+ snapshotState(),
4160
+ captureTraceCallsite(tracer)
4161
+ );
2770
4162
  return toSingleResult(response);
2771
4163
  },
2772
4164
  async maybeSingle(columns, options) {
@@ -2775,14 +4167,29 @@ function createTableBuilder(tableName, client, formatGatewayResult) {
2775
4167
  });
2776
4168
  return builder;
2777
4169
  }
2778
- function createQueryBuilder(client, formatGatewayResult) {
4170
+ function createQueryBuilder(client, formatGatewayResult, tracer) {
2779
4171
  return async function query(query, options) {
2780
4172
  const normalizedQuery = query.trim();
2781
4173
  if (!normalizedQuery) {
2782
4174
  throw new Error("query requires a non-empty string");
2783
4175
  }
2784
- const response = await client.queryGateway({ query: normalizedQuery }, options);
2785
- return formatGatewayResult(response, { operation: "query" });
4176
+ const payload = { query: normalizedQuery };
4177
+ const callsite = captureTraceCallsite(tracer);
4178
+ return executeWithQueryTrace(
4179
+ tracer,
4180
+ {
4181
+ operation: "query",
4182
+ endpoint: "/gateway/query",
4183
+ sql: normalizedQuery,
4184
+ payload,
4185
+ options
4186
+ },
4187
+ async () => {
4188
+ const response = await client.queryGateway(payload, options);
4189
+ return formatGatewayResult(response, { operation: "query" });
4190
+ },
4191
+ callsite
4192
+ );
2786
4193
  };
2787
4194
  }
2788
4195
  function createClientFromConfig(config) {
@@ -2794,8 +4201,9 @@ function createClientFromConfig(config) {
2794
4201
  headers: config.headers
2795
4202
  });
2796
4203
  const formatGatewayResult = createResultFormatter(config.experimental);
4204
+ const queryTracer = createQueryTracer(config.experimental);
2797
4205
  const auth = createAuthClient(config.auth);
2798
- const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
4206
+ const from = (table) => createTableBuilder(table, gateway, formatGatewayResult, queryTracer, config.experimental);
2799
4207
  const rpc = (fn, args, options) => {
2800
4208
  const normalizedFn = fn.trim();
2801
4209
  if (!normalizedFn) {
@@ -2806,10 +4214,12 @@ function createClientFromConfig(config) {
2806
4214
  args,
2807
4215
  options,
2808
4216
  gateway,
2809
- formatGatewayResult
4217
+ formatGatewayResult,
4218
+ queryTracer,
4219
+ captureTraceCallsite(queryTracer)
2810
4220
  );
2811
4221
  };
2812
- const query = createQueryBuilder(gateway, formatGatewayResult);
4222
+ const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
2813
4223
  const db = createDbModule({ from, rpc, query });
2814
4224
  return {
2815
4225
  from,
@@ -2824,12 +4234,40 @@ function toBackendConfig(b) {
2824
4234
  if (!b) return DEFAULT_BACKEND;
2825
4235
  return typeof b === "string" ? { type: b } : b;
2826
4236
  }
4237
+ function mergeAuthClientConfig(current, next) {
4238
+ const merged = {
4239
+ ...current ?? {},
4240
+ ...next
4241
+ };
4242
+ if (current?.headers || next.headers) {
4243
+ merged.headers = {
4244
+ ...current?.headers ?? {},
4245
+ ...next.headers ?? {}
4246
+ };
4247
+ }
4248
+ return merged;
4249
+ }
4250
+ function mergeExperimentalOptions(current, next) {
4251
+ const merged = {
4252
+ ...current ?? {},
4253
+ ...next
4254
+ };
4255
+ if (current?.traceQueries && typeof current.traceQueries === "object" && next.traceQueries && typeof next.traceQueries === "object") {
4256
+ merged.traceQueries = {
4257
+ ...current.traceQueries,
4258
+ ...next.traceQueries
4259
+ };
4260
+ }
4261
+ return merged;
4262
+ }
2827
4263
  var AthenaClientBuilderImpl = class {
2828
4264
  baseUrl;
2829
4265
  apiKey;
2830
4266
  backendConfig = DEFAULT_BACKEND;
2831
4267
  clientName;
2832
4268
  defaultHeaders;
4269
+ authConfig;
4270
+ experimentalOptions;
2833
4271
  isHealthTrackingEnabled = false;
2834
4272
  url(url) {
2835
4273
  this.baseUrl = url;
@@ -2851,6 +4289,35 @@ var AthenaClientBuilderImpl = class {
2851
4289
  this.defaultHeaders = headers;
2852
4290
  return this;
2853
4291
  }
4292
+ auth(config) {
4293
+ this.authConfig = mergeAuthClientConfig(this.authConfig, config);
4294
+ return this;
4295
+ }
4296
+ experimental(options) {
4297
+ this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options);
4298
+ return this;
4299
+ }
4300
+ options(options) {
4301
+ if (options.client !== void 0) {
4302
+ this.clientName = options.client;
4303
+ }
4304
+ if (options.backend !== void 0) {
4305
+ this.backendConfig = toBackendConfig(options.backend);
4306
+ }
4307
+ if (options.headers !== void 0) {
4308
+ this.defaultHeaders = {
4309
+ ...this.defaultHeaders ?? {},
4310
+ ...options.headers
4311
+ };
4312
+ }
4313
+ if (options.auth !== void 0) {
4314
+ this.authConfig = mergeAuthClientConfig(this.authConfig, options.auth);
4315
+ }
4316
+ if (options.experimental !== void 0) {
4317
+ this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options.experimental);
4318
+ }
4319
+ return this;
4320
+ }
2854
4321
  healthTracking(enabled) {
2855
4322
  this.isHealthTrackingEnabled = enabled;
2856
4323
  return this;
@@ -2865,7 +4332,9 @@ var AthenaClientBuilderImpl = class {
2865
4332
  client: this.clientName,
2866
4333
  backend: this.backendConfig,
2867
4334
  headers: this.defaultHeaders,
2868
- healthTracking: this.isHealthTrackingEnabled
4335
+ healthTracking: this.isHealthTrackingEnabled,
4336
+ auth: this.authConfig,
4337
+ experimental: this.experimentalOptions
2869
4338
  });
2870
4339
  }
2871
4340
  };
@@ -3480,7 +4949,7 @@ function resolveNullishValue(mode) {
3480
4949
  if (mode === "null") return null;
3481
4950
  return "";
3482
4951
  }
3483
- function isRecord4(value) {
4952
+ function isRecord7(value) {
3484
4953
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3485
4954
  }
3486
4955
  function isNullableColumn(model, key) {
@@ -3489,7 +4958,7 @@ function isNullableColumn(model, key) {
3489
4958
  }
3490
4959
  function toModelFormDefaults(model, values, options) {
3491
4960
  const source = values;
3492
- if (!isRecord4(source)) {
4961
+ if (!isRecord7(source)) {
3493
4962
  return {};
3494
4963
  }
3495
4964
  const mode = options?.nullishMode ?? "empty-string";
@@ -3745,7 +5214,7 @@ function normalizeBooleanFlag(rawValue, fallback) {
3745
5214
  return rawValue;
3746
5215
  }
3747
5216
  if (typeof rawValue === "string") {
3748
- return parseBooleanFlag(rawValue, fallback);
5217
+ return parseBooleanFlag2(rawValue, fallback);
3749
5218
  }
3750
5219
  return fallback;
3751
5220
  }
@@ -3920,6 +5389,11 @@ async function loadGeneratorConfig(options = {}) {
3920
5389
  }
3921
5390
  }
3922
5391
 
5392
+ // src/utils/slugify.ts
5393
+ function slugify(input) {
5394
+ return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
5395
+ }
5396
+
3923
5397
  // src/generator/naming.ts
3924
5398
  var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
3925
5399
  var RESERVED_IDENTIFIERS = /* @__PURE__ */ new Set([
@@ -4015,7 +5489,7 @@ function applyNamingStyle(input, style) {
4015
5489
  case "snake":
4016
5490
  return words.map((word) => word.toLowerCase()).join("_");
4017
5491
  case "kebab":
4018
- return words.map((word) => word.toLowerCase()).join("-");
5492
+ return slugify(words.join("-"));
4019
5493
  default:
4020
5494
  return input;
4021
5495
  }
@@ -4533,7 +6007,7 @@ var AthenaGatewayCatalogClient = class {
4533
6007
  async queryRows(query) {
4534
6008
  const result = await this.client.query(query);
4535
6009
  if (result.error || result.status < 200 || result.status >= 300) {
4536
- throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
6010
+ throw new Error(result.error?.message ?? `Gateway query failed with status ${result.status}`);
4537
6011
  }
4538
6012
  return result.data ?? [];
4539
6013
  }
@@ -4628,10 +6102,24 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
4628
6102
  }
4629
6103
  throw new Error(`Unsupported generator provider kind: ${providerConfig.kind ?? "unknown"}`);
4630
6104
  }
6105
+ function canOverwriteArtifact(file) {
6106
+ return file.kind === "model" || file.kind === "schema";
6107
+ }
6108
+ async function fileExists(path) {
6109
+ try {
6110
+ await stat(path);
6111
+ return true;
6112
+ } catch {
6113
+ return false;
6114
+ }
6115
+ }
4631
6116
  async function writeArtifacts(files, cwd) {
4632
6117
  const writtenFiles = [];
4633
6118
  for (const file of files) {
4634
6119
  const absolutePath = resolve(cwd, file.path);
6120
+ if (!canOverwriteArtifact(file) && await fileExists(absolutePath)) {
6121
+ continue;
6122
+ }
4635
6123
  await mkdir(dirname(absolutePath), { recursive: true });
4636
6124
  await writeFile(absolutePath, file.content, "utf8");
4637
6125
  writtenFiles.push(file.path);
@@ -4658,6 +6146,6 @@ async function runSchemaGenerator(options = {}) {
4658
6146
  };
4659
6147
  }
4660
6148
 
4661
- 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 };
6149
+ 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 };
4662
6150
  //# sourceMappingURL=index.js.map
4663
6151
  //# sourceMappingURL=index.js.map