@xylex-group/athena 2.0.0 → 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 (48) hide show
  1. package/README.md +287 -95
  2. package/dist/browser.cjs +4791 -0
  3. package/dist/browser.cjs.map +1 -0
  4. package/dist/browser.d.cts +25 -0
  5. package/dist/browser.d.ts +25 -0
  6. package/dist/browser.js +4745 -0
  7. package/dist/browser.js.map +1 -0
  8. package/dist/cli/index.cjs +2087 -220
  9. package/dist/cli/index.cjs.map +1 -1
  10. package/dist/cli/index.d.cts +3 -2
  11. package/dist/cli/index.d.ts +3 -2
  12. package/dist/cli/index.js +2089 -222
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/cookies.cjs +890 -0
  15. package/dist/cookies.cjs.map +1 -0
  16. package/dist/cookies.d.cts +174 -0
  17. package/dist/cookies.d.ts +174 -0
  18. package/dist/cookies.js +869 -0
  19. package/dist/cookies.js.map +1 -0
  20. package/dist/index.cjs +3046 -1200
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +8 -408
  23. package/dist/index.d.ts +8 -408
  24. package/dist/index.js +3045 -1202
  25. package/dist/index.js.map +1 -1
  26. package/dist/{model-form-CVOtC8jq.d.ts → model-form-BpDXlbxb.d.ts} +97 -2
  27. package/dist/{model-form-hXkvHS_3.d.cts → model-form-hoE2jHIi.d.cts} +97 -2
  28. package/dist/pipeline-BNIw8pDQ.d.ts +8 -0
  29. package/dist/pipeline-DNIpEsN8.d.cts +8 -0
  30. package/dist/react-email-BvyCZnfW.d.cts +610 -0
  31. package/dist/react-email-qPA1wjFV.d.ts +610 -0
  32. package/dist/react.cjs +30 -9
  33. package/dist/react.cjs.map +1 -1
  34. package/dist/react.d.cts +4 -4
  35. package/dist/react.d.ts +4 -4
  36. package/dist/react.js +30 -9
  37. package/dist/react.js.map +1 -1
  38. package/dist/{types-BnzoaNRC.d.cts → types-A5e97acl.d.cts} +2 -1
  39. package/dist/{types-BnzoaNRC.d.ts → types-A5e97acl.d.ts} +2 -1
  40. package/dist/{pipeline-CQgV-Yfo.d.ts → types-BnD22-vb.d.ts} +2 -7
  41. package/dist/{pipeline-C-cN0ACi.d.cts → types-bDlr4u7p.d.cts} +2 -7
  42. package/dist/utils.cjs +153 -0
  43. package/dist/utils.cjs.map +1 -0
  44. package/dist/utils.d.cts +23 -0
  45. package/dist/utils.d.ts +23 -0
  46. package/dist/utils.js +146 -0
  47. package/dist/utils.js.map +1 -0
  48. package/package.json +87 -9
@@ -4,10 +4,14 @@ var promises = require('fs/promises');
4
4
  var path = require('path');
5
5
  var fs = require('fs');
6
6
  var url = require('url');
7
- var pg = require('pg');
8
7
 
9
8
  // src/generator/pipeline.ts
10
9
 
10
+ // src/utils/slugify.ts
11
+ function slugify(input) {
12
+ return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
13
+ }
14
+
11
15
  // src/generator/naming.ts
12
16
  var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
