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