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