13
17
  var RESERVED_IDENTIFIERS = /* @__PURE__ */ new Set([
@@ -103,7 +107,7 @@ function applyNamingStyle(input, style) {
103
107
  case "snake":
104
108
  return words.map((word) => word.toLowerCase()).join("_");
105
109
  case "kebab":
106
- return words.map((word) => word.toLowerCase()).join("-");
110
+ return slugify(words.join("-"));
107
111
  default:
108
112
  return input;
109
113
  }
@@ -149,9 +153,13 @@ function resolvePlaceholderMap(baseTokens, outputConfig) {
149
153
  const resolved = {
150
154
  ...baseTokens
151
155
  };
156
+ const reservedTokenKeys = new Set(Object.keys(baseTokens));
152
157
  const entries = Object.entries(outputConfig.placeholderMap ?? {});
153
158
  for (let index = 0; index < entries.length; index += 1) {
154
159
  const [key, value] = entries[index];
160
+ if (reservedTokenKeys.has(key)) {
161
+ continue;
162
+ }
155
163
  let current = value;
156
164
  for (let depth = 0; depth < 8; depth += 1) {
157
165
  const next = renderTemplate(current, resolved);
@@ -348,8 +356,11 @@ var AthenaGatewayError = class _AthenaGatewayError extends Error {
348
356
  });
349
357
  }
350
358
  };
359
+ function isAthenaGatewayError(error) {
360
+ return error instanceof AthenaGatewayError;
361
+ }
351
362
 
352
- // src/auxiliaries.ts
363
+ // src/utils/parse-boolean-flag.ts
353
364
  function parseBooleanFlag(rawValue, fallback) {
354
365
  if (!rawValue) return fallback;
355
366
  const normalized = rawValue.trim().toLowerCase();
@@ -362,6 +373,293 @@ function parseBooleanFlag(rawValue, fallback) {
362
373
  return fallback;
363
374
  }
364
375
 
376
+ // src/auxiliaries.ts
377
+ var AthenaErrorCode = {
378
+ UniqueViolation: "UNIQUE_VIOLATION",
379
+ NotFound: "NOT_FOUND",
380
+ ValidationFailed: "VALIDATION_FAILED",
381
+ AuthUnauthorized: "AUTH_UNAUTHORIZED",
382
+ AuthForbidden: "AUTH_FORBIDDEN",
383
+ RateLimited: "RATE_LIMITED",
384
+ NetworkUnavailable: "NETWORK_UNAVAILABLE",
385
+ TransientFailure: "TRANSIENT_FAILURE",
386
+ HttpFailure: "HTTP_FAILURE",
387
+ Unknown: "UNKNOWN"
388
+ };
389
+ var AthenaErrorCategory = {
390
+ Transport: "transport",
391
+ Client: "client",
392
+ Server: "server",
393
+ Database: "database",
394
+ Unknown: "unknown"
395
+ };
396
+ function parseBooleanFlag2(rawValue, fallback) {
397
+ return parseBooleanFlag(rawValue, fallback);
398
+ }
399
+ function isRecord(value) {
400
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
401
+ }
402
+ function firstNonEmptyString(...values) {
403
+ for (const value of values) {
404
+ if (typeof value === "string" && value.trim().length > 0) {
405
+ return value.trim();
406
+ }
407
+ }
408
+ return void 0;
409
+ }
410
+ function messageFromUnknownError(error) {
411
+ if (typeof error === "string" && error.trim().length > 0) {
412
+ return error.trim();
413
+ }
414
+ if (error instanceof Error && error.message.trim().length > 0) {
415
+ return error.message.trim();
416
+ }
417
+ if (!isRecord(error)) {
418
+ return void 0;
419
+ }
420
+ return firstNonEmptyString(error.message, error.error, error.details);
421
+ }
422
+ function gatewayCodeFromUnknownError(error) {
423
+ if (!isRecord(error) || typeof error.gatewayCode !== "string") {
424
+ return void 0;
425
+ }
426
+ return error.gatewayCode;
427
+ }
428
+ function isAthenaResultErrorLike(value) {
429
+ return isRecord(value) && typeof value.message === "string" && (value.athenaCode === void 0 || isAthenaErrorCode(value.athenaCode)) && (value.kind === void 0 || isAthenaErrorKind(value.kind)) && (value.category === void 0 || isAthenaErrorCategory(value.category)) && (value.retryable === void 0 || typeof value.retryable === "boolean") && (value.status === void 0 || typeof value.status === "number");
430
+ }
431
+ function isAthenaErrorKind(value) {
432
+ return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
433
+ }
434
+ function isAthenaErrorCode(value) {
435
+ return value === "UNIQUE_VIOLATION" || value === "NOT_FOUND" || value === "VALIDATION_FAILED" || value === "AUTH_UNAUTHORIZED" || value === "AUTH_FORBIDDEN" || value === "RATE_LIMITED" || value === "NETWORK_UNAVAILABLE" || value === "TRANSIENT_FAILURE" || value === "HTTP_FAILURE" || value === "UNKNOWN";
436
+ }
437
+ function isAthenaErrorCategory(value) {
438
+ return value === "transport" || value === "client" || value === "server" || value === "database" || value === "unknown";
439
+ }
440
+ function isNormalizedAthenaError(value) {
441
+ return isRecord(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
442
+ }
443
+ function withContextOverrides(normalized, context) {
444
+ if (!context?.table && !context?.operation) {
445
+ return normalized;
446
+ }
447
+ return {
448
+ ...normalized,
449
+ table: context.table ?? normalized.table,
450
+ operation: context.operation ?? normalized.operation
451
+ };
452
+ }
453
+ function resolveAttachedNormalizedError(resultOrError) {
454
+ if (!isRecord(resultOrError)) return void 0;
455
+ if (!("__athenaNormalizedError" in resultOrError)) return void 0;
456
+ const candidate = resultOrError.__athenaNormalizedError;
457
+ return isNormalizedAthenaError(candidate) ? candidate : void 0;
458
+ }
459
+ function isAthenaResultLike(value) {
460
+ return isRecord(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
461
+ }
462
+ function operationFromDetails(details) {
463
+ if (!details?.endpoint) return void 0;
464
+ if (details.endpoint === "/gateway/fetch" || details.endpoint === "/gateway/query") return "select";
465
+ if (details.endpoint === "/gateway/insert") return "insert";
466
+ if (details.endpoint === "/gateway/update") return "update";
467
+ if (details.endpoint === "/gateway/delete") return "delete";
468
+ if (details.endpoint === "/gateway/rpc" || details.endpoint.startsWith("/rpc/")) return "rpc";
469
+ return void 0;
470
+ }
471
+ function matchRegex(input, patterns) {
472
+ for (const pattern of patterns) {
473
+ const match = pattern.exec(input);
474
+ if (match?.[1]) return match[1];
475
+ }
476
+ return void 0;
477
+ }
478
+ function extractConstraint(message) {
479
+ return matchRegex(message, [
480
+ /unique constraint\s+["'`]([^"'`]+)["'`]/i,
481
+ /constraint\s+["'`]([^"'`]+)["'`]/i
482
+ ]);
483
+ }
484
+ function extractTable(message) {
485
+ return matchRegex(message, [
486
+ /(?:table|relation)\s+["'`]([^"'`]+)["'`]/i,
487
+ /on\s+table\s+([a-zA-Z0-9_.]+)/i
488
+ ]);
489
+ }
490
+ function classifyKind(status, code, message) {
491
+ const lower = message.toLowerCase();
492
+ const hasUniquePattern = lower.includes("unique constraint") || lower.includes("duplicate key") || lower.includes("already exists") || lower.includes("duplicate");
493
+ const hasNotFoundPattern = lower.includes("not found") || lower.includes("no rows");
494
+ const hasValidationPattern = lower.includes("validation") || lower.includes("invalid") || lower.includes("malformed");
495
+ const hasAuthPattern = lower.includes("unauthorized") || lower.includes("forbidden") || lower.includes("auth");
496
+ const hasRateLimitPattern = lower.includes("rate limit") || lower.includes("too many requests");
497
+ const hasTransientPattern = lower.includes("timeout") || lower.includes("temporar") || lower.includes("connection reset") || lower.includes("socket") || lower.includes("deadlock");
498
+ if (status === 409 || hasUniquePattern) return "unique_violation";
499
+ if (status === 404 || hasNotFoundPattern) return "not_found";
500
+ if (status === 401 || status === 403 || hasAuthPattern) return "auth";
501
+ if (status === 429 || hasRateLimitPattern) return "rate_limit";
502
+ if (status === 400 || status === 422 || hasValidationPattern) return "validation";
503
+ if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
504
+ return "transient";
505
+ }
506
+ return "unknown";
507
+ }
508
+ function toAthenaErrorCode(kind, status, gatewayCode) {
509
+ if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
510
+ return AthenaErrorCode.NetworkUnavailable;
511
+ }
512
+ switch (kind) {
513
+ case "unique_violation":
514
+ return AthenaErrorCode.UniqueViolation;
515
+ case "not_found":
516
+ return AthenaErrorCode.NotFound;
517
+ case "validation":
518
+ return AthenaErrorCode.ValidationFailed;
519
+ case "rate_limit":
520
+ return AthenaErrorCode.RateLimited;
521
+ case "auth":
522
+ if (status === 403) {
523
+ return AthenaErrorCode.AuthForbidden;
524
+ }
525
+ return AthenaErrorCode.AuthUnauthorized;
526
+ case "transient":
527
+ return status !== void 0 && status >= 500 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.TransientFailure;
528
+ case "unknown":
529
+ default:
530
+ return status !== void 0 && status >= 400 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.Unknown;
531
+ }
532
+ }
533
+ function toAthenaErrorCategory(kind, status) {
534
+ if (kind === "transient" && (status === 0 || status === void 0)) {
535
+ return AthenaErrorCategory.Transport;
536
+ }
537
+ if (kind === "unique_violation") return AthenaErrorCategory.Database;
538
+ if (kind === "validation" || kind === "auth" || kind === "not_found") return AthenaErrorCategory.Client;
539
+ if (kind === "rate_limit" || kind === "transient") return AthenaErrorCategory.Server;
540
+ return AthenaErrorCategory.Unknown;
541
+ }
542
+ function isRetryable(kind, status) {
543
+ if (kind === "rate_limit" || kind === "transient") return true;
544
+ return status !== void 0 && status >= 500;
545
+ }
546
+ function normalizeAthenaError(resultOrError, context) {
547
+ const attached = resolveAttachedNormalizedError(resultOrError);
548
+ if (attached) {
549
+ return withContextOverrides(attached, context);
550
+ }
551
+ if (isAthenaResultLike(resultOrError)) {
552
+ if (isAthenaResultErrorLike(resultOrError.error)) {
553
+ return {
554
+ kind: resultOrError.error.kind ?? classifyKind(resultOrError.status, gatewayCodeFromUnknownError(resultOrError.error), resultOrError.error.message),
555
+ code: resultOrError.error.athenaCode ?? toAthenaErrorCode(
556
+ resultOrError.error.kind ?? classifyKind(
557
+ resultOrError.status,
558
+ gatewayCodeFromUnknownError(resultOrError.error),
559
+ resultOrError.error.message
560
+ ),
561
+ resultOrError.error.status ?? resultOrError.status,
562
+ gatewayCodeFromUnknownError(resultOrError.error)
563
+ ),
564
+ category: resultOrError.error.category ?? toAthenaErrorCategory(
565
+ resultOrError.error.kind ?? classifyKind(
566
+ resultOrError.status,
567
+ gatewayCodeFromUnknownError(resultOrError.error),
568
+ resultOrError.error.message
569
+ ),
570
+ resultOrError.error.status ?? resultOrError.status
571
+ ),
572
+ retryable: resultOrError.error.retryable ?? isRetryable(
573
+ resultOrError.error.kind ?? classifyKind(
574
+ resultOrError.status,
575
+ gatewayCodeFromUnknownError(resultOrError.error),
576
+ resultOrError.error.message
577
+ ),
578
+ resultOrError.error.status ?? resultOrError.status
579
+ ),
580
+ status: resultOrError.error.status ?? resultOrError.status,
581
+ constraint: resultOrError.error.constraint,
582
+ table: context?.table ?? resultOrError.error.table,
583
+ operation: context?.operation ?? resultOrError.error.operation,
584
+ message: resultOrError.error.message,
585
+ raw: resultOrError.error.raw ?? resultOrError.raw
586
+ };
587
+ }
588
+ const details = resultOrError.errorDetails;
589
+ const message2 = messageFromUnknownError(resultOrError.error) ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
590
+ const operation = context?.operation ?? operationFromDetails(details);
591
+ const table = context?.table ?? extractTable(message2);
592
+ const constraint = extractConstraint(message2);
593
+ const gatewayCode = details?.code ?? gatewayCodeFromUnknownError(resultOrError.error);
594
+ const kind2 = classifyKind(resultOrError.status, gatewayCode, message2);
595
+ const code = toAthenaErrorCode(kind2, resultOrError.status, gatewayCode);
596
+ const category = toAthenaErrorCategory(kind2, resultOrError.status);
597
+ return {
598
+ kind: kind2,
599
+ code,
600
+ category,
601
+ retryable: isRetryable(kind2, resultOrError.status),
602
+ status: resultOrError.status,
603
+ constraint,
604
+ table,
605
+ operation,
606
+ message: message2,
607
+ raw: resultOrError.raw
608
+ };
609
+ }
610
+ if (isAthenaGatewayError(resultOrError)) {
611
+ const details = resultOrError.toDetails();
612
+ const operation = context?.operation ?? operationFromDetails(details);
613
+ const table = context?.table ?? extractTable(resultOrError.message);
614
+ const constraint = extractConstraint(resultOrError.message);
615
+ const kind2 = classifyKind(resultOrError.status, resultOrError.code, resultOrError.message);
616
+ const code = toAthenaErrorCode(kind2, resultOrError.status, resultOrError.code);
617
+ const category = toAthenaErrorCategory(kind2, resultOrError.status);
618
+ return {
619
+ kind: kind2,
620
+ code,
621
+ category,
622
+ retryable: isRetryable(kind2, resultOrError.status),
623
+ status: resultOrError.status,
624
+ constraint,
625
+ table,
626
+ operation,
627
+ message: resultOrError.message,
628
+ raw: resultOrError
629
+ };
630
+ }
631
+ if (resultOrError instanceof Error) {
632
+ const maybeStatus = isRecord(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
633
+ const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
634
+ return {
635
+ kind: kind2,
636
+ code: toAthenaErrorCode(kind2, maybeStatus),
637
+ category: toAthenaErrorCategory(kind2, maybeStatus),
638
+ retryable: isRetryable(kind2, maybeStatus),
639
+ status: maybeStatus,
640
+ constraint: extractConstraint(resultOrError.message),
641
+ table: context?.table ?? extractTable(resultOrError.message),
642
+ operation: context?.operation,
643
+ message: resultOrError.message,
644
+ raw: resultOrError
645
+ };
646
+ }
647
+ const message = typeof resultOrError === "string" ? resultOrError : "Unknown Athena error";
648
+ const kind = classifyKind(void 0, void 0, message);
649
+ return {
650
+ kind,
651
+ code: toAthenaErrorCode(kind, void 0),
652
+ category: toAthenaErrorCategory(kind, void 0),
653
+ retryable: isRetryable(kind, void 0),
654
+ status: void 0,
655
+ constraint: extractConstraint(message),
656
+ table: context?.table ?? extractTable(message),
657
+ operation: context?.operation,
658
+ message,
659
+ raw: resultOrError
660
+ };
661
+ }
662
+
365
663
  // src/generator/schema-selection.ts
366
664
  var DEFAULT_POSTGRES_SCHEMAS = ["public"];
367
665
  function collectSchemaNames(input) {
@@ -392,6 +690,7 @@ function resolveProviderSchemas(providerConfig) {
392
690
  }
393
691
 
394
692
  // src/generator/config.ts
693
+ var POSTGRES_PROTOCOLS = /* @__PURE__ */ new Set(["postgres:", "postgresql:"]);
395
694
  var DEFAULT_CONFIG_CANDIDATES = [
396
695
  "athena.config.ts",
397
696
  "athena.config.js",
@@ -421,12 +720,157 @@ var DEFAULT_EXPERIMENTAL_FLAGS = {
421
720
  postgresGatewayIntrospection: false,
422
721
  scyllaProviderContracts: true
423
722
  };
723
+ var PROJECT_ENV_FILENAMES = [".env", ".env.local"];
724
+ var DIRECT_CONNECTION_STRING_ENV_KEYS = [
725
+ "ATHENA_GENERATOR_PG_URL",
726
+ "DATABASE_URL",
727
+ "PG_URL",
728
+ "POSTGRES_URL",
729
+ "POSTGRESQL_URL"
730
+ ];
731
+ var POSTGRES_DATABASE_ENV_KEYS = ["ATHENA_GENERATOR_DB", "ATHENA_DATABASE", "PGDATABASE"];
732
+ var POSTGRES_PASSWORD_ENV_KEYS = ["ATHENA_GENERATOR_PG_PASSWORD", "PGPASSWORD"];
733
+ var GATEWAY_URL_ENV_KEYS = ["ATHENA_URL", "ATHENA_GATEWAY_URL", "ATHENA_GENERATOR_URL"];
734
+ var GATEWAY_API_KEY_ENV_KEYS = [
735
+ "ATHENA_API_KEY",
736
+ "ATHENA_GATEWAY_API_KEY",
737
+ "ATHENA_GENERATOR_API_KEY"
738
+ ];
739
+ function normalizeRawEnvValue(rawValue) {
740
+ if (rawValue.startsWith('"') && rawValue.endsWith('"') && rawValue.length >= 2) {
741
+ const inner = rawValue.slice(1, -1);
742
+ return inner.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
743
+ }
744
+ if (rawValue.startsWith("'") && rawValue.endsWith("'") && rawValue.length >= 2) {
745
+ return rawValue.slice(1, -1);
746
+ }
747
+ const commentIndex = rawValue.search(/\s+#/);
748
+ const withoutComment = commentIndex >= 0 ? rawValue.slice(0, commentIndex) : rawValue;
749
+ return withoutComment.trim();
750
+ }
751
+ function parseEnvLine(line) {
752
+ const trimmed = line.trim();
753
+ if (!trimmed || trimmed.startsWith("#")) {
754
+ return void 0;
755
+ }
756
+ const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
757
+ if (!match) {
758
+ return void 0;
759
+ }
760
+ const [, key, rawValue] = match;
761
+ return [key, normalizeRawEnvValue(rawValue.trim())];
762
+ }
763
+ function readProjectEnvEntries(cwd) {
764
+ const nodeEnv = process.env.NODE_ENV?.trim();
765
+ const filenames = [
766
+ ...PROJECT_ENV_FILENAMES,
767
+ ...nodeEnv ? [`.env.${nodeEnv}`, `.env.${nodeEnv}.local`] : []
768
+ ];
769
+ const entries = /* @__PURE__ */ new Map();
770
+ for (const filename of filenames) {
771
+ const absolutePath = path.resolve(cwd, filename);
772
+ if (!fs.existsSync(absolutePath)) {
773
+ continue;
774
+ }
775
+ const content = fs.readFileSync(absolutePath, "utf8");
776
+ const lines = content.split(/\r?\n/g);
777
+ for (const line of lines) {
778
+ const parsed = parseEnvLine(line);
779
+ if (!parsed) {
780
+ continue;
781
+ }
782
+ const [key, value] = parsed;
783
+ entries.set(key, value);
784
+ }
785
+ }
786
+ return entries;
787
+ }
788
+ function applyProjectEnv(cwd) {
789
+ const envEntries = readProjectEnvEntries(cwd);
790
+ if (envEntries.size === 0) {
791
+ return () => {
792
+ };
793
+ }
794
+ const initialKeys = new Set(
795
+ Object.keys(process.env).filter((key) => process.env[key] !== void 0)
796
+ );
797
+ const staged = /* @__PURE__ */ new Map();
798
+ for (const [key, value] of envEntries.entries()) {
799
+ if (initialKeys.has(key)) {
800
+ continue;
801
+ }
802
+ staged.set(key, value);
803
+ }
804
+ for (const [key, value] of staged.entries()) {
805
+ process.env[key] = value;
806
+ }
807
+ return () => {
808
+ for (const key of staged.keys()) {
809
+ delete process.env[key];
810
+ }
811
+ };
812
+ }
813
+ function readEnvStringValue(key) {
814
+ const value = process.env[key];
815
+ if (typeof value !== "string") {
816
+ return void 0;
817
+ }
818
+ const trimmed = value.trim();
819
+ return trimmed.length > 0 ? trimmed : void 0;
820
+ }
821
+ function resolveFallbackValue(fallbackKeys) {
822
+ for (const key of fallbackKeys) {
823
+ const value = readEnvStringValue(key);
824
+ if (value) {
825
+ return value;
826
+ }
827
+ }
828
+ return void 0;
829
+ }
830
+ function normalizeOptionalString(value, fallbackKeys) {
831
+ if (typeof value === "string") {
832
+ const trimmed = value.trim();
833
+ if (trimmed.length > 0) {
834
+ return trimmed;
835
+ }
836
+ }
837
+ return resolveFallbackValue(fallbackKeys);
838
+ }
839
+ function normalizeRequiredString(value, fieldLabel, fallbackKeys) {
840
+ const resolved = normalizeOptionalString(value, fallbackKeys);
841
+ if (resolved) {
842
+ return resolved;
843
+ }
844
+ throw new Error(
845
+ `Generator config is missing ${fieldLabel}. Set ${fieldLabel} directly or provide one of: ${fallbackKeys.join(", ")}.`
846
+ );
847
+ }
848
+ function applyPostgresPasswordFallback(connectionString) {
849
+ let parsedUrl;
850
+ try {
851
+ parsedUrl = new URL(connectionString);
852
+ } catch {
853
+ return connectionString;
854
+ }
855
+ if (!POSTGRES_PROTOCOLS.has(parsedUrl.protocol)) {
856
+ return connectionString;
857
+ }
858
+ if (!parsedUrl.username || parsedUrl.password) {
859
+ return connectionString;
860
+ }
861
+ const fallbackPassword = resolveFallbackValue(POSTGRES_PASSWORD_ENV_KEYS);
862
+ if (!fallbackPassword) {
863
+ return connectionString;
864
+ }
865
+ parsedUrl.password = fallbackPassword;
866
+ return parsedUrl.toString();
867
+ }
424
868
  function normalizeBooleanFlag(rawValue, fallback) {
425
869
  if (typeof rawValue === "boolean") {
426
870
  return rawValue;
427
871
  }
428
872
  if (typeof rawValue === "string") {
429
- return parseBooleanFlag(rawValue, fallback);
873
+ return parseBooleanFlag2(rawValue, fallback);
430
874
  }
431
875
  return fallback;
432
876
  }
@@ -466,9 +910,41 @@ function normalizeOutputConfig(output) {
466
910
  };
467
911
  }
468
912
  function normalizeProviderConfig(provider) {
469
- if (provider.kind === "postgres") {
913
+ if (provider.kind === "postgres" && provider.mode === "direct") {
914
+ const connectionString = normalizeRequiredString(
915
+ provider.connectionString,
916
+ "provider.connectionString",
917
+ DIRECT_CONNECTION_STRING_ENV_KEYS
918
+ );
919
+ const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS);
920
+ return {
921
+ ...provider,
922
+ connectionString: applyPostgresPasswordFallback(connectionString),
923
+ database,
924
+ schemas: normalizeSchemaSelection(provider.schemas)
925
+ };
926
+ }
927
+ if (provider.kind === "postgres" && provider.mode === "gateway") {
928
+ const gatewayUrl = normalizeRequiredString(
929
+ provider.gatewayUrl,
930
+ "provider.gatewayUrl",
931
+ GATEWAY_URL_ENV_KEYS
932
+ );
933
+ const apiKey = normalizeRequiredString(
934
+ provider.apiKey,
935
+ "provider.apiKey",
936
+ GATEWAY_API_KEY_ENV_KEYS
937
+ );
938
+ const database = normalizeRequiredString(
939
+ provider.database,
940
+ "provider.database",
941
+ POSTGRES_DATABASE_ENV_KEYS
942
+ );
470
943
  return {
471
944
  ...provider,
945
+ gatewayUrl,
946
+ apiKey,
947
+ database,
472
948
  schemas: normalizeSchemaSelection(provider.schemas)
473
949
  };
474
950
  }
@@ -527,6 +1003,11 @@ function extractConfigExport(module) {
527
1003
  if (moduleExports && typeof moduleExports === "object") {
528
1004
  queue.push(moduleExports);
529
1005
  }
1006
+ for (const value of Object.values(record)) {
1007
+ if (value && typeof value === "object") {
1008
+ queue.push(value);
1009
+ }
1010
+ }
530
1011
  }
531
1012
  throw new Error(
532
1013
  "Generator config file must export a config object as default export or `config`."
@@ -541,19 +1022,24 @@ function importConfigModule(moduleSpecifier) {
541
1022
  }
542
1023
  async function loadGeneratorConfig(options = {}) {
543
1024
  const cwd = options.cwd ?? process.cwd();
1025
+ const restoreProjectEnv = applyProjectEnv(cwd);
544
1026
  const resolvedPath = options.configPath ? path.resolve(cwd, options.configPath) : findGeneratorConfigPath(cwd);
545
1027
  if (!resolvedPath) {
546
1028
  throw new Error(
547
1029
  `No generator config found in ${cwd}. Expected one of: ${DEFAULT_CONFIG_CANDIDATES.join(", ")}`
548
1030
  );
549
1031
  }
550
- const moduleUrl = url.pathToFileURL(resolvedPath);
551
- const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
552
- const rawConfig = extractConfigExport(module);
553
- return {
554
- configPath: resolvedPath,
555
- config: normalizeGeneratorConfig(rawConfig)
556
- };
1032
+ try {
1033
+ const moduleUrl = url.pathToFileURL(resolvedPath);
1034
+ const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
1035
+ const rawConfig = extractConfigExport(module);
1036
+ return {
1037
+ configPath: resolvedPath,
1038
+ config: normalizeGeneratorConfig(rawConfig)
1039
+ };
1040
+ } finally {
1041
+ restoreProjectEnv();
1042
+ }
557
1043
  }
558
1044
 
559
1045
  // src/generator/renderer.ts
@@ -695,13 +1181,65 @@ function assertNoDuplicatePaths(files) {
695
1181
  [
696
1182
  `Generator output collision detected for path: ${file.path}`,
697
1183
  `Collision: ${existing.kind} and ${file.kind}.`,
698
- "When syncing multiple schemas, include a schema placeholder such as {schema} or {schema_kebab} in model/schema output targets."
1184
+ "Use explicit placeholders such as {model}, {model_kebab}, {schema}, or {schema_kebab} in output targets so each artifact resolves to a unique path."
699
1185
  ].join(" ")
700
1186
  );
701
1187
  }
702
1188
  seen.set(file.path, file);
703
1189
  }
704
1190
  }
1191
+ function addSchemaSegmentToPath(pathValue, schemaName) {
1192
+ const normalizedPath = normalizePath(pathValue);
1193
+ const parsedPath = path.posix.parse(normalizedPath);
1194
+ const schemaSegment = applyNamingStyle(schemaName, "kebab");
1195
+ if (!schemaSegment) {
1196
+ return normalizedPath;
1197
+ }
1198
+ const dir = parsedPath.dir.length > 0 ? `${parsedPath.dir}/${schemaSegment}` : schemaSegment;
1199
+ return normalizePath(path.posix.join(dir, parsedPath.base));
1200
+ }
1201
+ function scopeDuplicateDescriptorPathsBySchema(descriptors) {
1202
+ const nextDescriptors = descriptors.map((descriptor) => ({ ...descriptor }));
1203
+ const duplicates = /* @__PURE__ */ new Map();
1204
+ for (let index = 0; index < nextDescriptors.length; index += 1) {
1205
+ const descriptor = nextDescriptors[index];
1206
+ const indexes = duplicates.get(descriptor.filePath) ?? [];
1207
+ indexes.push(index);
1208
+ duplicates.set(descriptor.filePath, indexes);
1209
+ }
1210
+ let appliedSchemaScoping = false;
1211
+ for (const indexes of duplicates.values()) {
1212
+ if (indexes.length <= 1) {
1213
+ continue;
1214
+ }
1215
+ const schemaNames = new Set(indexes.map((index) => nextDescriptors[index].schemaName));
1216
+ if (schemaNames.size <= 1) {
1217
+ continue;
1218
+ }
1219
+ for (const index of indexes) {
1220
+ const descriptor = nextDescriptors[index];
1221
+ descriptor.filePath = addSchemaSegmentToPath(descriptor.filePath, descriptor.schemaName);
1222
+ }
1223
+ appliedSchemaScoping = true;
1224
+ }
1225
+ if (!appliedSchemaScoping) {
1226
+ return nextDescriptors;
1227
+ }
1228
+ const normalizedPaths = /* @__PURE__ */ new Set();
1229
+ for (const descriptor of nextDescriptors) {
1230
+ if (normalizedPaths.has(descriptor.filePath)) {
1231
+ throw new Error(
1232
+ [
1233
+ `Generator output collision detected for path: ${descriptor.filePath}`,
1234
+ "Automatic schema path scoping was applied but collisions remain.",
1235
+ "Add explicit placeholders such as {model}, {model_kebab}, {schema}, or {schema_kebab} to your output targets."
1236
+ ].join(" ")
1237
+ );
1238
+ }
1239
+ normalizedPaths.add(descriptor.filePath);
1240
+ }
1241
+ return nextDescriptors;
1242
+ }
705
1243
  var ArtifactComposer = class {
706
1244
  constructor(snapshot, config) {
707
1245
  this.snapshot = snapshot;
@@ -740,7 +1278,8 @@ var ArtifactComposer = class {
740
1278
  });
741
1279
  }
742
1280
  }
743
- const schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
1281
+ const scopedModelDescriptors = scopeDuplicateDescriptorPathsBySchema(modelDescriptors);
1282
+ let schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
744
1283
  const schemaPath = normalizePath(
745
1284
  renderOutputPath(this.config.output.targets.schema, {
746
1285
  provider: providerName,
@@ -758,9 +1297,10 @@ var ArtifactComposer = class {
758
1297
  this.config.naming.schemaConst,
759
1298
  "schema"
760
1299
  ),
761
- models: modelDescriptors.filter((model) => model.schemaName === schemaName)
1300
+ models: scopedModelDescriptors.filter((model) => model.schemaName === schemaName)
762
1301
  };
763
1302
  });
1303
+ schemaDescriptors = scopeDuplicateDescriptorPathsBySchema(schemaDescriptors);
764
1304
  const databasePath = normalizePath(
765
1305
  renderOutputPath(this.config.output.targets.database, {
766
1306
  provider: providerName,
@@ -780,7 +1320,7 @@ var ArtifactComposer = class {
780
1320
  schemas: schemaDescriptors
781
1321
  };
782
1322
  const files = [];
783
- for (const modelDescriptor of modelDescriptors) {
1323
+ for (const modelDescriptor of scopedModelDescriptors) {
784
1324
  files.push(renderModelArtifact(this.snapshot, modelDescriptor, this.config));
785
1325
  }
786
1326
  for (const schemaDescriptor of schemaDescriptors) {
@@ -844,26 +1384,42 @@ function parseResponseBody(rawText, contentType) {
844
1384
  function normalizeHeaderValue(value) {
845
1385
  return value ? value : void 0;
846
1386
  }
847
- function isRecord(value) {
1387
+ function isRecord2(value) {
848
1388
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
849
1389
  }
1390
+ function nonEmptyString(value) {
1391
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
1392
+ }
1393
+ function resolveStructuredErrorPayload(payload) {
1394
+ if (!isRecord2(payload)) return null;
1395
+ return isRecord2(payload.error) ? payload.error : payload;
1396
+ }
850
1397
  function resolveRequestId(headers) {
851
1398
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
852
1399
  }
853
1400
  function resolveErrorMessage(payload, fallback) {
854
- if (isRecord(payload)) {
855
- const messageCandidates = [payload.error, payload.message, payload.details];
1401
+ const structuredPayload = resolveStructuredErrorPayload(payload);
1402
+ if (structuredPayload) {
1403
+ const messageCandidates = [structuredPayload.message, structuredPayload.error, structuredPayload.details];
856
1404
  for (const candidate of messageCandidates) {
857
- if (typeof candidate === "string" && candidate.trim().length > 0) {
858
- return candidate.trim();
859
- }
1405
+ const resolved = nonEmptyString(candidate);
1406
+ if (resolved) return resolved;
860
1407
  }
861
1408
  }
862
- if (typeof payload === "string" && payload.trim().length > 0) {
863
- return payload.trim();
864
- }
1409
+ const rawMessage = nonEmptyString(payload);
1410
+ if (rawMessage) return rawMessage;
865
1411
  return fallback;
866
1412
  }
1413
+ function resolveErrorHint(payload) {
1414
+ const structuredPayload = resolveStructuredErrorPayload(payload);
1415
+ return structuredPayload ? nonEmptyString(structuredPayload.hint) : void 0;
1416
+ }
1417
+ function resolveStatusText(response, payload) {
1418
+ const rawStatusText = nonEmptyString(response.statusText);
1419
+ if (rawStatusText) return rawStatusText;
1420
+ const payloadRecord = isRecord2(payload) ? payload : null;
1421
+ return payloadRecord ? nonEmptyString(payloadRecord.statusText) ?? null : null;
1422
+ }
867
1423
  function detailsFromError(error) {
868
1424
  return error.toDetails();
869
1425
  }
@@ -1034,6 +1590,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1034
1590
  return {
1035
1591
  ok: false,
1036
1592
  status: response.status,
1593
+ statusText: resolveStatusText(response, parsedBody.parsed),
1037
1594
  data: null,
1038
1595
  error: invalidJsonError.message,
1039
1596
  errorDetails: detailsFromError(invalidJsonError),
@@ -1041,7 +1598,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1041
1598
  };
1042
1599
  }
1043
1600
  const parsed = parsedBody.parsed;
1044
- const parsedPayload = isRecord(parsed) ? parsed : null;
1601
+ const parsedPayload = isRecord2(parsed) ? parsed : null;
1045
1602
  if (!response.ok) {
1046
1603
  const httpError = new AthenaGatewayError({
1047
1604
  code: "HTTP_ERROR",
@@ -1052,11 +1609,13 @@ async function callAthena(config, endpoint, method, payload, options) {
1052
1609
  status: response.status,
1053
1610
  endpoint,
1054
1611
  method,
1055
- requestId
1612
+ requestId,
1613
+ hint: resolveErrorHint(parsed)
1056
1614
  });
1057
1615
  return {
1058
1616
  ok: false,
1059
1617
  status: response.status,
1618
+ statusText: resolveStatusText(response, parsed),
1060
1619
  data: null,
1061
1620
  error: httpError.message,
1062
1621
  errorDetails: detailsFromError(httpError),
@@ -1068,6 +1627,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1068
1627
  return {
1069
1628
  ok: true,
1070
1629
  status: response.status,
1630
+ statusText: resolveStatusText(response, parsed),
1071
1631
  data: payloadData ?? null,
1072
1632
  count: payloadCount,
1073
1633
  error: void 0,
@@ -1087,6 +1647,7 @@ async function callAthena(config, endpoint, method, payload, options) {
1087
1647
  return {
1088
1648
  ok: false,
1089
1649
  status: 0,
1650
+ statusText: null,
1090
1651
  data: null,
1091
1652
  error: networkError.message,
1092
1653
  errorDetails: detailsFromError(networkError),
@@ -1128,10 +1689,29 @@ function createAthenaGatewayClient(config = {}) {
1128
1689
  // src/sql-identifiers.ts
1129
1690
  var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
1130
1691
  var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
1131
- var ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
1692
+ var SQL_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
1693
+ var RESPONSE_ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_.]*)$/i;
1132
1694
  function quoteIdentifierSegment(identifier) {
1133
1695
  return `"${identifier.replace(/"/g, '""')}"`;
1134
1696
  }
1697
+ function parseAliasedIdentifierToken(token) {
1698
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(token);
1699
+ if (responseAliasMatch) {
1700
+ const [, aliasIdentifier2, baseIdentifier2] = responseAliasMatch;
1701
+ if (COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier2) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier2)) {
1702
+ return { baseIdentifier: baseIdentifier2, aliasIdentifier: aliasIdentifier2 };
1703
+ }
1704
+ }
1705
+ const sqlAliasMatch = SQL_ALIAS_PATTERN.exec(token);
1706
+ if (!sqlAliasMatch) {
1707
+ return null;
1708
+ }
1709
+ const [, baseIdentifier, aliasIdentifier] = sqlAliasMatch;
1710
+ if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
1711
+ return null;
1712
+ }
1713
+ return { baseIdentifier, aliasIdentifier };
1714
+ }
1135
1715
  function quoteQualifiedIdentifier(identifier) {
1136
1716
  return identifier.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
1137
1717
  }
@@ -1140,23 +1720,27 @@ function quoteSelectToken(token) {
1140
1720
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
1141
1721
  return quoteQualifiedIdentifier(token);
1142
1722
  }
1143
- const aliasMatch = ALIAS_PATTERN.exec(token);
1144
- if (!aliasMatch) {
1145
- return token;
1146
- }
1147
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
1148
- if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
1723
+ const aliasedIdentifier = parseAliasedIdentifierToken(token);
1724
+ if (!aliasedIdentifier) {
1149
1725
  return token;
1150
1726
  }
1727
+ const { baseIdentifier, aliasIdentifier } = aliasedIdentifier;
1151
1728
  return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
1152
1729
  }
1730
+ function quoteSelectColumnToken(token) {
1731
+ const trimmed = token.trim();
1732
+ if (!trimmed || trimmed === "*") return trimmed || "*";
1733
+ const responseAliasMatch = RESPONSE_ALIAS_PATTERN.exec(trimmed);
1734
+ if (responseAliasMatch) {
1735
+ const [, aliasIdentifier, baseIdentifier] = responseAliasMatch;
1736
+ return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
1737
+ }
1738
+ return quoteQualifiedIdentifier(trimmed);
1739
+ }
1153
1740
  function canAutoQuoteToken(token) {
1154
1741
  if (token === "*") return true;
1155
1742
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
1156
- const aliasMatch = ALIAS_PATTERN.exec(token);
1157
- if (!aliasMatch) return false;
1158
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
1159
- return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
1743
+ return parseAliasedIdentifierToken(token) != null;
1160
1744
  }
1161
1745
  function splitTopLevelCommaSeparated(input) {
1162
1746
  const parts = [];
@@ -1240,6 +1824,190 @@ function quoteSelectColumnsExpression(columns) {
1240
1824
  return tokens.map(quoteSelectToken).join(", ");
1241
1825
  }
1242
1826
 
1827
+ // src/auth/react-email.ts
1828
+ var reactEmailRenderModulePromise;
1829
+ function isRecord3(value) {
1830
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1831
+ }
1832
+ function isFunction(value) {
1833
+ return typeof value === "function";
1834
+ }
1835
+ function toStringOrUndefined(value) {
1836
+ if (typeof value !== "string") return void 0;
1837
+ return value;
1838
+ }
1839
+ function nowIsoString() {
1840
+ return (/* @__PURE__ */ new Date()).toISOString();
1841
+ }
1842
+ function emitReactEmailEvent(observe, phase, input = {}) {
1843
+ if (!observe) return;
1844
+ try {
1845
+ observe({
1846
+ phase,
1847
+ timestamp: nowIsoString(),
1848
+ ...input
1849
+ });
1850
+ } catch {
1851
+ }
1852
+ }
1853
+ function mergeRenderDefaults(input, defaults) {
1854
+ return {
1855
+ ...input,
1856
+ pretty: input.pretty ?? defaults?.pretty,
1857
+ includePlainText: input.includePlainText ?? defaults?.includePlainText
1858
+ };
1859
+ }
1860
+ function mergeRuntimeOptions(options) {
1861
+ if (!options) return void 0;
1862
+ return {
1863
+ defaults: options.defaults,
1864
+ observe: options.observe,
1865
+ route: "route" in options ? options.route : void 0
1866
+ };
1867
+ }
1868
+ async function resolveReactEmailRenderModule() {
1869
+ if (!reactEmailRenderModulePromise) {
1870
+ reactEmailRenderModulePromise = (async () => {
1871
+ try {
1872
+ const loaded = await import('@react-email/render');
1873
+ if (!isFunction(loaded.render)) {
1874
+ throw new Error("missing render(...) export");
1875
+ }
1876
+ return {
1877
+ render: loaded.render,
1878
+ toPlainText: isFunction(loaded.toPlainText) ? loaded.toPlainText : void 0,
1879
+ pretty: isFunction(loaded.pretty) ? loaded.pretty : void 0
1880
+ };
1881
+ } catch (error) {
1882
+ const message = error instanceof Error ? error.message : String(error);
1883
+ throw new Error(
1884
+ `React Email rendering requires @react-email/render. Install it in your project (for example: pnpm add @react-email/render). Loader error: ${message}`
1885
+ );
1886
+ }
1887
+ })();
1888
+ }
1889
+ if (!reactEmailRenderModulePromise) {
1890
+ throw new Error("React Email renderer module failed to initialize");
1891
+ }
1892
+ return reactEmailRenderModulePromise;
1893
+ }
1894
+ async function resolveReactEmailElement(input) {
1895
+ if (input.element != null) {
1896
+ return input.element;
1897
+ }
1898
+ if (!input.component) {
1899
+ throw new Error("react email payload requires either `element` or `component`");
1900
+ }
1901
+ try {
1902
+ const reactModule = await import('react');
1903
+ if (typeof reactModule.createElement !== "function") {
1904
+ throw new Error("react createElement(...) export is unavailable");
1905
+ }
1906
+ return reactModule.createElement(
1907
+ input.component,
1908
+ input.props ?? {}
1909
+ );
1910
+ } catch (error) {
1911
+ const message = error instanceof Error ? error.message : String(error);
1912
+ throw new Error(
1913
+ `React Email component rendering requires react runtime support. Install react in your project. Loader error: ${message}`
1914
+ );
1915
+ }
1916
+ }
1917
+ async function renderAthenaReactEmail(input, options) {
1918
+ if (!isRecord3(input)) {
1919
+ throw new Error("react email payload must be an object");
1920
+ }
1921
+ const runtimeOptions = mergeRuntimeOptions(options);
1922
+ const start = Date.now();
1923
+ emitReactEmailEvent(runtimeOptions?.observe, "render:start", {
1924
+ route: runtimeOptions?.route,
1925
+ message: "Rendering react email payload"
1926
+ });
1927
+ try {
1928
+ const normalizedInput = mergeRenderDefaults(input, runtimeOptions?.defaults);
1929
+ const element = await resolveReactEmailElement(normalizedInput);
1930
+ const renderModule = await resolveReactEmailRenderModule();
1931
+ const htmlValue = await renderModule.render(element);
1932
+ const renderedHtml = typeof htmlValue === "string" ? htmlValue : String(htmlValue ?? "");
1933
+ if (!renderedHtml.trim()) {
1934
+ throw new Error("react email renderer returned an empty HTML string");
1935
+ }
1936
+ let html = renderedHtml;
1937
+ if (normalizedInput.pretty && renderModule.pretty) {
1938
+ const prettyValue = await renderModule.pretty(renderedHtml);
1939
+ if (typeof prettyValue === "string" && prettyValue.trim().length > 0) {
1940
+ html = prettyValue;
1941
+ }
1942
+ }
1943
+ const explicitText = toStringOrUndefined(normalizedInput.text);
1944
+ if (explicitText !== void 0) {
1945
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
1946
+ route: runtimeOptions?.route,
1947
+ durationMs: Date.now() - start,
1948
+ message: "Rendered react email with explicit text"
1949
+ });
1950
+ return {
1951
+ html,
1952
+ text: explicitText
1953
+ };
1954
+ }
1955
+ if (normalizedInput.includePlainText === false || !renderModule.toPlainText) {
1956
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
1957
+ route: runtimeOptions?.route,
1958
+ durationMs: Date.now() - start,
1959
+ message: "Rendered react email without plain-text derivation"
1960
+ });
1961
+ return { html };
1962
+ }
1963
+ const plainTextValue = await renderModule.toPlainText(html);
1964
+ const plainText = toStringOrUndefined(plainTextValue);
1965
+ emitReactEmailEvent(runtimeOptions?.observe, "render:success", {
1966
+ route: runtimeOptions?.route,
1967
+ durationMs: Date.now() - start,
1968
+ message: plainText ? "Rendered react email with derived plain text" : "Rendered react email HTML only"
1969
+ });
1970
+ if (plainText === void 0) {
1971
+ return { html };
1972
+ }
1973
+ return {
1974
+ html,
1975
+ text: plainText
1976
+ };
1977
+ } catch (error) {
1978
+ const message = error instanceof Error ? error.message : String(error);
1979
+ emitReactEmailEvent(runtimeOptions?.observe, "render:error", {
1980
+ route: runtimeOptions?.route,
1981
+ durationMs: Date.now() - start,
1982
+ error: message,
1983
+ message: "Failed to render react email payload"
1984
+ });
1985
+ throw error;
1986
+ }
1987
+ }
1988
+ async function resolveReactEmailPayloadFields(input, fields, options) {
1989
+ const { react, ...payloadWithoutReact } = input;
1990
+ if (!react) {
1991
+ return payloadWithoutReact;
1992
+ }
1993
+ const rendered = await renderAthenaReactEmail(react, options);
1994
+ const payload = {
1995
+ ...payloadWithoutReact
1996
+ };
1997
+ payload[fields.htmlField] = rendered.html;
1998
+ const currentTextValue = payload[fields.textField];
1999
+ if (rendered.text !== void 0 && (currentTextValue === void 0 || currentTextValue === null || currentTextValue === "")) {
2000
+ payload[fields.textField] = rendered.text;
2001
+ }
2002
+ if (fields.variablesField && (payload[fields.variablesField] === void 0 || payload[fields.variablesField] === null) && isRecord3(react.props)) {
2003
+ const derivedVariables = Object.keys(react.props);
2004
+ if (derivedVariables.length > 0) {
2005
+ payload[fields.variablesField] = derivedVariables;
2006
+ }
2007
+ }
2008
+ return payload;
2009
+ }
2010
+
1243
2011
  // src/auth/client.ts
1244
2012
  var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
1245
2013
  var FALLBACK_SDK_VERSION2 = "1.0.0";
@@ -1249,7 +2017,7 @@ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
1249
2017
  function normalizeBaseUrl(baseUrl) {
1250
2018
  return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
1251
2019
  }
1252
- function isRecord2(value) {
2020
+ function isRecord4(value) {
1253
2021
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1254
2022
  }
1255
2023
  function normalizeHeaderValue2(value) {
@@ -1274,7 +2042,7 @@ function resolveRequestId2(headers) {
1274
2042
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
1275
2043
  }
1276
2044
  function resolveErrorMessage2(payload, fallback) {
1277
- if (isRecord2(payload)) {
2045
+ if (isRecord4(payload)) {
1278
2046
  const messageCandidates = [payload.error, payload.message, payload.details];
1279
2047
  for (const candidate of messageCandidates) {
1280
2048
  if (typeof candidate === "string" && candidate.trim().length > 0) {
@@ -1600,6 +2368,19 @@ function createAuthClient(config = {}) {
1600
2368
  options
1601
2369
  );
1602
2370
  };
2371
+ const withReactEmailRoute = (route) => ({
2372
+ ...resolvedConfig.reactEmail,
2373
+ route
2374
+ });
2375
+ const resolveAdminEmailPayload = (route, input) => resolveReactEmailPayloadFields(input, {
2376
+ htmlField: "htmlBody",
2377
+ textField: "textBody"
2378
+ }, withReactEmailRoute(route));
2379
+ const resolveAdminEmailTemplatePayload = (route, input) => resolveReactEmailPayloadFields(input, {
2380
+ htmlField: "htmlTemplate",
2381
+ textField: "textTemplate",
2382
+ variablesField: "variables"
2383
+ }, withReactEmailRoute(route));
1603
2384
  const listUserEmailsWithFallback = async (input, options) => {
1604
2385
  const primary = await getWithQuery(
1605
2386
  "/email/list",
@@ -1627,7 +2408,7 @@ function createAuthClient(config = {}) {
1627
2408
  data: null
1628
2409
  };
1629
2410
  }
1630
- const fallbackStatus = isRecord2(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
2411
+ const fallbackStatus = isRecord4(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
1631
2412
  return {
1632
2413
  ...fallback,
1633
2414
  data: {
@@ -2063,8 +2844,16 @@ function createAuthClient(config = {}) {
2063
2844
  email: {
2064
2845
  list: (input, options) => getWithQuery("/admin/email/list", input, options),
2065
2846
  get: (input, options) => getWithQuery("/admin/email/get", input, options),
2066
- create: (input, options) => postGeneric("/admin/email/create", input, options),
2067
- update: (input, options) => postGeneric("/admin/email/update", input, options),
2847
+ create: async (input, options) => postGeneric(
2848
+ "/admin/email/create",
2849
+ await resolveAdminEmailPayload("/admin/email/create", input),
2850
+ options
2851
+ ),
2852
+ update: async (input, options) => postGeneric(
2853
+ "/admin/email/update",
2854
+ await resolveAdminEmailPayload("/admin/email/update", input),
2855
+ options
2856
+ ),
2068
2857
  delete: (input, options) => postGeneric("/admin/email/delete", input, options),
2069
2858
  failure: {
2070
2859
  list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
@@ -2076,17 +2865,33 @@ function createAuthClient(config = {}) {
2076
2865
  template: {
2077
2866
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
2078
2867
  get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
2079
- create: (input, options) => postGeneric("/admin/email-template/create", input, options),
2080
- update: (input, options) => postGeneric("/admin/email-template/update", input, options),
2868
+ create: async (input, options) => postGeneric(
2869
+ "/admin/email-template/create",
2870
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
2871
+ options
2872
+ ),
2873
+ update: async (input, options) => postGeneric(
2874
+ "/admin/email-template/update",
2875
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
2876
+ options
2877
+ ),
2081
2878
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
2082
2879
  }
2083
2880
  },
2084
2881
  emailTemplate: {
2085
2882
  get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
2086
- create: (input, options) => postGeneric("/admin/email-template/create", input, options),
2883
+ create: async (input, options) => postGeneric(
2884
+ "/admin/email-template/create",
2885
+ await resolveAdminEmailTemplatePayload("/admin/email-template/create", input),
2886
+ options
2887
+ ),
2087
2888
  delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
2088
2889
  list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
2089
- update: (input, options) => postGeneric("/admin/email-template/update", input, options)
2890
+ update: async (input, options) => postGeneric(
2891
+ "/admin/email-template/update",
2892
+ await resolveAdminEmailTemplatePayload("/admin/email-template/update", input),
2893
+ options
2894
+ )
2090
2895
  }
2091
2896
  },
2092
2897
  apiKey: {
@@ -2278,16 +3083,313 @@ function createAuthClient(config = {}) {
2278
3083
  };
2279
3084
  }
2280
3085
 
2281
- // src/client.ts
2282
- var DEFAULT_COLUMNS = "*";
3086
+ // src/db/module.ts
3087
+ function createDbModule(input) {
3088
+ const db = {
3089
+ from(table) {
3090
+ return input.from(table);
3091
+ },
3092
+ select(table, columns, options) {
3093
+ return input.from(table).select(columns, options);
3094
+ },
3095
+ insert(table, values, options) {
3096
+ return Array.isArray(values) ? input.from(table).insert(values, options) : input.from(table).insert(values, options);
3097
+ },
3098
+ upsert(table, values, options) {
3099
+ return Array.isArray(values) ? input.from(table).upsert(values, options) : input.from(table).upsert(values, options);
3100
+ },
3101
+ update(table, values, options) {
3102
+ return input.from(table).update(values, options);
3103
+ },
3104
+ delete(table, options) {
3105
+ return input.from(table).delete(options);
3106
+ },
3107
+ rpc(fn, args, options) {
3108
+ return input.rpc(fn, args, options);
3109
+ },
3110
+ query(query, options) {
3111
+ return input.query(query, options);
3112
+ }
3113
+ };
3114
+ return db;
3115
+ }
3116
+
3117
+ // src/query-ast.ts
2283
3118
  var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
3119
+ var FILTER_OPERATORS = /* @__PURE__ */ new Set([
3120
+ "eq",
3121
+ "neq",
3122
+ "gt",
3123
+ "gte",
3124
+ "lt",
3125
+ "lte",
3126
+ "like",
3127
+ "ilike",
3128
+ "is",
3129
+ "in",
3130
+ "contains",
3131
+ "containedBy"
3132
+ ]);
3133
+ var BOOLEAN_SAFE_OPERATORS = /* @__PURE__ */ new Set([
3134
+ "eq",
3135
+ "neq",
3136
+ "gt",
3137
+ "gte",
3138
+ "lt",
3139
+ "lte",
3140
+ "like",
3141
+ "ilike",
3142
+ "is"
3143
+ ]);
3144
+ function isRecord5(value) {
3145
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3146
+ }
3147
+ function isUuidString(value) {
3148
+ return UUID_PATTERN.test(value.trim());
3149
+ }
3150
+ function isUuidIdentifierColumn(column) {
3151
+ return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
3152
+ }
3153
+ function shouldUseUuidTextComparison(column, value) {
3154
+ return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
3155
+ }
3156
+ function isRelationSelectNode(value) {
3157
+ return isRecord5(value) && isRecord5(value.select);
3158
+ }
3159
+ function normalizeIdentifier(value, label) {
3160
+ const normalized = value.trim();
3161
+ if (!normalized) {
3162
+ throw new Error(`${label} must be a non-empty string`);
3163
+ }
3164
+ return normalized;
3165
+ }
3166
+ function stringifyFilterValue(value) {
3167
+ if (Array.isArray(value)) {
3168
+ return value.join(",");
3169
+ }
3170
+ return String(value);
3171
+ }
3172
+ function buildGatewayCondition(operator, column, value) {
3173
+ const condition = { operator };
3174
+ if (column) {
3175
+ condition.column = column;
3176
+ if (operator === "eq") {
3177
+ condition.eq_column = column;
3178
+ }
3179
+ }
3180
+ if (value !== void 0) {
3181
+ condition.value = value;
3182
+ if (operator === "eq") {
3183
+ condition.eq_value = value;
3184
+ }
3185
+ }
3186
+ if (operator === "eq" && column && value !== void 0 && shouldUseUuidTextComparison(column, value)) {
3187
+ condition.column_cast = "text";
3188
+ condition.eq_column_cast = "text";
3189
+ }
3190
+ return condition;
3191
+ }
3192
+ function compileRelationToken(key, node) {
3193
+ const nested = compileSelectShape(node.select);
3194
+ const propertyKey = normalizeIdentifier(key, "select relation key");
3195
+ const relationToken = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
3196
+ const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
3197
+ const prefix = alias ? `${alias}:` : "";
3198
+ return `${prefix}${relationToken}(${nested})`;
3199
+ }
3200
+ function compileSelectShape(select) {
3201
+ if (!isRecord5(select)) {
3202
+ throw new Error("findMany select must be an object");
3203
+ }
3204
+ const tokens = [];
3205
+ for (const [rawKey, rawValue] of Object.entries(select)) {
3206
+ if (rawValue === void 0) {
3207
+ continue;
3208
+ }
3209
+ if (rawValue === true) {
3210
+ tokens.push(normalizeIdentifier(rawKey, "select column"));
3211
+ continue;
3212
+ }
3213
+ if (isRelationSelectNode(rawValue)) {
3214
+ tokens.push(compileRelationToken(rawKey, rawValue));
3215
+ continue;
3216
+ }
3217
+ throw new Error(`Unsupported select node for "${rawKey}"`);
3218
+ }
3219
+ if (tokens.length === 0) {
3220
+ throw new Error("findMany select requires at least one field");
3221
+ }
3222
+ return tokens.join(",");
3223
+ }
3224
+ function compileColumnWhere(column, input) {
3225
+ const normalizedColumn = normalizeIdentifier(column, "where column");
3226
+ if (!isRecord5(input)) {
3227
+ return [buildGatewayCondition("eq", normalizedColumn, input)];
3228
+ }
3229
+ const conditions = [];
3230
+ for (const [rawOperator, rawValue] of Object.entries(input)) {
3231
+ if (rawValue === void 0) {
3232
+ continue;
3233
+ }
3234
+ if (!FILTER_OPERATORS.has(rawOperator)) {
3235
+ throw new Error(`Unsupported where operator "${rawOperator}" on "${normalizedColumn}"`);
3236
+ }
3237
+ if ((rawOperator === "in" || rawOperator === "contains" || rawOperator === "containedBy") && !Array.isArray(rawValue)) {
3238
+ throw new Error(`where.${normalizedColumn}.${rawOperator} requires an array value`);
3239
+ }
3240
+ conditions.push(
3241
+ buildGatewayCondition(
3242
+ rawOperator,
3243
+ normalizedColumn,
3244
+ rawValue
3245
+ )
3246
+ );
3247
+ }
3248
+ if (conditions.length === 0) {
3249
+ throw new Error(`where.${normalizedColumn} requires at least one operator`);
3250
+ }
3251
+ return conditions;
3252
+ }
3253
+ function compileBooleanExpressionTerms(clause, label) {
3254
+ if (!isRecord5(clause)) {
3255
+ throw new Error(`findMany where.${label} clauses must be objects`);
3256
+ }
3257
+ const entries = Object.entries(clause).filter(([, value]) => value !== void 0);
3258
+ if (entries.length !== 1) {
3259
+ throw new Error(`findMany where.${label} clauses must target exactly one column`);
3260
+ }
3261
+ const [rawColumn, rawValue] = entries[0];
3262
+ const column = normalizeIdentifier(rawColumn, `where.${label} column`);
3263
+ if (!isRecord5(rawValue)) {
3264
+ return [`${column}.eq.${stringifyFilterValue(rawValue)}`];
3265
+ }
3266
+ const operatorEntries = Object.entries(rawValue).filter(([, value]) => value !== void 0);
3267
+ if (operatorEntries.length === 0) {
3268
+ throw new Error(`findMany where.${label}.${column} requires at least one operator`);
3269
+ }
3270
+ if (label === "not" && operatorEntries.length > 1) {
3271
+ throw new Error("findMany where.not only supports a single lossless operator expression");
3272
+ }
3273
+ return operatorEntries.map(([rawOperator, rawOperand]) => {
3274
+ if (!BOOLEAN_SAFE_OPERATORS.has(rawOperator)) {
3275
+ throw new Error(`findMany where.${label} only supports lossless scalar operators`);
3276
+ }
3277
+ if (Array.isArray(rawOperand)) {
3278
+ throw new Error(`findMany where.${label} does not support array-valued operators`);
3279
+ }
3280
+ return `${column}.${rawOperator}.${stringifyFilterValue(rawOperand)}`;
3281
+ });
3282
+ }
3283
+ function compileWhere(where) {
3284
+ if (where === void 0) {
3285
+ return void 0;
3286
+ }
3287
+ if (!isRecord5(where)) {
3288
+ throw new Error("findMany where must be an object");
3289
+ }
3290
+ const conditions = [];
3291
+ for (const [rawKey, rawValue] of Object.entries(where)) {
3292
+ if (rawValue === void 0) {
3293
+ continue;
3294
+ }
3295
+ if (rawKey === "or") {
3296
+ if (!Array.isArray(rawValue) || rawValue.length === 0) {
3297
+ throw new Error("findMany where.or must be a non-empty array");
3298
+ }
3299
+ const expressions = rawValue.flatMap(
3300
+ (value) => compileBooleanExpressionTerms(value, "or")
3301
+ );
3302
+ conditions.push(buildGatewayCondition("or", void 0, expressions.join(",")));
3303
+ continue;
3304
+ }
3305
+ if (rawKey === "not") {
3306
+ const expressions = compileBooleanExpressionTerms(rawValue, "not");
3307
+ if (expressions.length !== 1) {
3308
+ throw new Error("findMany where.not must compile to exactly one lossless expression");
3309
+ }
3310
+ conditions.push(buildGatewayCondition("not", void 0, expressions[0]));
3311
+ continue;
3312
+ }
3313
+ conditions.push(...compileColumnWhere(rawKey, rawValue));
3314
+ }
3315
+ return conditions.length > 0 ? conditions : void 0;
3316
+ }
3317
+ function resolveOrderDirection(input) {
3318
+ if (typeof input === "boolean") {
3319
+ return input === false ? "descending" : "ascending";
3320
+ }
3321
+ if (typeof input === "string") {
3322
+ const normalized = input.trim().toLowerCase();
3323
+ if (normalized === "asc" || normalized === "ascending") {
3324
+ return "ascending";
3325
+ }
3326
+ if (normalized === "desc" || normalized === "descending") {
3327
+ return "descending";
3328
+ }
3329
+ throw new Error(`Unsupported orderBy direction "${input}"`);
3330
+ }
3331
+ return input.ascending === false ? "descending" : "ascending";
3332
+ }
3333
+ function compileOrderBy(orderBy) {
3334
+ if (orderBy === void 0) {
3335
+ return void 0;
3336
+ }
3337
+ if (!isRecord5(orderBy)) {
3338
+ throw new Error("findMany orderBy must be an object");
3339
+ }
3340
+ if ("column" in orderBy) {
3341
+ return {
3342
+ field: normalizeIdentifier(String(orderBy.column), "orderBy column"),
3343
+ direction: orderBy.ascending === false ? "descending" : "ascending"
3344
+ };
3345
+ }
3346
+ const entries = Object.entries(orderBy).filter(([, value]) => value !== void 0);
3347
+ if (entries.length === 0) {
3348
+ return void 0;
3349
+ }
3350
+ if (entries.length > 1) {
3351
+ throw new Error("findMany orderBy only supports a single column in v1");
3352
+ }
3353
+ const [column, input] = entries[0];
3354
+ return {
3355
+ field: normalizeIdentifier(column, "orderBy column"),
3356
+ direction: resolveOrderDirection(input)
3357
+ };
3358
+ }
3359
+
3360
+ // src/client.ts
3361
+ var DEFAULT_COLUMNS = "*";
2284
3362
  var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
3363
+ var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
3364
+ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
3365
+ "src\\client.ts",
3366
+ "src/client.ts",
3367
+ "dist\\client.",
3368
+ "dist/client.",
3369
+ "node_modules\\@xylex-group\\athena",
3370
+ "node_modules/@xylex-group/athena",
3371
+ "node:internal",
3372
+ "internal/process"
3373
+ ];
3374
+ function canUseFindManyAstTransport(state) {
3375
+ return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
3376
+ }
3377
+ function toFindManyAstOrder(order) {
3378
+ if (!order) {
3379
+ return void 0;
3380
+ }
3381
+ return {
3382
+ column: order.field,
3383
+ ascending: order.direction !== "descending"
3384
+ };
3385
+ }
2285
3386
  function formatResult(response) {
2286
3387
  const result = {
2287
3388
  data: response.data ?? null,
2288
- error: response.error ?? null,
3389
+ error: null,
2289
3390
  errorDetails: response.errorDetails ?? null,
2290
3391
  status: response.status,
3392
+ statusText: response.statusText ?? null,
2291
3393
  raw: response.raw
2292
3394
  };
2293
3395
  if (response.count !== void 0) {
@@ -2295,6 +3397,245 @@ function formatResult(response) {
2295
3397
  }
2296
3398
  return result;
2297
3399
  }
3400
+ function attachNormalizedError(result, normalizedError) {
3401
+ Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
3402
+ value: normalizedError,
3403
+ enumerable: false,
3404
+ configurable: true,
3405
+ writable: false
3406
+ });
3407
+ }
3408
+ function createResultFormatter(experimental) {
3409
+ return (response, context) => {
3410
+ const result = formatResult(response);
3411
+ if (response.error == null && response.errorDetails == null) {
3412
+ return result;
3413
+ }
3414
+ const normalizedError = normalizeAthenaError(
3415
+ {
3416
+ ...result,
3417
+ error: response.error ?? response.errorDetails?.message ?? null
3418
+ },
3419
+ context
3420
+ );
3421
+ result.error = createResultError(response, result, normalizedError);
3422
+ attachNormalizedError(result, normalizedError);
3423
+ return result;
3424
+ };
3425
+ }
3426
+ function isRecord6(value) {
3427
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3428
+ }
3429
+ function firstNonEmptyString2(...values) {
3430
+ for (const value of values) {
3431
+ if (typeof value === "string" && value.trim().length > 0) {
3432
+ return value.trim();
3433
+ }
3434
+ }
3435
+ return void 0;
3436
+ }
3437
+ function resolveStructuredErrorPayload2(raw) {
3438
+ if (!isRecord6(raw)) return null;
3439
+ return isRecord6(raw.error) ? raw.error : raw;
3440
+ }
3441
+ function resolveStructuredErrorDetails(payload, message) {
3442
+ if (!payload || !("details" in payload)) {
3443
+ return null;
3444
+ }
3445
+ const details = payload.details;
3446
+ if (details == null) {
3447
+ return null;
3448
+ }
3449
+ if (typeof details === "string" && details.trim() === message.trim()) {
3450
+ return null;
3451
+ }
3452
+ return details;
3453
+ }
3454
+ function createResultError(response, result, normalized) {
3455
+ const rawRecord = isRecord6(response.raw) ? response.raw : null;
3456
+ const payload = resolveStructuredErrorPayload2(response.raw);
3457
+ const message = firstNonEmptyString2(
3458
+ response.error,
3459
+ payload?.message,
3460
+ payload?.error,
3461
+ payload?.details,
3462
+ response.errorDetails?.message,
3463
+ normalized.message
3464
+ ) ?? normalized.message;
3465
+ const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
3466
+ const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
3467
+ const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
3468
+ const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
3469
+ return {
3470
+ message,
3471
+ code,
3472
+ athenaCode: normalized.code,
3473
+ gatewayCode: response.errorDetails?.code ?? null,
3474
+ kind: normalized.kind,
3475
+ category: normalized.category,
3476
+ retryable: normalized.retryable,
3477
+ details,
3478
+ hint,
3479
+ status: result.status,
3480
+ statusText,
3481
+ constraint: normalized.constraint,
3482
+ table: normalized.table,
3483
+ operation: normalized.operation,
3484
+ endpoint: response.errorDetails?.endpoint,
3485
+ method: response.errorDetails?.method,
3486
+ requestId: response.errorDetails?.requestId,
3487
+ cause: response.errorDetails?.cause,
3488
+ raw: result.raw
3489
+ };
3490
+ }
3491
+ function parseQueryTraceCallsiteFrame(frame) {
3492
+ const trimmed = frame.trim();
3493
+ if (!trimmed) {
3494
+ return null;
3495
+ }
3496
+ let body = trimmed.replace(/^at\s+/, "");
3497
+ if (body.startsWith("async ")) {
3498
+ body = body.slice(6);
3499
+ }
3500
+ let functionName;
3501
+ let location = body;
3502
+ const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
3503
+ if (wrappedMatch) {
3504
+ functionName = wrappedMatch[1].trim() || void 0;
3505
+ location = wrappedMatch[2].trim();
3506
+ }
3507
+ const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
3508
+ if (!locationMatch) {
3509
+ return null;
3510
+ }
3511
+ const filePath = locationMatch[1].replace(/^file:\/\//, "");
3512
+ const line = Number(locationMatch[2]);
3513
+ const column = Number(locationMatch[3]);
3514
+ if (!Number.isFinite(line) || !Number.isFinite(column)) {
3515
+ return null;
3516
+ }
3517
+ const normalizedPath = filePath.replace(/\\/g, "/");
3518
+ const fileName = normalizedPath.split("/").at(-1) ?? filePath;
3519
+ return {
3520
+ filePath,
3521
+ fileName,
3522
+ line,
3523
+ column,
3524
+ frame: trimmed,
3525
+ functionName
3526
+ };
3527
+ }
3528
+ function captureQueryTraceCallsite() {
3529
+ const stack = new Error().stack;
3530
+ if (!stack) return null;
3531
+ const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
3532
+ for (const frame of frames) {
3533
+ if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
3534
+ continue;
3535
+ }
3536
+ const callsite = parseQueryTraceCallsiteFrame(frame);
3537
+ if (callsite) return callsite;
3538
+ }
3539
+ const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
3540
+ return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
3541
+ }
3542
+ function defaultQueryTraceLogger(event) {
3543
+ const target = event.table ?? event.functionName ?? "gateway";
3544
+ const outcomeState = event.outcome?.error ? "error" : "ok";
3545
+ const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
3546
+ console.info(banner, event);
3547
+ }
3548
+ function captureTraceCallsite(tracer) {
3549
+ return tracer?.captureCallsite() ?? null;
3550
+ }
3551
+ function createTraceCallsiteStore(tracer, initialCallsite) {
3552
+ let storedCallsite = initialCallsite ?? void 0;
3553
+ return {
3554
+ resolve(callsite) {
3555
+ if (callsite) {
3556
+ storedCallsite = callsite;
3557
+ return callsite;
3558
+ }
3559
+ if (storedCallsite !== void 0) {
3560
+ return storedCallsite;
3561
+ }
3562
+ const capturedCallsite = captureTraceCallsite(tracer);
3563
+ if (capturedCallsite) {
3564
+ storedCallsite = capturedCallsite;
3565
+ }
3566
+ return capturedCallsite;
3567
+ }
3568
+ };
3569
+ }
3570
+ function createQueryTracer(experimental) {
3571
+ const traceOption = experimental?.traceQueries;
3572
+ if (!traceOption) {
3573
+ return void 0;
3574
+ }
3575
+ const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
3576
+ const emit = (event) => {
3577
+ try {
3578
+ logger(event);
3579
+ } catch (error) {
3580
+ console.warn("[athena-js][trace] logger failed", error);
3581
+ }
3582
+ };
3583
+ return {
3584
+ captureCallsite: captureQueryTraceCallsite,
3585
+ publishSuccess(context, result, durationMs, callsite) {
3586
+ emit({
3587
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3588
+ durationMs,
3589
+ operation: context.operation,
3590
+ endpoint: context.endpoint,
3591
+ table: context.table,
3592
+ functionName: context.functionName,
3593
+ sql: context.sql,
3594
+ payload: context.payload,
3595
+ options: context.options,
3596
+ callsite,
3597
+ outcome: {
3598
+ status: result.status,
3599
+ error: result.error,
3600
+ errorDetails: result.errorDetails ?? null,
3601
+ count: result.count ?? null,
3602
+ data: result.data,
3603
+ raw: result.raw
3604
+ }
3605
+ });
3606
+ },
3607
+ publishFailure(context, error, durationMs, callsite) {
3608
+ emit({
3609
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3610
+ durationMs,
3611
+ operation: context.operation,
3612
+ endpoint: context.endpoint,
3613
+ table: context.table,
3614
+ functionName: context.functionName,
3615
+ sql: context.sql,
3616
+ payload: context.payload,
3617
+ options: context.options,
3618
+ callsite,
3619
+ thrownError: error
3620
+ });
3621
+ }
3622
+ };
3623
+ }
3624
+ async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
3625
+ if (!tracer) {
3626
+ return runner();
3627
+ }
3628
+ const callsite = callsiteOverride ?? tracer.captureCallsite();
3629
+ const startedAt = Date.now();
3630
+ try {
3631
+ const result = await runner();
3632
+ tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
3633
+ return result;
3634
+ } catch (error) {
3635
+ tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
3636
+ throw error;
3637
+ }
3638
+ }
2298
3639
  function toSingleResult(response) {
2299
3640
  const payload = response.data;
2300
3641
  const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
@@ -2315,15 +3656,16 @@ function asAthenaJsonObject(value) {
2315
3656
  function asAthenaJsonObjectArray(values) {
2316
3657
  return values;
2317
3658
  }
2318
- function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
3659
+ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
2319
3660
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
2320
3661
  let selectedOptions;
2321
3662
  let promise = null;
2322
- const run = (columns, options) => {
3663
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
3664
+ const run = (columns, options, callsite) => {
2323
3665
  const payloadColumns = columns ?? selectedColumns;
2324
3666
  const payloadOptions = options ?? selectedOptions;
2325
3667
  if (!promise) {
2326
- promise = executor(payloadColumns, payloadOptions);
3668
+ promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
2327
3669
  }
2328
3670
  return promise;
2329
3671
  };
@@ -2331,7 +3673,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2331
3673
  select(columns = selectedColumns, options) {
2332
3674
  selectedColumns = columns;
2333
3675
  selectedOptions = options ?? selectedOptions;
2334
- return run(columns, options);
3676
+ return run(columns, options, captureTraceCallsite(tracer));
2335
3677
  },
2336
3678
  returning(columns = selectedColumns, options) {
2337
3679
  return mutationQuery.select(columns, options);
@@ -2339,7 +3681,7 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2339
3681
  single(columns = selectedColumns, options) {
2340
3682
  selectedColumns = columns;
2341
3683
  selectedOptions = options ?? selectedOptions;
2342
- return run(columns, options).then(toSingleResult);
3684
+ return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
2343
3685
  },
2344
3686
  maybeSingle(columns = selectedColumns, options) {
2345
3687
  return mutationQuery.single(columns, options);
@@ -2362,21 +3704,12 @@ function getResourceId(state) {
2362
3704
  );
2363
3705
  return candidate?.value?.toString();
2364
3706
  }
2365
- function stringifyFilterValue(value) {
3707
+ function stringifyFilterValue2(value) {
2366
3708
  if (Array.isArray(value)) {
2367
3709
  return value.join(",");
2368
3710
  }
2369
3711
  return String(value);
2370
3712
  }
2371
- function isUuidString(value) {
2372
- return UUID_PATTERN.test(value.trim());
2373
- }
2374
- function isUuidIdentifierColumn(column) {
2375
- return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
2376
- }
2377
- function shouldUseUuidTextComparison(column, value) {
2378
- return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
2379
- }
2380
3713
  function normalizeCast(cast) {
2381
3714
  const normalized = cast.trim().toLowerCase();
2382
3715
  if (!SAFE_CAST_PATTERN.test(normalized)) {
@@ -2399,25 +3732,92 @@ function withCast(expression, cast) {
2399
3732
  }
2400
3733
  function buildSelectColumnsClause(columns) {
2401
3734
  if (Array.isArray(columns)) {
2402
- return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
3735
+ return columns.map((column) => quoteSelectColumnToken(column)).join(", ");
2403
3736
  }
2404
3737
  return quoteSelectColumnsExpression(columns);
2405
3738
  }
3739
+ function parseIdentifierSegment(input) {
3740
+ const trimmed = input.trim();
3741
+ if (!trimmed) return null;
3742
+ if (!trimmed.startsWith('"')) {
3743
+ return {
3744
+ normalizedValue: trimmed.toLowerCase()
3745
+ };
3746
+ }
3747
+ let value = "";
3748
+ let index = 1;
3749
+ let closed = false;
3750
+ while (index < trimmed.length) {
3751
+ const char = trimmed[index];
3752
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
3753
+ if (char === '"' && next === '"') {
3754
+ value += '"';
3755
+ index += 2;
3756
+ continue;
3757
+ }
3758
+ if (char === '"') {
3759
+ closed = true;
3760
+ index += 1;
3761
+ break;
3762
+ }
3763
+ value += char;
3764
+ index += 1;
3765
+ }
3766
+ if (!closed || trimmed.slice(index).trim().length > 0 || !value.trim()) {
3767
+ return null;
3768
+ }
3769
+ return {
3770
+ normalizedValue: value
3771
+ };
3772
+ }
3773
+ function splitQualifiedTableName(tableName) {
3774
+ const trimmed = tableName.trim();
3775
+ let inQuotes = false;
3776
+ for (let index = 0; index < trimmed.length; index += 1) {
3777
+ const char = trimmed[index];
3778
+ const next = index + 1 < trimmed.length ? trimmed[index + 1] : "";
3779
+ if (char === '"') {
3780
+ if (inQuotes && next === '"') {
3781
+ index += 1;
3782
+ continue;
3783
+ }
3784
+ inQuotes = !inQuotes;
3785
+ continue;
3786
+ }
3787
+ if (char === "." && !inQuotes) {
3788
+ const schemaSegment = trimmed.slice(0, index).trim();
3789
+ const tableSegment = trimmed.slice(index + 1).trim();
3790
+ if (!schemaSegment || !tableSegment) {
3791
+ return null;
3792
+ }
3793
+ return { schemaSegment };
3794
+ }
3795
+ }
3796
+ return null;
3797
+ }
2406
3798
  function resolveTableNameForCall(tableName, schema) {
2407
3799
  if (!schema) return tableName;
2408
3800
  const normalizedSchema = schema.trim();
2409
3801
  if (!normalizedSchema) {
2410
3802
  throw new Error("schema option must be a non-empty string");
2411
3803
  }
2412
- if (tableName.includes(".")) {
2413
- if (tableName.startsWith(`${normalizedSchema}.`)) {
2414
- return tableName;
3804
+ const normalizedTableName = tableName.trim();
3805
+ const parsedSchema = parseIdentifierSegment(normalizedSchema);
3806
+ if (!parsedSchema) {
3807
+ throw new Error("schema option must be a non-empty string");
3808
+ }
3809
+ const qualified = splitQualifiedTableName(normalizedTableName);
3810
+ if (qualified) {
3811
+ const parsedTableSchema = parseIdentifierSegment(qualified.schemaSegment);
3812
+ const sameSchema = parsedTableSchema ? parsedTableSchema.normalizedValue === parsedSchema.normalizedValue : normalizedTableName.startsWith(`${normalizedSchema}.`);
3813
+ if (sameSchema) {
3814
+ return normalizedTableName;
2415
3815
  }
2416
3816
  throw new Error(
2417
- `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
3817
+ `schema option "${normalizedSchema}" conflicts with schema-qualified table "${normalizedTableName}"`
2418
3818
  );
2419
3819
  }
2420
- return `${normalizedSchema}.${tableName}`;
3820
+ return `${normalizedSchema}.${normalizedTableName}`;
2421
3821
  }
2422
3822
  function conditionToSqlClause(condition) {
2423
3823
  if (!condition.column) return null;
@@ -2495,6 +3895,237 @@ function buildTypedSelectQuery(input) {
2495
3895
  }
2496
3896
  return `${sqlParts.join(" ")};`;
2497
3897
  }
3898
+ function sanitizeSqlComment(comment) {
3899
+ return comment.replace(/\*\//g, "* /");
3900
+ }
3901
+ function toSqlJsonLiteral(value) {
3902
+ if (value === void 0) return "DEFAULT";
3903
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3904
+ return toSqlLiteral(value);
3905
+ }
3906
+ return `'${escapeSqlStringLiteral(JSON.stringify(value))}'::jsonb`;
3907
+ }
3908
+ function conditionToDebugSqlClause(condition) {
3909
+ const exact = conditionToSqlClause(condition);
3910
+ if (exact) return exact;
3911
+ const rawCondition = sanitizeSqlComment(JSON.stringify(condition));
3912
+ if (!condition.column) {
3913
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
3914
+ }
3915
+ const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
3916
+ const value = condition.value;
3917
+ const rhs = withCast(toSqlJsonLiteral(value), condition.value_cast);
3918
+ switch (condition.operator) {
3919
+ case "contains":
3920
+ return `${column} @> ${rhs}`;
3921
+ case "containedBy":
3922
+ return `${column} <@ ${rhs}`;
3923
+ case "not":
3924
+ return `TRUE /* NOT expression passthrough: ${rawCondition} */`;
3925
+ case "or":
3926
+ return `TRUE /* OR expression passthrough: ${rawCondition} */`;
3927
+ default:
3928
+ return `TRUE /* unsupported condition: ${rawCondition} */`;
3929
+ }
3930
+ }
3931
+ function resolvePagination(input) {
3932
+ let limit = input.limit;
3933
+ let offset = input.offset;
3934
+ if (limit === void 0 && input.pageSize !== void 0) {
3935
+ limit = input.pageSize;
3936
+ }
3937
+ if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
3938
+ offset = (input.currentPage - 1) * input.pageSize;
3939
+ }
3940
+ return { limit, offset };
3941
+ }
3942
+ function appendOrderLimitOffset(sqlParts, order, limit, offset) {
3943
+ if (order?.field) {
3944
+ const direction = order.direction === "descending" ? "DESC" : "ASC";
3945
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(order.field)} ${direction}`);
3946
+ }
3947
+ if (limit !== void 0) {
3948
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
3949
+ }
3950
+ if (offset !== void 0) {
3951
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
3952
+ }
3953
+ }
3954
+ function buildDebugSelectQuery(input) {
3955
+ const sqlParts = [
3956
+ `SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
3957
+ ];
3958
+ if (input.conditions?.length) {
3959
+ const whereClauses = input.conditions.map(conditionToDebugSqlClause);
3960
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
3961
+ }
3962
+ const pagination = resolvePagination(input);
3963
+ appendOrderLimitOffset(sqlParts, input.order, pagination.limit, pagination.offset);
3964
+ return `${sqlParts.join(" ")};`;
3965
+ }
3966
+ function resolveDebugTableIdentifier(tableName) {
3967
+ if (!tableName?.trim()) {
3968
+ return '"__unknown_table__"';
3969
+ }
3970
+ return quoteQualifiedIdentifier(tableName);
3971
+ }
3972
+ function buildInsertDebugSql(payload) {
3973
+ const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
3974
+ const columns = [];
3975
+ const seen = /* @__PURE__ */ new Set();
3976
+ for (const row of rows) {
3977
+ for (const column of Object.keys(row)) {
3978
+ if (seen.has(column)) continue;
3979
+ seen.add(column);
3980
+ columns.push(column);
3981
+ }
3982
+ }
3983
+ const sqlParts = [`INSERT INTO ${quoteQualifiedIdentifier(payload.table_name)}`];
3984
+ if (!rows.length || !columns.length) {
3985
+ sqlParts.push("DEFAULT VALUES");
3986
+ if (rows.length > 1) {
3987
+ sqlParts.push(`/* trace: ${rows.length} rows collapsed to DEFAULT VALUES */`);
3988
+ }
3989
+ } else {
3990
+ const valuesClause = rows.map((row) => {
3991
+ const values = columns.map((column) => {
3992
+ const hasColumn = Object.prototype.hasOwnProperty.call(row, column);
3993
+ if (!hasColumn) {
3994
+ return payload.default_to_null ? "NULL" : "DEFAULT";
3995
+ }
3996
+ const rowValue = row[column];
3997
+ return toSqlJsonLiteral(rowValue);
3998
+ });
3999
+ return `(${values.join(", ")})`;
4000
+ }).join(", ");
4001
+ const columnClause = columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
4002
+ sqlParts.push(`(${columnClause})`);
4003
+ sqlParts.push(`VALUES ${valuesClause}`);
4004
+ }
4005
+ if (payload.on_conflict) {
4006
+ const conflictColumns = Array.isArray(payload.on_conflict) ? payload.on_conflict.map((column) => quoteQualifiedIdentifier(column)).join(", ") : payload.on_conflict;
4007
+ if (payload.update_body && Object.keys(payload.update_body).length > 0) {
4008
+ const assignments = Object.entries(payload.update_body).map(
4009
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
4010
+ );
4011
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO UPDATE SET ${assignments.join(", ")}`);
4012
+ } else {
4013
+ sqlParts.push(`ON CONFLICT (${conflictColumns}) DO NOTHING`);
4014
+ }
4015
+ }
4016
+ if (payload.columns) {
4017
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
4018
+ }
4019
+ return `${sqlParts.join(" ")};`;
4020
+ }
4021
+ function buildUpdateDebugSql(payload) {
4022
+ const set = payload.set ?? payload.data ?? {};
4023
+ const assignments = Object.entries(set).map(
4024
+ ([column, value]) => `${quoteQualifiedIdentifier(column)} = ${toSqlJsonLiteral(value)}`
4025
+ );
4026
+ const sqlParts = [
4027
+ `UPDATE ${resolveDebugTableIdentifier(payload.table_name)} SET ${assignments.length ? assignments.join(", ") : "/* empty set */"}`
4028
+ ];
4029
+ if (payload.conditions?.length) {
4030
+ const whereClauses = payload.conditions.map(conditionToDebugSqlClause);
4031
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
4032
+ }
4033
+ const pagination = resolvePagination({
4034
+ currentPage: payload.current_page,
4035
+ pageSize: payload.page_size
4036
+ });
4037
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
4038
+ if (payload.columns) {
4039
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
4040
+ }
4041
+ return `${sqlParts.join(" ")};`;
4042
+ }
4043
+ function buildDeleteDebugSql(payload) {
4044
+ const sqlParts = [`DELETE FROM ${quoteQualifiedIdentifier(payload.table_name)}`];
4045
+ const whereClauses = [];
4046
+ if (payload.resource_id) {
4047
+ whereClauses.push(`"resource_id" = ${toSqlLiteral(payload.resource_id)}`);
4048
+ }
4049
+ if (payload.conditions?.length) {
4050
+ whereClauses.push(...payload.conditions.map(conditionToDebugSqlClause));
4051
+ }
4052
+ if (whereClauses.length) {
4053
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
4054
+ }
4055
+ const pagination = resolvePagination({
4056
+ currentPage: payload.current_page,
4057
+ pageSize: payload.page_size
4058
+ });
4059
+ appendOrderLimitOffset(sqlParts, payload.sort_by, pagination.limit, pagination.offset);
4060
+ if (payload.columns) {
4061
+ sqlParts.push(`RETURNING ${buildSelectColumnsClause(payload.columns)}`);
4062
+ }
4063
+ return `${sqlParts.join(" ")};`;
4064
+ }
4065
+ function rpcFilterToSqlClause(filter) {
4066
+ const column = quoteQualifiedIdentifier(filter.column);
4067
+ const value = filter.value;
4068
+ switch (filter.operator) {
4069
+ case "eq":
4070
+ case "neq":
4071
+ case "gt":
4072
+ case "gte":
4073
+ case "lt":
4074
+ case "lte":
4075
+ case "like":
4076
+ case "ilike": {
4077
+ if (value === void 0 || Array.isArray(value)) {
4078
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4079
+ }
4080
+ const operatorMap = {
4081
+ eq: "=",
4082
+ neq: "!=",
4083
+ gt: ">",
4084
+ gte: ">=",
4085
+ lt: "<",
4086
+ lte: "<=",
4087
+ like: "LIKE",
4088
+ ilike: "ILIKE"
4089
+ };
4090
+ return `${column} ${operatorMap[filter.operator]} ${toSqlLiteral(value)}`;
4091
+ }
4092
+ case "is":
4093
+ if (value === null) return `${column} IS NULL`;
4094
+ if (value === true) return `${column} IS TRUE`;
4095
+ if (value === false) return `${column} IS FALSE`;
4096
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4097
+ case "in":
4098
+ if (!Array.isArray(value)) {
4099
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4100
+ }
4101
+ if (value.length === 0) return "FALSE";
4102
+ return `${column} IN (${value.map((item) => toSqlLiteral(item)).join(", ")})`;
4103
+ default:
4104
+ return `TRUE /* unsupported rpc filter: ${sanitizeSqlComment(JSON.stringify(filter))} */`;
4105
+ }
4106
+ }
4107
+ function buildRpcDebugSql(payload) {
4108
+ const argsEntries = payload.args ? Object.entries(payload.args) : [];
4109
+ const argsClause = argsEntries.map(([key, value]) => `${quoteQualifiedIdentifier(key)} => ${toSqlJsonLiteral(value)}`).join(", ");
4110
+ const functionRef = payload.schema ? `${quoteQualifiedIdentifier(payload.schema)}.${quoteQualifiedIdentifier(payload.function)}` : quoteQualifiedIdentifier(payload.function);
4111
+ const sqlParts = [
4112
+ `SELECT ${payload.select ? quoteSelectColumnsExpression(payload.select) : "*"} FROM ${functionRef}(${argsClause})`
4113
+ ];
4114
+ if (payload.filters?.length) {
4115
+ sqlParts.push(`WHERE ${payload.filters.map(rpcFilterToSqlClause).join(" AND ")}`);
4116
+ }
4117
+ if (payload.order?.column) {
4118
+ const direction = payload.order.ascending === false ? "DESC" : "ASC";
4119
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(payload.order.column)} ${direction}`);
4120
+ }
4121
+ if (payload.limit !== void 0) {
4122
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(payload.limit))}`);
4123
+ }
4124
+ if (payload.offset !== void 0) {
4125
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(payload.offset))}`);
4126
+ }
4127
+ return `${sqlParts.join(" ")};`;
4128
+ }
2498
4129
  function createFilterMethods(state, addCondition, self) {
2499
4130
  return {
2500
4131
  eq(column, value) {
@@ -2606,7 +4237,7 @@ function createFilterMethods(state, addCondition, self) {
2606
4237
  not(columnOrExpression, operator, value) {
2607
4238
  const expression = String(columnOrExpression);
2608
4239
  if (operator != null && value !== void 0) {
2609
- addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
4240
+ addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue2(value)}`);
2610
4241
  } else {
2611
4242
  addCondition("not", void 0, expression);
2612
4243
  }
@@ -2669,14 +4300,15 @@ function createRpcFilterMethods(filters, self) {
2669
4300
  }
2670
4301
  };
2671
4302
  }
2672
- function createRpcBuilder(functionName, args, baseOptions, client) {
4303
+ function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
2673
4304
  const state = {
2674
4305
  filters: []
2675
4306
  };
2676
4307
  let selectedColumns;
2677
4308
  let selectedOptions;
2678
4309
  let promise = null;
2679
- const executeRpc = async (columns, options) => {
4310
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
4311
+ const executeRpc = async (columns, options, callsite) => {
2680
4312
  const mergedOptions = mergeOptions(baseOptions, options);
2681
4313
  const payload = {
2682
4314
  function: functionName,
@@ -2690,14 +4322,30 @@ function createRpcBuilder(functionName, args, baseOptions, client) {
2690
4322
  offset: state.offset,
2691
4323
  order: state.order
2692
4324
  };
2693
- const response = await client.rpcGateway(payload, mergedOptions);
2694
- return formatResult(response);
4325
+ const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
4326
+ const sql = buildRpcDebugSql(payload);
4327
+ return executeWithQueryTrace(
4328
+ tracer,
4329
+ {
4330
+ operation: "rpc",
4331
+ endpoint,
4332
+ functionName,
4333
+ sql,
4334
+ payload,
4335
+ options: mergedOptions
4336
+ },
4337
+ async () => {
4338
+ const response = await client.rpcGateway(payload, mergedOptions);
4339
+ return formatGatewayResult(response, { operation: "rpc" });
4340
+ },
4341
+ callsite
4342
+ );
2695
4343
  };
2696
- const run = (columns, options) => {
4344
+ const run = (columns, options, callsite) => {
2697
4345
  const payloadColumns = columns ?? selectedColumns;
2698
4346
  const payloadOptions = options ?? selectedOptions;
2699
4347
  if (!promise) {
2700
- promise = executeRpc(payloadColumns, payloadOptions);
4348
+ promise = executeRpc(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
2701
4349
  }
2702
4350
  return promise;
2703
4351
  };
@@ -2707,10 +4355,10 @@ function createRpcBuilder(functionName, args, baseOptions, client) {
2707
4355
  select(columns = selectedColumns, options) {
2708
4356
  selectedColumns = columns;
2709
4357
  selectedOptions = options ?? selectedOptions;
2710
- return run(columns, options);
4358
+ return run(columns, options, captureTraceCallsite(tracer));
2711
4359
  },
2712
4360
  async single(columns, options) {
2713
- const result = await run(columns, options);
4361
+ const result = await run(columns, options, captureTraceCallsite(tracer));
2714
4362
  return toSingleResult(result);
2715
4363
  },
2716
4364
  maybeSingle(columns, options) {
@@ -2745,7 +4393,7 @@ function createRpcBuilder(functionName, args, baseOptions, client) {
2745
4393
  });
2746
4394
  return builder;
2747
4395
  }
2748
- function createTableBuilder(tableName, client) {
4396
+ function createTableBuilder(tableName, client, formatGatewayResult, tracer, experimental) {
2749
4397
  const state = {
2750
4398
  conditions: []
2751
4399
  };
@@ -2777,15 +4425,24 @@ function createTableBuilder(tableName, client) {
2777
4425
  }
2778
4426
  state.conditions.push(condition);
2779
4427
  };
4428
+ const snapshotState = () => ({
4429
+ conditions: state.conditions.map((condition) => ({ ...condition })),
4430
+ limit: state.limit,
4431
+ offset: state.offset,
4432
+ order: state.order ? { ...state.order } : void 0,
4433
+ currentPage: state.currentPage,
4434
+ pageSize: state.pageSize,
4435
+ totalPages: state.totalPages
4436
+ });
2780
4437
  const builder = {};
2781
4438
  const filterMethods = createFilterMethods(
2782
4439
  state,
2783
4440
  addCondition,
2784
4441
  builder
2785
4442
  );
2786
- const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
4443
+ const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
2787
4444
  const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
2788
- const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
4445
+ const conditions = executionState.conditions.length ? executionState.conditions.map((condition) => ({ ...condition })) : void 0;
2789
4446
  const hasTypedEqualityComparison = conditions?.some(
2790
4447
  (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
2791
4448
  ) ?? false;
@@ -2794,53 +4451,107 @@ function createTableBuilder(tableName, client) {
2794
4451
  tableName: resolvedTableName,
2795
4452
  columns,
2796
4453
  conditions,
2797
- limit: state.limit,
2798
- offset: state.offset,
2799
- currentPage: state.currentPage,
2800
- pageSize: state.pageSize,
2801
- order: state.order
4454
+ limit: executionState.limit,
4455
+ offset: executionState.offset,
4456
+ currentPage: executionState.currentPage,
4457
+ pageSize: executionState.pageSize,
4458
+ order: executionState.order
2802
4459
  });
2803
4460
  if (query) {
2804
- const queryResponse = await client.queryGateway({ query }, options);
2805
- return formatResult(queryResponse);
4461
+ const payload2 = { query };
4462
+ return executeWithQueryTrace(
4463
+ tracer,
4464
+ {
4465
+ operation: "select",
4466
+ endpoint: "/gateway/query",
4467
+ table: resolvedTableName,
4468
+ sql: query,
4469
+ payload: payload2,
4470
+ options
4471
+ },
4472
+ async () => {
4473
+ const queryResponse = await client.queryGateway(payload2, options);
4474
+ return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
4475
+ },
4476
+ callsite
4477
+ );
2806
4478
  }
2807
4479
  }
2808
4480
  const payload = {
2809
4481
  table_name: resolvedTableName,
2810
4482
  columns,
2811
4483
  conditions,
2812
- limit: state.limit,
2813
- offset: state.offset,
2814
- current_page: state.currentPage,
2815
- page_size: state.pageSize,
2816
- total_pages: state.totalPages,
2817
- sort_by: state.order,
4484
+ limit: executionState.limit,
4485
+ offset: executionState.offset,
4486
+ current_page: executionState.currentPage,
4487
+ page_size: executionState.pageSize,
4488
+ total_pages: executionState.totalPages,
4489
+ sort_by: executionState.order,
2818
4490
  strip_nulls: options?.stripNulls ?? true,
2819
4491
  count: options?.count,
2820
4492
  head: options?.head
2821
4493
  };
2822
- const response = await client.fetchGateway(payload, options);
2823
- return formatResult(response);
4494
+ const sql = buildDebugSelectQuery({
4495
+ tableName: resolvedTableName,
4496
+ columns,
4497
+ conditions,
4498
+ limit: executionState.limit,
4499
+ offset: executionState.offset,
4500
+ currentPage: executionState.currentPage,
4501
+ pageSize: executionState.pageSize,
4502
+ order: executionState.order
4503
+ });
4504
+ return executeWithQueryTrace(
4505
+ tracer,
4506
+ {
4507
+ operation: "select",
4508
+ endpoint: "/gateway/fetch",
4509
+ table: resolvedTableName,
4510
+ sql,
4511
+ payload,
4512
+ options
4513
+ },
4514
+ async () => {
4515
+ const response = await client.fetchGateway(payload, options);
4516
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4517
+ },
4518
+ callsite
4519
+ );
2824
4520
  };
2825
- const createSelectChain = (columns, options) => {
4521
+ const createSelectChain = (columns, options, initialCallsite) => {
2826
4522
  const chain = {};
4523
+ const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
2827
4524
  const filterMethods2 = createFilterMethods(state, addCondition, chain);
2828
4525
  Object.assign(chain, filterMethods2, {
2829
4526
  async single(cols, opts) {
2830
- const r = await runSelect(cols ?? columns, opts ?? options);
4527
+ const r = await runSelect(
4528
+ cols ?? columns,
4529
+ opts ?? options,
4530
+ snapshotState(),
4531
+ callsiteStore.resolve(captureTraceCallsite(tracer))
4532
+ );
2831
4533
  return toSingleResult(r);
2832
4534
  },
2833
4535
  maybeSingle(cols, opts) {
2834
4536
  return chain.single(cols, opts);
2835
4537
  },
2836
4538
  then(onfulfilled, onrejected) {
2837
- return runSelect(columns, options).then(onfulfilled, onrejected);
4539
+ return runSelect(
4540
+ columns,
4541
+ options,
4542
+ snapshotState(),
4543
+ callsiteStore.resolve()
4544
+ ).then(onfulfilled, onrejected);
2838
4545
  },
2839
4546
  catch(onrejected) {
2840
- return runSelect(columns, options).catch(onrejected);
4547
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).catch(
4548
+ onrejected
4549
+ );
2841
4550
  },
2842
4551
  finally(onfinally) {
2843
- return runSelect(columns, options).finally(onfinally);
4552
+ return runSelect(columns, options, snapshotState(), callsiteStore.resolve()).finally(
4553
+ onfinally
4554
+ );
2844
4555
  }
2845
4556
  });
2846
4557
  return chain;
@@ -2857,11 +4568,75 @@ function createTableBuilder(tableName, client) {
2857
4568
  return builder;
2858
4569
  },
2859
4570
  select(columns = DEFAULT_COLUMNS, options) {
2860
- return createSelectChain(columns, options);
4571
+ return createSelectChain(columns, options, captureTraceCallsite(tracer));
4572
+ },
4573
+ async findMany(options) {
4574
+ const columns = compileSelectShape(options.select);
4575
+ const baseState = snapshotState();
4576
+ const executionState = snapshotState();
4577
+ const callsite = captureTraceCallsite(tracer);
4578
+ const compiledWhere = compileWhere(options.where);
4579
+ if (compiledWhere?.length) {
4580
+ executionState.conditions.push(...compiledWhere);
4581
+ }
4582
+ if (options.orderBy !== void 0) {
4583
+ executionState.order = compileOrderBy(options.orderBy);
4584
+ }
4585
+ if (options.limit !== void 0) {
4586
+ executionState.limit = options.limit;
4587
+ }
4588
+ if (experimental?.findManyAst && canUseFindManyAstTransport(baseState)) {
4589
+ const resolvedTableName = resolveTableNameForCall(tableName, void 0);
4590
+ const payload = {
4591
+ table_name: resolvedTableName,
4592
+ select: options.select
4593
+ };
4594
+ if (options.where !== void 0) {
4595
+ payload.where = options.where;
4596
+ }
4597
+ const astOrder = toFindManyAstOrder(executionState.order);
4598
+ if (astOrder !== void 0) {
4599
+ payload.orderBy = astOrder;
4600
+ }
4601
+ if (executionState.limit !== void 0) {
4602
+ payload.limit = executionState.limit;
4603
+ }
4604
+ const sql = buildDebugSelectQuery({
4605
+ tableName: resolvedTableName,
4606
+ columns,
4607
+ conditions: executionState.conditions,
4608
+ limit: executionState.limit,
4609
+ order: executionState.order
4610
+ });
4611
+ return executeWithQueryTrace(
4612
+ tracer,
4613
+ {
4614
+ operation: "select",
4615
+ endpoint: "/gateway/fetch",
4616
+ table: resolvedTableName,
4617
+ sql,
4618
+ payload
4619
+ },
4620
+ async () => {
4621
+ const response = await client.fetchGateway(
4622
+ payload
4623
+ );
4624
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4625
+ },
4626
+ callsite
4627
+ );
4628
+ }
4629
+ return runSelect(
4630
+ columns,
4631
+ void 0,
4632
+ executionState,
4633
+ callsite
4634
+ );
2861
4635
  },
2862
4636
  insert(values, options) {
4637
+ const mutationCallsite = captureTraceCallsite(tracer);
2863
4638
  if (Array.isArray(values)) {
2864
- const executeInsertMany = async (columns, selectOptions) => {
4639
+ const executeInsertMany = async (columns, selectOptions, callsite) => {
2865
4640
  const mergedOptions = mergeOptions(options, selectOptions);
2866
4641
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2867
4642
  const payload = {
@@ -2874,12 +4649,27 @@ function createTableBuilder(tableName, client) {
2874
4649
  if (mergedOptions?.defaultToNull !== void 0) {
2875
4650
  payload.default_to_null = mergedOptions.defaultToNull;
2876
4651
  }
2877
- const response = await client.insertGateway(payload, mergedOptions);
2878
- return formatResult(response);
4652
+ const sql = buildInsertDebugSql(payload);
4653
+ return executeWithQueryTrace(
4654
+ tracer,
4655
+ {
4656
+ operation: "insert",
4657
+ endpoint: "/gateway/insert",
4658
+ table: resolvedTableName,
4659
+ sql,
4660
+ payload,
4661
+ options: mergedOptions
4662
+ },
4663
+ async () => {
4664
+ const response = await client.insertGateway(payload, mergedOptions);
4665
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4666
+ },
4667
+ callsite
4668
+ );
2879
4669
  };
2880
- return createMutationQuery(executeInsertMany);
4670
+ return createMutationQuery(executeInsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
2881
4671
  }
2882
- const executeInsertOne = async (columns, selectOptions) => {
4672
+ const executeInsertOne = async (columns, selectOptions, callsite) => {
2883
4673
  const mergedOptions = mergeOptions(options, selectOptions);
2884
4674
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2885
4675
  const payload = {
@@ -2892,14 +4682,30 @@ function createTableBuilder(tableName, client) {
2892
4682
  if (mergedOptions?.defaultToNull !== void 0) {
2893
4683
  payload.default_to_null = mergedOptions.defaultToNull;
2894
4684
  }
2895
- const response = await client.insertGateway(payload, mergedOptions);
2896
- return formatResult(response);
4685
+ const sql = buildInsertDebugSql(payload);
4686
+ return executeWithQueryTrace(
4687
+ tracer,
4688
+ {
4689
+ operation: "insert",
4690
+ endpoint: "/gateway/insert",
4691
+ table: resolvedTableName,
4692
+ sql,
4693
+ payload,
4694
+ options: mergedOptions
4695
+ },
4696
+ async () => {
4697
+ const response = await client.insertGateway(payload, mergedOptions);
4698
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4699
+ },
4700
+ callsite
4701
+ );
2897
4702
  };
2898
- return createMutationQuery(executeInsertOne);
4703
+ return createMutationQuery(executeInsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
2899
4704
  },
2900
4705
  upsert(values, options) {
4706
+ const mutationCallsite = captureTraceCallsite(tracer);
2901
4707
  if (Array.isArray(values)) {
2902
- const executeUpsertMany = async (columns, selectOptions) => {
4708
+ const executeUpsertMany = async (columns, selectOptions, callsite) => {
2903
4709
  const mergedOptions = mergeOptions(options, selectOptions);
2904
4710
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2905
4711
  const payload = {
@@ -2914,12 +4720,27 @@ function createTableBuilder(tableName, client) {
2914
4720
  if (mergedOptions?.defaultToNull !== void 0) {
2915
4721
  payload.default_to_null = mergedOptions.defaultToNull;
2916
4722
  }
2917
- const response = await client.insertGateway(payload, mergedOptions);
2918
- return formatResult(response);
4723
+ const sql = buildInsertDebugSql(payload);
4724
+ return executeWithQueryTrace(
4725
+ tracer,
4726
+ {
4727
+ operation: "upsert",
4728
+ endpoint: "/gateway/insert",
4729
+ table: resolvedTableName,
4730
+ sql,
4731
+ payload,
4732
+ options: mergedOptions
4733
+ },
4734
+ async () => {
4735
+ const response = await client.insertGateway(payload, mergedOptions);
4736
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4737
+ },
4738
+ callsite
4739
+ );
2919
4740
  };
2920
- return createMutationQuery(executeUpsertMany);
4741
+ return createMutationQuery(executeUpsertMany, DEFAULT_COLUMNS, tracer, mutationCallsite);
2921
4742
  }
2922
- const executeUpsertOne = async (columns, selectOptions) => {
4743
+ const executeUpsertOne = async (columns, selectOptions, callsite) => {
2923
4744
  const mergedOptions = mergeOptions(options, selectOptions);
2924
4745
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2925
4746
  const payload = {
@@ -2934,13 +4755,29 @@ function createTableBuilder(tableName, client) {
2934
4755
  if (mergedOptions?.defaultToNull !== void 0) {
2935
4756
  payload.default_to_null = mergedOptions.defaultToNull;
2936
4757
  }
2937
- const response = await client.insertGateway(payload, mergedOptions);
2938
- return formatResult(response);
4758
+ const sql = buildInsertDebugSql(payload);
4759
+ return executeWithQueryTrace(
4760
+ tracer,
4761
+ {
4762
+ operation: "upsert",
4763
+ endpoint: "/gateway/insert",
4764
+ table: resolvedTableName,
4765
+ sql,
4766
+ payload,
4767
+ options: mergedOptions
4768
+ },
4769
+ async () => {
4770
+ const response = await client.insertGateway(payload, mergedOptions);
4771
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
4772
+ },
4773
+ callsite
4774
+ );
2939
4775
  };
2940
- return createMutationQuery(executeUpsertOne);
4776
+ return createMutationQuery(executeUpsertOne, DEFAULT_COLUMNS, tracer, mutationCallsite);
2941
4777
  },
2942
4778
  update(values, options) {
2943
- const executeUpdate = async (columns, selectOptions) => {
4779
+ const mutationCallsite = captureTraceCallsite(tracer);
4780
+ const executeUpdate = async (columns, selectOptions, callsite) => {
2944
4781
  const filters = state.conditions.length ? [...state.conditions] : void 0;
2945
4782
  const mergedOptions = mergeOptions(options, selectOptions);
2946
4783
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
@@ -2955,10 +4792,25 @@ function createTableBuilder(tableName, client) {
2955
4792
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
2956
4793
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
2957
4794
  if (columns) payload.columns = columns;
2958
- const response = await client.updateGateway(payload, mergedOptions);
2959
- return formatResult(response);
4795
+ const sql = buildUpdateDebugSql(payload);
4796
+ return executeWithQueryTrace(
4797
+ tracer,
4798
+ {
4799
+ operation: "update",
4800
+ endpoint: "/gateway/update",
4801
+ table: resolvedTableName,
4802
+ sql,
4803
+ payload,
4804
+ options: mergedOptions
4805
+ },
4806
+ async () => {
4807
+ const response = await client.updateGateway(payload, mergedOptions);
4808
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
4809
+ },
4810
+ callsite
4811
+ );
2960
4812
  };
2961
- const mutation = createMutationQuery(executeUpdate, null);
4813
+ const mutation = createMutationQuery(executeUpdate, null, tracer, mutationCallsite);
2962
4814
  const updateChain = {};
2963
4815
  const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
2964
4816
  Object.assign(updateChain, filterMethods2, mutation);
@@ -2970,7 +4822,8 @@ function createTableBuilder(tableName, client) {
2970
4822
  if (!resourceId && !filters?.length) {
2971
4823
  throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
2972
4824
  }
2973
- const executeDelete = async (columns, selectOptions) => {
4825
+ const mutationCallsite = captureTraceCallsite(tracer);
4826
+ const executeDelete = async (columns, selectOptions, callsite) => {
2974
4827
  const mergedOptions = mergeOptions(options, selectOptions);
2975
4828
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2976
4829
  const payload = {
@@ -2983,13 +4836,33 @@ function createTableBuilder(tableName, client) {
2983
4836
  if (state.pageSize !== void 0) payload.page_size = state.pageSize;
2984
4837
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
2985
4838
  if (columns) payload.columns = columns;
2986
- const response = await client.deleteGateway(payload, mergedOptions);
2987
- return formatResult(response);
4839
+ const sql = buildDeleteDebugSql(payload);
4840
+ return executeWithQueryTrace(
4841
+ tracer,
4842
+ {
4843
+ operation: "delete",
4844
+ endpoint: "/gateway/delete",
4845
+ table: resolvedTableName,
4846
+ sql,
4847
+ payload,
4848
+ options: mergedOptions
4849
+ },
4850
+ async () => {
4851
+ const response = await client.deleteGateway(payload, mergedOptions);
4852
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
4853
+ },
4854
+ callsite
4855
+ );
2988
4856
  };
2989
- return createMutationQuery(executeDelete, null);
4857
+ return createMutationQuery(executeDelete, null, tracer, mutationCallsite);
2990
4858
  },
2991
4859
  async single(columns, options) {
2992
- const response = await builder.select(columns, options);
4860
+ const response = await runSelect(
4861
+ columns ?? DEFAULT_COLUMNS,
4862
+ options,
4863
+ snapshotState(),
4864
+ captureTraceCallsite(tracer)
4865
+ );
2993
4866
  return toSingleResult(response);
2994
4867
  },
2995
4868
  async maybeSingle(columns, options) {
@@ -2998,14 +4871,29 @@ function createTableBuilder(tableName, client) {
2998
4871
  });
2999
4872
  return builder;
3000
4873
  }
3001
- function createQueryBuilder(client) {
4874
+ function createQueryBuilder(client, formatGatewayResult, tracer) {
3002
4875
  return async function query(query, options) {
3003
4876
  const normalizedQuery = query.trim();
3004
4877
  if (!normalizedQuery) {
3005
4878
  throw new Error("query requires a non-empty string");
3006
4879
  }
3007
- const response = await client.queryGateway({ query: normalizedQuery }, options);
3008
- return formatResult(response);
4880
+ const payload = { query: normalizedQuery };
4881
+ const callsite = captureTraceCallsite(tracer);
4882
+ return executeWithQueryTrace(
4883
+ tracer,
4884
+ {
4885
+ operation: "query",
4886
+ endpoint: "/gateway/query",
4887
+ sql: normalizedQuery,
4888
+ payload,
4889
+ options
4890
+ },
4891
+ async () => {
4892
+ const response = await client.queryGateway(payload, options);
4893
+ return formatGatewayResult(response, { operation: "query" });
4894
+ },
4895
+ callsite
4896
+ );
3009
4897
  };
3010
4898
  }
3011
4899
  function createClientFromConfig(config) {
@@ -3016,24 +4904,32 @@ function createClientFromConfig(config) {
3016
4904
  backend: config.backend,
3017
4905
  headers: config.headers
3018
4906
  });
4907
+ const formatGatewayResult = createResultFormatter();
4908
+ const queryTracer = createQueryTracer(config.experimental);
3019
4909
  const auth = createAuthClient(config.auth);
4910
+ const from = (table) => createTableBuilder(table, gateway, formatGatewayResult, queryTracer, config.experimental);
4911
+ const rpc = (fn, args, options) => {
4912
+ const normalizedFn = fn.trim();
4913
+ if (!normalizedFn) {
4914
+ throw new Error("rpc requires a function name");
4915
+ }
4916
+ return createRpcBuilder(
4917
+ normalizedFn,
4918
+ args,
4919
+ options,
4920
+ gateway,
4921
+ formatGatewayResult,
4922
+ queryTracer,
4923
+ captureTraceCallsite(queryTracer)
4924
+ );
4925
+ };
4926
+ const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
4927
+ const db = createDbModule({ from, rpc, query });
3020
4928
  return {
3021
- from(table) {
3022
- return createTableBuilder(table, gateway);
3023
- },
3024
- rpc(fn, args, options) {
3025
- const normalizedFn = fn.trim();
3026
- if (!normalizedFn) {
3027
- throw new Error("rpc requires a function name");
3028
- }
3029
- return createRpcBuilder(
3030
- normalizedFn,
3031
- args,
3032
- options,
3033
- gateway
3034
- );
3035
- },
3036
- query: createQueryBuilder(gateway),
4929
+ from,
4930
+ db,
4931
+ rpc,
4932
+ query,
3037
4933
  auth: auth.auth
3038
4934
  };
3039
4935
  }
@@ -3042,77 +4938,16 @@ function toBackendConfig(b) {
3042
4938
  if (!b) return DEFAULT_BACKEND;
3043
4939
  return typeof b === "string" ? { type: b } : b;
3044
4940
  }
3045
- var AthenaClientBuilderImpl = class {
3046
- baseUrl;
3047
- apiKey;
3048
- backendConfig = DEFAULT_BACKEND;
3049
- clientName;
3050
- defaultHeaders;
3051
- isHealthTrackingEnabled = false;
3052
- url(url) {
3053
- this.baseUrl = url;
3054
- return this;
3055
- }
3056
- key(apiKey) {
3057
- this.apiKey = apiKey;
3058
- return this;
3059
- }
3060
- backend(backend) {
3061
- this.backendConfig = toBackendConfig(backend);
3062
- return this;
3063
- }
3064
- client(clientName) {
3065
- this.clientName = clientName;
3066
- return this;
3067
- }
3068
- headers(headers) {
3069
- this.defaultHeaders = headers;
3070
- return this;
3071
- }
3072
- healthTracking(enabled) {
3073
- this.isHealthTrackingEnabled = enabled;
3074
- return this;
3075
- }
3076
- build() {
3077
- if (!this.baseUrl || !this.apiKey) {
3078
- throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
3079
- }
3080
- return createClientFromConfig({
3081
- baseUrl: this.baseUrl,
3082
- apiKey: this.apiKey,
3083
- client: this.clientName,
3084
- backend: this.backendConfig,
3085
- headers: this.defaultHeaders,
3086
- healthTracking: this.isHealthTrackingEnabled
3087
- });
3088
- }
3089
- };
3090
- var AthenaClient = class _AthenaClient {
3091
- /** Create a fluent builder for a strongly-typed Athena SDK client. */
3092
- static builder() {
3093
- return new AthenaClientBuilderImpl();
3094
- }
3095
- /** Build a client from process environment variables. */
3096
- static fromEnvironment() {
3097
- const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
3098
- const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
3099
- if (!url || !key) {
3100
- throw new Error(
3101
- "ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
3102
- );
3103
- }
3104
- return _AthenaClient.builder().url(url).key(key).build();
3105
- }
3106
- };
3107
4941
  function createClient(url, apiKey, options) {
3108
- const b = AthenaClient.builder().url(url).key(apiKey).backend(toBackendConfig(options?.backend));
3109
- if (options?.client) b.client(options.client);
3110
- if (options?.headers && Object.keys(options.headers).length > 0) b.headers(options.headers);
3111
- const client = b.build();
3112
- if (options?.auth) {
3113
- client.auth = createAuthClient(options.auth).auth;
3114
- }
3115
- return client;
4942
+ return createClientFromConfig({
4943
+ baseUrl: url,
4944
+ apiKey,
4945
+ client: options?.client,
4946
+ backend: toBackendConfig(options?.backend),
4947
+ headers: options?.headers,
4948
+ auth: options?.auth,
4949
+ experimental: options?.experimental
4950
+ });
3116
4951
  }
3117
4952
 
3118
4953
  // src/schema/postgres-introspection-core.ts
@@ -3462,6 +5297,23 @@ var PostgresCatalogSnapshotAssembler = class {
3462
5297
  table.relations[key] = relation;
3463
5298
  }
3464
5299
  };
5300
+
5301
+ // src/schema/postgres-provider.ts
5302
+ var pgPoolConstructorPromise;
5303
+ async function loadPgPoolConstructor() {
5304
+ if (!pgPoolConstructorPromise) {
5305
+ pgPoolConstructorPromise = import('pg').then((module) => {
5306
+ const poolConstructor = module.Pool ?? module.default?.Pool;
5307
+ if (!poolConstructor) {
5308
+ throw new Error(
5309
+ '@xylex-group/athena: Unable to load the PostgreSQL driver. Ensure "pg" is installed and this API runs in a Node.js server runtime.'
5310
+ );
5311
+ }
5312
+ return poolConstructor;
5313
+ });
5314
+ }
5315
+ return pgPoolConstructorPromise;
5316
+ }
3465
5317
  var PgCatalogClient = class {
3466
5318
  constructor(pool) {
3467
5319
  this.pool = pool;
@@ -3501,7 +5353,8 @@ var PostgresIntrospectionProvider = class {
3501
5353
  }
3502
5354
  async inspect(options) {
3503
5355
  const schemas = options?.schemas && options.schemas.length > 0 ? normalizePostgresCatalogSchemas(options.schemas) : this.schemas;
3504
- const pool = new pg.Pool({
5356
+ const PoolConstructor = await loadPgPoolConstructor();
5357
+ const pool = new PoolConstructor({
3505
5358
  connectionString: this.connectionString
3506
5359
  });
3507
5360
  const catalogClient = new PgCatalogClient(pool);
@@ -3540,7 +5393,7 @@ var AthenaGatewayCatalogClient = class {
3540
5393
  async queryRows(query) {
3541
5394
  const result = await this.client.query(query);
3542
5395
  if (result.error || result.status < 200 || result.status >= 300) {
3543
- throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
5396
+ throw new Error(result.error?.message ?? `Gateway query failed with status ${result.status}`);
3544
5397
  }
3545
5398
  return result.data ?? [];
3546
5399
  }
@@ -3637,10 +5490,24 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
3637
5490
  }
3638
5491
 
3639
5492
  // src/generator/pipeline.ts
5493
+ function canOverwriteArtifact(file) {
5494
+ return file.kind === "model" || file.kind === "schema";
5495
+ }
5496
+ async function fileExists(path) {
5497
+ try {
5498
+ await promises.stat(path);
5499
+ return true;
5500
+ } catch {
5501
+ return false;
5502
+ }
5503
+ }
3640
5504
  async function writeArtifacts(files, cwd) {
3641
5505
  const writtenFiles = [];
3642
5506
  for (const file of files) {
3643
5507
  const absolutePath = path.resolve(cwd, file.path);
5508
+ if (!canOverwriteArtifact(file) && await fileExists(absolutePath)) {
5509
+ continue;
5510
+ }
3644
5511
  await promises.mkdir(path.dirname(absolutePath), { recursive: true });
3645
5512
  await promises.writeFile(absolutePath, file.content, "utf8");
3646
5513
  writtenFiles.push(file.path);