@xylex-group/athena 1.9.0 → 2.1.2

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 (45) hide show
  1. package/README.md +86 -68
  2. package/bin/athena-js.js +0 -0
  3. package/dist/browser.cjs +3319 -0
  4. package/dist/browser.cjs.map +1 -0
  5. package/dist/browser.d.cts +25 -0
  6. package/dist/browser.d.ts +25 -0
  7. package/dist/browser.js +3276 -0
  8. package/dist/browser.js.map +1 -0
  9. package/dist/cli/index.cjs +1839 -275
  10. package/dist/cli/index.cjs.map +1 -1
  11. package/dist/cli/index.d.cts +3 -2
  12. package/dist/cli/index.d.ts +3 -2
  13. package/dist/cli/index.js +1840 -276
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/client-BX0NQqOn.d.ts +435 -0
  16. package/dist/client-dpAp-NZK.d.cts +435 -0
  17. package/dist/cookies.cjs +890 -0
  18. package/dist/cookies.cjs.map +1 -0
  19. package/dist/cookies.d.cts +174 -0
  20. package/dist/cookies.d.ts +174 -0
  21. package/dist/cookies.js +869 -0
  22. package/dist/cookies.js.map +1 -0
  23. package/dist/index.cjs +2724 -1777
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +8 -641
  26. package/dist/index.d.ts +8 -641
  27. package/dist/index.js +2725 -1779
  28. package/dist/index.js.map +1 -1
  29. package/dist/model-form-2hqmoOUX.d.ts +1284 -0
  30. package/dist/model-form-Cy-zaO0u.d.cts +1284 -0
  31. package/dist/pipeline-BOPszLsL.d.ts +8 -0
  32. package/dist/pipeline-E3FDbs4W.d.cts +8 -0
  33. package/dist/react.cjs +93 -0
  34. package/dist/react.cjs.map +1 -1
  35. package/dist/react.d.cts +38 -4
  36. package/dist/react.d.ts +38 -4
  37. package/dist/react.js +93 -1
  38. package/dist/react.js.map +1 -1
  39. package/dist/{types-BnzoaNRC.d.cts → types-BaBzjwXr.d.cts} +1 -1
  40. package/dist/{types-BnzoaNRC.d.ts → types-BaBzjwXr.d.ts} +1 -1
  41. package/dist/{pipeline-CQgV-Yfo.d.ts → types-CeBPrnGj.d.ts} +2 -7
  42. package/dist/{pipeline-C-cN0ACi.d.cts → types-CpqL-pZx.d.cts} +2 -7
  43. package/package.json +36 -17
  44. package/dist/model-form-Bm_kqCn2.d.ts +0 -92
  45. package/dist/model-form-DkS48fsh.d.cts +0 -92
package/dist/cli/index.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import { mkdir, writeFile } 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
 
@@ -147,9 +146,13 @@ function resolvePlaceholderMap(baseTokens, outputConfig) {
147
146
  const resolved = {
148
147
  ...baseTokens
149
148
  };
149
+ const reservedTokenKeys = new Set(Object.keys(baseTokens));
150
150
  const entries = Object.entries(outputConfig.placeholderMap ?? {});
151
151
  for (let index = 0; index < entries.length; index += 1) {
152
152
  const [key, value] = entries[index];
153
+ if (reservedTokenKeys.has(key)) {
154
+ continue;
155
+ }
153
156
  let current = value;
154
157
  for (let depth = 0; depth < 8; depth += 1) {
155
158
  const next = renderTemplate(current, resolved);
@@ -290,6 +293,295 @@ function resolvePostgresColumnType(column) {
290
293
  return wrapArrayType(baseType, column.arrayDimensions);
291
294
  }
292
295
 
296
+ // src/gateway/errors.ts
297
+ var AthenaGatewayError = class _AthenaGatewayError extends Error {
298
+ code;
299
+ status;
300
+ endpoint;
301
+ method;
302
+ requestId;
303
+ hint;
304
+ causeDetail;
305
+ constructor(input) {
306
+ super(input.message);
307
+ this.name = "AthenaGatewayError";
308
+ this.code = input.code;
309
+ this.status = input.status ?? 0;
310
+ this.endpoint = input.endpoint;
311
+ this.method = input.method;
312
+ this.requestId = input.requestId;
313
+ this.hint = input.hint;
314
+ this.causeDetail = input.cause;
315
+ }
316
+ toDetails() {
317
+ return {
318
+ code: this.code,
319
+ message: this.message,
320
+ status: this.status,
321
+ endpoint: this.endpoint,
322
+ method: this.method,
323
+ requestId: this.requestId,
324
+ hint: this.hint,
325
+ cause: this.causeDetail
326
+ };
327
+ }
328
+ static fromResponse(response, fallback) {
329
+ const details = response.errorDetails;
330
+ if (details) {
331
+ return new _AthenaGatewayError({
332
+ code: details.code,
333
+ message: details.message,
334
+ status: details.status,
335
+ endpoint: details.endpoint ?? fallback.endpoint,
336
+ method: details.method ?? fallback.method,
337
+ requestId: details.requestId ?? fallback.requestId,
338
+ hint: details.hint,
339
+ cause: details.cause
340
+ });
341
+ }
342
+ return new _AthenaGatewayError({
343
+ code: "HTTP_ERROR",
344
+ message: response.error ?? "Gateway request failed",
345
+ status: response.status,
346
+ endpoint: fallback.endpoint,
347
+ method: fallback.method,
348
+ requestId: fallback.requestId
349
+ });
350
+ }
351
+ };
352
+ function isAthenaGatewayError(error) {
353
+ return error instanceof AthenaGatewayError;
354
+ }
355
+
356
+ // src/auxiliaries.ts
357
+ var AthenaErrorCode = {
358
+ UniqueViolation: "UNIQUE_VIOLATION",
359
+ NotFound: "NOT_FOUND",
360
+ ValidationFailed: "VALIDATION_FAILED",
361
+ AuthUnauthorized: "AUTH_UNAUTHORIZED",
362
+ AuthForbidden: "AUTH_FORBIDDEN",
363
+ RateLimited: "RATE_LIMITED",
364
+ NetworkUnavailable: "NETWORK_UNAVAILABLE",
365
+ TransientFailure: "TRANSIENT_FAILURE",
366
+ HttpFailure: "HTTP_FAILURE",
367
+ Unknown: "UNKNOWN"
368
+ };
369
+ var AthenaErrorCategory = {
370
+ Transport: "transport",
371
+ Client: "client",
372
+ Server: "server",
373
+ Database: "database",
374
+ Unknown: "unknown"
375
+ };
376
+ function parseBooleanFlag(rawValue, fallback) {
377
+ if (!rawValue) return fallback;
378
+ const normalized = rawValue.trim().toLowerCase();
379
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
380
+ return true;
381
+ }
382
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
383
+ return false;
384
+ }
385
+ return fallback;
386
+ }
387
+ function isRecord(value) {
388
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
389
+ }
390
+ function isAthenaErrorKind(value) {
391
+ return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
392
+ }
393
+ function isAthenaErrorCode(value) {
394
+ 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";
395
+ }
396
+ function isAthenaErrorCategory(value) {
397
+ return value === "transport" || value === "client" || value === "server" || value === "database" || value === "unknown";
398
+ }
399
+ function isNormalizedAthenaError(value) {
400
+ return isRecord(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
401
+ }
402
+ function withContextOverrides(normalized, context) {
403
+ if (!context?.table && !context?.operation) {
404
+ return normalized;
405
+ }
406
+ return {
407
+ ...normalized,
408
+ table: context.table ?? normalized.table,
409
+ operation: context.operation ?? normalized.operation
410
+ };
411
+ }
412
+ function resolveAttachedNormalizedError(resultOrError) {
413
+ if (!isRecord(resultOrError)) return void 0;
414
+ if (!("__athenaNormalizedError" in resultOrError)) return void 0;
415
+ const candidate = resultOrError.__athenaNormalizedError;
416
+ return isNormalizedAthenaError(candidate) ? candidate : void 0;
417
+ }
418
+ function isAthenaResultLike(value) {
419
+ return isRecord(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
420
+ }
421
+ function operationFromDetails(details) {
422
+ if (!details?.endpoint) return void 0;
423
+ if (details.endpoint === "/gateway/fetch" || details.endpoint === "/gateway/query") return "select";
424
+ if (details.endpoint === "/gateway/insert") return "insert";
425
+ if (details.endpoint === "/gateway/update") return "update";
426
+ if (details.endpoint === "/gateway/delete") return "delete";
427
+ if (details.endpoint === "/gateway/rpc" || details.endpoint.startsWith("/rpc/")) return "rpc";
428
+ return void 0;
429
+ }
430
+ function matchRegex(input, patterns) {
431
+ for (const pattern of patterns) {
432
+ const match = pattern.exec(input);
433
+ if (match?.[1]) return match[1];
434
+ }
435
+ return void 0;
436
+ }
437
+ function extractConstraint(message) {
438
+ return matchRegex(message, [
439
+ /unique constraint\s+["'`]([^"'`]+)["'`]/i,
440
+ /constraint\s+["'`]([^"'`]+)["'`]/i
441
+ ]);
442
+ }
443
+ function extractTable(message) {
444
+ return matchRegex(message, [
445
+ /(?:table|relation)\s+["'`]([^"'`]+)["'`]/i,
446
+ /on\s+table\s+([a-zA-Z0-9_.]+)/i
447
+ ]);
448
+ }
449
+ function classifyKind(status, code, message) {
450
+ const lower = message.toLowerCase();
451
+ const hasUniquePattern = lower.includes("unique constraint") || lower.includes("duplicate key") || lower.includes("already exists") || lower.includes("duplicate");
452
+ const hasNotFoundPattern = lower.includes("not found") || lower.includes("no rows");
453
+ const hasValidationPattern = lower.includes("validation") || lower.includes("invalid") || lower.includes("malformed");
454
+ const hasAuthPattern = lower.includes("unauthorized") || lower.includes("forbidden") || lower.includes("auth");
455
+ const hasRateLimitPattern = lower.includes("rate limit") || lower.includes("too many requests");
456
+ const hasTransientPattern = lower.includes("timeout") || lower.includes("temporar") || lower.includes("connection reset") || lower.includes("socket") || lower.includes("deadlock");
457
+ if (status === 409 || hasUniquePattern) return "unique_violation";
458
+ if (status === 404 || hasNotFoundPattern) return "not_found";
459
+ if (status === 401 || status === 403 || hasAuthPattern) return "auth";
460
+ if (status === 429 || hasRateLimitPattern) return "rate_limit";
461
+ if (status === 400 || status === 422 || hasValidationPattern) return "validation";
462
+ if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
463
+ return "transient";
464
+ }
465
+ return "unknown";
466
+ }
467
+ function toAthenaErrorCode(kind, status, gatewayCode) {
468
+ if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
469
+ return AthenaErrorCode.NetworkUnavailable;
470
+ }
471
+ switch (kind) {
472
+ case "unique_violation":
473
+ return AthenaErrorCode.UniqueViolation;
474
+ case "not_found":
475
+ return AthenaErrorCode.NotFound;
476
+ case "validation":
477
+ return AthenaErrorCode.ValidationFailed;
478
+ case "rate_limit":
479
+ return AthenaErrorCode.RateLimited;
480
+ case "auth":
481
+ if (status === 403) {
482
+ return AthenaErrorCode.AuthForbidden;
483
+ }
484
+ return AthenaErrorCode.AuthUnauthorized;
485
+ case "transient":
486
+ return status !== void 0 && status >= 500 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.TransientFailure;
487
+ case "unknown":
488
+ default:
489
+ return status !== void 0 && status >= 400 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.Unknown;
490
+ }
491
+ }
492
+ function toAthenaErrorCategory(kind, status) {
493
+ if (kind === "transient" && (status === 0 || status === void 0)) {
494
+ return AthenaErrorCategory.Transport;
495
+ }
496
+ if (kind === "unique_violation") return AthenaErrorCategory.Database;
497
+ if (kind === "validation" || kind === "auth" || kind === "not_found") return AthenaErrorCategory.Client;
498
+ if (kind === "rate_limit" || kind === "transient") return AthenaErrorCategory.Server;
499
+ return AthenaErrorCategory.Unknown;
500
+ }
501
+ function isRetryable(kind, status) {
502
+ if (kind === "rate_limit" || kind === "transient") return true;
503
+ return status !== void 0 && status >= 500;
504
+ }
505
+ function normalizeAthenaError(resultOrError, context) {
506
+ const attached = resolveAttachedNormalizedError(resultOrError);
507
+ if (attached) {
508
+ return withContextOverrides(attached, context);
509
+ }
510
+ if (isAthenaResultLike(resultOrError)) {
511
+ const details = resultOrError.errorDetails;
512
+ const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
513
+ const operation = context?.operation ?? operationFromDetails(details);
514
+ const table = context?.table ?? extractTable(message2);
515
+ const constraint = extractConstraint(message2);
516
+ const kind2 = classifyKind(resultOrError.status, details?.code, message2);
517
+ const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
518
+ const category = toAthenaErrorCategory(kind2, resultOrError.status);
519
+ return {
520
+ kind: kind2,
521
+ code,
522
+ category,
523
+ retryable: isRetryable(kind2, resultOrError.status),
524
+ status: resultOrError.status,
525
+ constraint,
526
+ table,
527
+ operation,
528
+ message: message2,
529
+ raw: resultOrError.raw
530
+ };
531
+ }
532
+ if (isAthenaGatewayError(resultOrError)) {
533
+ const details = resultOrError.toDetails();
534
+ const operation = context?.operation ?? operationFromDetails(details);
535
+ const table = context?.table ?? extractTable(resultOrError.message);
536
+ const constraint = extractConstraint(resultOrError.message);
537
+ const kind2 = classifyKind(resultOrError.status, resultOrError.code, resultOrError.message);
538
+ const code = toAthenaErrorCode(kind2, resultOrError.status, resultOrError.code);
539
+ const category = toAthenaErrorCategory(kind2, resultOrError.status);
540
+ return {
541
+ kind: kind2,
542
+ code,
543
+ category,
544
+ retryable: isRetryable(kind2, resultOrError.status),
545
+ status: resultOrError.status,
546
+ constraint,
547
+ table,
548
+ operation,
549
+ message: resultOrError.message,
550
+ raw: resultOrError
551
+ };
552
+ }
553
+ if (resultOrError instanceof Error) {
554
+ const maybeStatus = isRecord(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
555
+ const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
556
+ return {
557
+ kind: kind2,
558
+ code: toAthenaErrorCode(kind2, maybeStatus),
559
+ category: toAthenaErrorCategory(kind2, maybeStatus),
560
+ retryable: isRetryable(kind2, maybeStatus),
561
+ status: maybeStatus,
562
+ constraint: extractConstraint(resultOrError.message),
563
+ table: context?.table ?? extractTable(resultOrError.message),
564
+ operation: context?.operation,
565
+ message: resultOrError.message,
566
+ raw: resultOrError
567
+ };
568
+ }
569
+ const message = typeof resultOrError === "string" ? resultOrError : "Unknown Athena error";
570
+ const kind = classifyKind(void 0, void 0, message);
571
+ return {
572
+ kind,
573
+ code: toAthenaErrorCode(kind, void 0),
574
+ category: toAthenaErrorCategory(kind, void 0),
575
+ retryable: isRetryable(kind, void 0),
576
+ status: void 0,
577
+ constraint: extractConstraint(message),
578
+ table: context?.table ?? extractTable(message),
579
+ operation: context?.operation,
580
+ message,
581
+ raw: resultOrError
582
+ };
583
+ }
584
+
293
585
  // src/generator/schema-selection.ts
294
586
  var DEFAULT_POSTGRES_SCHEMAS = ["public"];
295
587
  function collectSchemaNames(input) {
@@ -320,6 +612,7 @@ function resolveProviderSchemas(providerConfig) {
320
612
  }
321
613
 
322
614
  // src/generator/config.ts
615
+ var POSTGRES_PROTOCOLS = /* @__PURE__ */ new Set(["postgres:", "postgresql:"]);
323
616
  var DEFAULT_CONFIG_CANDIDATES = [
324
617
  "athena.config.ts",
325
618
  "athena.config.js",
@@ -349,6 +642,184 @@ var DEFAULT_EXPERIMENTAL_FLAGS = {
349
642
  postgresGatewayIntrospection: false,
350
643
  scyllaProviderContracts: true
351
644
  };
645
+ var PROJECT_ENV_FILENAMES = [".env", ".env.local"];
646
+ var DIRECT_CONNECTION_STRING_ENV_KEYS = [
647
+ "ATHENA_GENERATOR_PG_URL",
648
+ "DATABASE_URL",
649
+ "PG_URL",
650
+ "POSTGRES_URL",
651
+ "POSTGRESQL_URL"
652
+ ];
653
+ var POSTGRES_DATABASE_ENV_KEYS = ["ATHENA_GENERATOR_DB", "ATHENA_DATABASE", "PGDATABASE"];
654
+ var POSTGRES_PASSWORD_ENV_KEYS = ["ATHENA_GENERATOR_PG_PASSWORD", "PGPASSWORD"];
655
+ var GATEWAY_URL_ENV_KEYS = ["ATHENA_URL", "ATHENA_GATEWAY_URL", "ATHENA_GENERATOR_URL"];
656
+ var GATEWAY_API_KEY_ENV_KEYS = [
657
+ "ATHENA_API_KEY",
658
+ "ATHENA_GATEWAY_API_KEY",
659
+ "ATHENA_GENERATOR_API_KEY"
660
+ ];
661
+ function normalizeRawEnvValue(rawValue) {
662
+ if (rawValue.startsWith('"') && rawValue.endsWith('"') && rawValue.length >= 2) {
663
+ const inner = rawValue.slice(1, -1);
664
+ return inner.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
665
+ }
666
+ if (rawValue.startsWith("'") && rawValue.endsWith("'") && rawValue.length >= 2) {
667
+ return rawValue.slice(1, -1);
668
+ }
669
+ const commentIndex = rawValue.search(/\s+#/);
670
+ const withoutComment = commentIndex >= 0 ? rawValue.slice(0, commentIndex) : rawValue;
671
+ return withoutComment.trim();
672
+ }
673
+ function parseEnvLine(line) {
674
+ const trimmed = line.trim();
675
+ if (!trimmed || trimmed.startsWith("#")) {
676
+ return void 0;
677
+ }
678
+ const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
679
+ if (!match) {
680
+ return void 0;
681
+ }
682
+ const [, key, rawValue] = match;
683
+ return [key, normalizeRawEnvValue(rawValue.trim())];
684
+ }
685
+ function readProjectEnvEntries(cwd) {
686
+ const nodeEnv = process.env.NODE_ENV?.trim();
687
+ const filenames = [
688
+ ...PROJECT_ENV_FILENAMES,
689
+ ...nodeEnv ? [`.env.${nodeEnv}`, `.env.${nodeEnv}.local`] : []
690
+ ];
691
+ const entries = /* @__PURE__ */ new Map();
692
+ for (const filename of filenames) {
693
+ const absolutePath = resolve(cwd, filename);
694
+ if (!existsSync(absolutePath)) {
695
+ continue;
696
+ }
697
+ const content = readFileSync(absolutePath, "utf8");
698
+ const lines = content.split(/\r?\n/g);
699
+ for (const line of lines) {
700
+ const parsed = parseEnvLine(line);
701
+ if (!parsed) {
702
+ continue;
703
+ }
704
+ const [key, value] = parsed;
705
+ entries.set(key, value);
706
+ }
707
+ }
708
+ return entries;
709
+ }
710
+ function applyProjectEnv(cwd) {
711
+ const envEntries = readProjectEnvEntries(cwd);
712
+ if (envEntries.size === 0) {
713
+ return () => {
714
+ };
715
+ }
716
+ const initialKeys = new Set(
717
+ Object.keys(process.env).filter((key) => process.env[key] !== void 0)
718
+ );
719
+ const staged = /* @__PURE__ */ new Map();
720
+ for (const [key, value] of envEntries.entries()) {
721
+ if (initialKeys.has(key)) {
722
+ continue;
723
+ }
724
+ staged.set(key, value);
725
+ }
726
+ for (const [key, value] of staged.entries()) {
727
+ process.env[key] = value;
728
+ }
729
+ return () => {
730
+ for (const key of staged.keys()) {
731
+ delete process.env[key];
732
+ }
733
+ };
734
+ }
735
+ function readEnvStringValue(key) {
736
+ const value = process.env[key];
737
+ if (typeof value !== "string") {
738
+ return void 0;
739
+ }
740
+ const trimmed = value.trim();
741
+ return trimmed.length > 0 ? trimmed : void 0;
742
+ }
743
+ function resolveFallbackValue(fallbackKeys) {
744
+ for (const key of fallbackKeys) {
745
+ const value = readEnvStringValue(key);
746
+ if (value) {
747
+ return value;
748
+ }
749
+ }
750
+ return void 0;
751
+ }
752
+ function normalizeOptionalString(value, fallbackKeys) {
753
+ if (typeof value === "string") {
754
+ const trimmed = value.trim();
755
+ if (trimmed.length > 0) {
756
+ return trimmed;
757
+ }
758
+ }
759
+ return resolveFallbackValue(fallbackKeys);
760
+ }
761
+ function normalizeRequiredString(value, fieldLabel, fallbackKeys) {
762
+ const resolved = normalizeOptionalString(value, fallbackKeys);
763
+ if (resolved) {
764
+ return resolved;
765
+ }
766
+ throw new Error(
767
+ `Generator config is missing ${fieldLabel}. Set ${fieldLabel} directly or provide one of: ${fallbackKeys.join(", ")}.`
768
+ );
769
+ }
770
+ function applyPostgresPasswordFallback(connectionString) {
771
+ let parsedUrl;
772
+ try {
773
+ parsedUrl = new URL(connectionString);
774
+ } catch {
775
+ return connectionString;
776
+ }
777
+ if (!POSTGRES_PROTOCOLS.has(parsedUrl.protocol)) {
778
+ return connectionString;
779
+ }
780
+ if (!parsedUrl.username || parsedUrl.password) {
781
+ return connectionString;
782
+ }
783
+ const fallbackPassword = resolveFallbackValue(POSTGRES_PASSWORD_ENV_KEYS);
784
+ if (!fallbackPassword) {
785
+ return connectionString;
786
+ }
787
+ parsedUrl.password = fallbackPassword;
788
+ return parsedUrl.toString();
789
+ }
790
+ function normalizeBooleanFlag(rawValue, fallback) {
791
+ if (typeof rawValue === "boolean") {
792
+ return rawValue;
793
+ }
794
+ if (typeof rawValue === "string") {
795
+ return parseBooleanFlag(rawValue, fallback);
796
+ }
797
+ return fallback;
798
+ }
799
+ function normalizeFeatureFlags(input) {
800
+ return {
801
+ emitRelations: normalizeBooleanFlag(
802
+ input?.emitRelations,
803
+ DEFAULT_FEATURES.emitRelations
804
+ ),
805
+ emitRegistry: normalizeBooleanFlag(
806
+ input?.emitRegistry,
807
+ DEFAULT_FEATURES.emitRegistry
808
+ )
809
+ };
810
+ }
811
+ function normalizeExperimentalFlags(input) {
812
+ return {
813
+ postgresGatewayIntrospection: normalizeBooleanFlag(
814
+ input?.postgresGatewayIntrospection,
815
+ DEFAULT_EXPERIMENTAL_FLAGS.postgresGatewayIntrospection
816
+ ),
817
+ scyllaProviderContracts: normalizeBooleanFlag(
818
+ input?.scyllaProviderContracts,
819
+ DEFAULT_EXPERIMENTAL_FLAGS.scyllaProviderContracts
820
+ )
821
+ };
822
+ }
352
823
  function normalizeOutputConfig(output) {
353
824
  return {
354
825
  targets: {
@@ -361,9 +832,41 @@ function normalizeOutputConfig(output) {
361
832
  };
362
833
  }
363
834
  function normalizeProviderConfig(provider) {
364
- if (provider.kind === "postgres") {
835
+ if (provider.kind === "postgres" && provider.mode === "direct") {
836
+ const connectionString = normalizeRequiredString(
837
+ provider.connectionString,
838
+ "provider.connectionString",
839
+ DIRECT_CONNECTION_STRING_ENV_KEYS
840
+ );
841
+ const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS);
842
+ return {
843
+ ...provider,
844
+ connectionString: applyPostgresPasswordFallback(connectionString),
845
+ database,
846
+ schemas: normalizeSchemaSelection(provider.schemas)
847
+ };
848
+ }
849
+ if (provider.kind === "postgres" && provider.mode === "gateway") {
850
+ const gatewayUrl = normalizeRequiredString(
851
+ provider.gatewayUrl,
852
+ "provider.gatewayUrl",
853
+ GATEWAY_URL_ENV_KEYS
854
+ );
855
+ const apiKey = normalizeRequiredString(
856
+ provider.apiKey,
857
+ "provider.apiKey",
858
+ GATEWAY_API_KEY_ENV_KEYS
859
+ );
860
+ const database = normalizeRequiredString(
861
+ provider.database,
862
+ "provider.database",
863
+ POSTGRES_DATABASE_ENV_KEYS
864
+ );
365
865
  return {
366
866
  ...provider,
867
+ gatewayUrl,
868
+ apiKey,
869
+ database,
367
870
  schemas: normalizeSchemaSelection(provider.schemas)
368
871
  };
369
872
  }
@@ -384,14 +887,8 @@ function normalizeGeneratorConfig(input) {
384
887
  ...DEFAULT_NAMING,
385
888
  ...input.naming ?? {}
386
889
  },
387
- features: {
388
- ...DEFAULT_FEATURES,
389
- ...input.features ?? {}
390
- },
391
- experimental: {
392
- ...DEFAULT_EXPERIMENTAL_FLAGS,
393
- ...input.experimental ?? {}
394
- }
890
+ features: normalizeFeatureFlags(input.features),
891
+ experimental: normalizeExperimentalFlags(input.experimental)
395
892
  };
396
893
  }
397
894
  function findGeneratorConfigPath(cwd = process.cwd()) {
@@ -428,6 +925,11 @@ function extractConfigExport(module) {
428
925
  if (moduleExports && typeof moduleExports === "object") {
429
926
  queue.push(moduleExports);
430
927
  }
928
+ for (const value of Object.values(record)) {
929
+ if (value && typeof value === "object") {
930
+ queue.push(value);
931
+ }
932
+ }
431
933
  }
432
934
  throw new Error(
433
935
  "Generator config file must export a config object as default export or `config`."
@@ -442,19 +944,24 @@ function importConfigModule(moduleSpecifier) {
442
944
  }
443
945
  async function loadGeneratorConfig(options = {}) {
444
946
  const cwd = options.cwd ?? process.cwd();
947
+ const restoreProjectEnv = applyProjectEnv(cwd);
445
948
  const resolvedPath = options.configPath ? resolve(cwd, options.configPath) : findGeneratorConfigPath(cwd);
446
949
  if (!resolvedPath) {
447
950
  throw new Error(
448
951
  `No generator config found in ${cwd}. Expected one of: ${DEFAULT_CONFIG_CANDIDATES.join(", ")}`
449
952
  );
450
953
  }
451
- const moduleUrl = pathToFileURL(resolvedPath);
452
- const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
453
- const rawConfig = extractConfigExport(module);
454
- return {
455
- configPath: resolvedPath,
456
- config: normalizeGeneratorConfig(rawConfig)
457
- };
954
+ try {
955
+ const moduleUrl = pathToFileURL(resolvedPath);
956
+ const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
957
+ const rawConfig = extractConfigExport(module);
958
+ return {
959
+ configPath: resolvedPath,
960
+ config: normalizeGeneratorConfig(rawConfig)
961
+ };
962
+ } finally {
963
+ restoreProjectEnv();
964
+ }
458
965
  }
459
966
 
460
967
  // src/generator/renderer.ts
@@ -596,13 +1103,65 @@ function assertNoDuplicatePaths(files) {
596
1103
  [
597
1104
  `Generator output collision detected for path: ${file.path}`,
598
1105
  `Collision: ${existing.kind} and ${file.kind}.`,
599
- "When syncing multiple schemas, include a schema placeholder such as {schema} or {schema_kebab} in model/schema output targets."
1106
+ "Use explicit placeholders such as {model}, {model_kebab}, {schema}, or {schema_kebab} in output targets so each artifact resolves to a unique path."
600
1107
  ].join(" ")
601
1108
  );
602
1109
  }
603
1110
  seen.set(file.path, file);
604
1111
  }
605
1112
  }
1113
+ function addSchemaSegmentToPath(pathValue, schemaName) {
1114
+ const normalizedPath = normalizePath(pathValue);
1115
+ const parsedPath = posix.parse(normalizedPath);
1116
+ const schemaSegment = applyNamingStyle(schemaName, "kebab");
1117
+ if (!schemaSegment) {
1118
+ return normalizedPath;
1119
+ }
1120
+ const dir = parsedPath.dir.length > 0 ? `${parsedPath.dir}/${schemaSegment}` : schemaSegment;
1121
+ return normalizePath(posix.join(dir, parsedPath.base));
1122
+ }
1123
+ function scopeDuplicateDescriptorPathsBySchema(descriptors) {
1124
+ const nextDescriptors = descriptors.map((descriptor) => ({ ...descriptor }));
1125
+ const duplicates = /* @__PURE__ */ new Map();
1126
+ for (let index = 0; index < nextDescriptors.length; index += 1) {
1127
+ const descriptor = nextDescriptors[index];
1128
+ const indexes = duplicates.get(descriptor.filePath) ?? [];
1129
+ indexes.push(index);
1130
+ duplicates.set(descriptor.filePath, indexes);
1131
+ }
1132
+ let appliedSchemaScoping = false;
1133
+ for (const indexes of duplicates.values()) {
1134
+ if (indexes.length <= 1) {
1135
+ continue;
1136
+ }
1137
+ const schemaNames = new Set(indexes.map((index) => nextDescriptors[index].schemaName));
1138
+ if (schemaNames.size <= 1) {
1139
+ continue;
1140
+ }
1141
+ for (const index of indexes) {
1142
+ const descriptor = nextDescriptors[index];
1143
+ descriptor.filePath = addSchemaSegmentToPath(descriptor.filePath, descriptor.schemaName);
1144
+ }
1145
+ appliedSchemaScoping = true;
1146
+ }
1147
+ if (!appliedSchemaScoping) {
1148
+ return nextDescriptors;
1149
+ }
1150
+ const normalizedPaths = /* @__PURE__ */ new Set();
1151
+ for (const descriptor of nextDescriptors) {
1152
+ if (normalizedPaths.has(descriptor.filePath)) {
1153
+ throw new Error(
1154
+ [
1155
+ `Generator output collision detected for path: ${descriptor.filePath}`,
1156
+ "Automatic schema path scoping was applied but collisions remain.",
1157
+ "Add explicit placeholders such as {model}, {model_kebab}, {schema}, or {schema_kebab} to your output targets."
1158
+ ].join(" ")
1159
+ );
1160
+ }
1161
+ normalizedPaths.add(descriptor.filePath);
1162
+ }
1163
+ return nextDescriptors;
1164
+ }
606
1165
  var ArtifactComposer = class {
607
1166
  constructor(snapshot, config) {
608
1167
  this.snapshot = snapshot;
@@ -641,7 +1200,8 @@ var ArtifactComposer = class {
641
1200
  });
642
1201
  }
643
1202
  }
644
- const schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
1203
+ const scopedModelDescriptors = scopeDuplicateDescriptorPathsBySchema(modelDescriptors);
1204
+ let schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
645
1205
  const schemaPath = normalizePath(
646
1206
  renderOutputPath(this.config.output.targets.schema, {
647
1207
  provider: providerName,
@@ -659,9 +1219,10 @@ var ArtifactComposer = class {
659
1219
  this.config.naming.schemaConst,
660
1220
  "schema"
661
1221
  ),
662
- models: modelDescriptors.filter((model) => model.schemaName === schemaName)
1222
+ models: scopedModelDescriptors.filter((model) => model.schemaName === schemaName)
663
1223
  };
664
1224
  });
1225
+ schemaDescriptors = scopeDuplicateDescriptorPathsBySchema(schemaDescriptors);
665
1226
  const databasePath = normalizePath(
666
1227
  renderOutputPath(this.config.output.targets.database, {
667
1228
  provider: providerName,
@@ -681,7 +1242,7 @@ var ArtifactComposer = class {
681
1242
  schemas: schemaDescriptors
682
1243
  };
683
1244
  const files = [];
684
- for (const modelDescriptor of modelDescriptors) {
1245
+ for (const modelDescriptor of scopedModelDescriptors) {
685
1246
  files.push(renderModelArtifact(this.snapshot, modelDescriptor, this.config));
686
1247
  }
687
1248
  for (const schemaDescriptor of schemaDescriptors) {
@@ -720,63 +1281,6 @@ function generateArtifactsFromSnapshot(snapshot, config) {
720
1281
  return new ArtifactComposer(snapshot, normalizedConfig).compose();
721
1282
  }
722
1283
 
723
- // src/gateway/errors.ts
724
- var AthenaGatewayError = class _AthenaGatewayError extends Error {
725
- code;
726
- status;
727
- endpoint;
728
- method;
729
- requestId;
730
- hint;
731
- causeDetail;
732
- constructor(input) {
733
- super(input.message);
734
- this.name = "AthenaGatewayError";
735
- this.code = input.code;
736
- this.status = input.status ?? 0;
737
- this.endpoint = input.endpoint;
738
- this.method = input.method;
739
- this.requestId = input.requestId;
740
- this.hint = input.hint;
741
- this.causeDetail = input.cause;
742
- }
743
- toDetails() {
744
- return {
745
- code: this.code,
746
- message: this.message,
747
- status: this.status,
748
- endpoint: this.endpoint,
749
- method: this.method,
750
- requestId: this.requestId,
751
- hint: this.hint,
752
- cause: this.causeDetail
753
- };
754
- }
755
- static fromResponse(response, fallback) {
756
- const details = response.errorDetails;
757
- if (details) {
758
- return new _AthenaGatewayError({
759
- code: details.code,
760
- message: details.message,
761
- status: details.status,
762
- endpoint: details.endpoint ?? fallback.endpoint,
763
- method: details.method ?? fallback.method,
764
- requestId: details.requestId ?? fallback.requestId,
765
- hint: details.hint,
766
- cause: details.cause
767
- });
768
- }
769
- return new _AthenaGatewayError({
770
- code: "HTTP_ERROR",
771
- message: response.error ?? "Gateway request failed",
772
- status: response.status,
773
- endpoint: fallback.endpoint,
774
- method: fallback.method,
775
- requestId: fallback.requestId
776
- });
777
- }
778
- };
779
-
780
1284
  // src/gateway/client.ts
781
1285
  var DEFAULT_BASE_URL = "https://athena-db.com";
782
1286
  var DEFAULT_CLIENT = "railway_direct";
@@ -802,14 +1306,14 @@ function parseResponseBody(rawText, contentType) {
802
1306
  function normalizeHeaderValue(value) {
803
1307
  return value ? value : void 0;
804
1308
  }
805
- function isRecord(value) {
1309
+ function isRecord2(value) {
806
1310
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
807
1311
  }
808
1312
  function resolveRequestId(headers) {
809
1313
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
810
1314
  }
811
1315
  function resolveErrorMessage(payload, fallback) {
812
- if (isRecord(payload)) {
1316
+ if (isRecord2(payload)) {
813
1317
  const messageCandidates = [payload.error, payload.message, payload.details];
814
1318
  for (const candidate of messageCandidates) {
815
1319
  if (typeof candidate === "string" && candidate.trim().length > 0) {
@@ -999,7 +1503,7 @@ async function callAthena(config, endpoint, method, payload, options) {
999
1503
  };
1000
1504
  }
1001
1505
  const parsed = parsedBody.parsed;
1002
- const parsedPayload = isRecord(parsed) ? parsed : null;
1506
+ const parsedPayload = isRecord2(parsed) ? parsed : null;
1003
1507
  if (!response.ok) {
1004
1508
  const httpError = new AthenaGatewayError({
1005
1509
  code: "HTTP_ERROR",
@@ -1082,126 +1586,1196 @@ function createAthenaGatewayClient(config = {}) {
1082
1586
  }
1083
1587
  };
1084
1588
  }
1085
-
1086
- // src/sql-identifiers.ts
1087
- var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
1088
- var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
1089
- var ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
1090
- function quoteIdentifierSegment(identifier) {
1091
- return `"${identifier.replace(/"/g, '""')}"`;
1589
+
1590
+ // src/sql-identifiers.ts
1591
+ var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
1592
+ var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
1593
+ var ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
1594
+ function quoteIdentifierSegment(identifier) {
1595
+ return `"${identifier.replace(/"/g, '""')}"`;
1596
+ }
1597
+ function quoteQualifiedIdentifier(identifier) {
1598
+ return identifier.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
1599
+ }
1600
+ function quoteSelectToken(token) {
1601
+ if (token === "*") return token;
1602
+ if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
1603
+ return quoteQualifiedIdentifier(token);
1604
+ }
1605
+ const aliasMatch = ALIAS_PATTERN.exec(token);
1606
+ if (!aliasMatch) {
1607
+ return token;
1608
+ }
1609
+ const [, baseIdentifier, aliasIdentifier] = aliasMatch;
1610
+ if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
1611
+ return token;
1612
+ }
1613
+ return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
1614
+ }
1615
+ function canAutoQuoteToken(token) {
1616
+ if (token === "*") return true;
1617
+ if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
1618
+ const aliasMatch = ALIAS_PATTERN.exec(token);
1619
+ if (!aliasMatch) return false;
1620
+ const [, baseIdentifier, aliasIdentifier] = aliasMatch;
1621
+ return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
1622
+ }
1623
+ function splitTopLevelCommaSeparated(input) {
1624
+ const parts = [];
1625
+ let buffer = "";
1626
+ let singleQuoted = false;
1627
+ let doubleQuoted = false;
1628
+ let depth = 0;
1629
+ for (let index = 0; index < input.length; index += 1) {
1630
+ const char = input[index];
1631
+ const next = index + 1 < input.length ? input[index + 1] : "";
1632
+ if (singleQuoted) {
1633
+ buffer += char;
1634
+ if (char === "'" && next === "'") {
1635
+ buffer += next;
1636
+ index += 1;
1637
+ continue;
1638
+ }
1639
+ if (char === "'") {
1640
+ singleQuoted = false;
1641
+ }
1642
+ continue;
1643
+ }
1644
+ if (doubleQuoted) {
1645
+ buffer += char;
1646
+ if (char === '"' && next === '"') {
1647
+ buffer += next;
1648
+ index += 1;
1649
+ continue;
1650
+ }
1651
+ if (char === '"') {
1652
+ doubleQuoted = false;
1653
+ }
1654
+ continue;
1655
+ }
1656
+ if (char === "'") {
1657
+ singleQuoted = true;
1658
+ buffer += char;
1659
+ continue;
1660
+ }
1661
+ if (char === '"') {
1662
+ doubleQuoted = true;
1663
+ buffer += char;
1664
+ continue;
1665
+ }
1666
+ if (char === "(") {
1667
+ depth += 1;
1668
+ buffer += char;
1669
+ continue;
1670
+ }
1671
+ if (char === ")") {
1672
+ depth -= 1;
1673
+ if (depth < 0) return null;
1674
+ buffer += char;
1675
+ continue;
1676
+ }
1677
+ if (char === "," && depth === 0) {
1678
+ parts.push(buffer.trim());
1679
+ buffer = "";
1680
+ continue;
1681
+ }
1682
+ buffer += char;
1683
+ }
1684
+ if (singleQuoted || doubleQuoted || depth !== 0) {
1685
+ return null;
1686
+ }
1687
+ if (buffer.trim().length > 0) {
1688
+ parts.push(buffer.trim());
1689
+ }
1690
+ return parts;
1691
+ }
1692
+ function quoteSelectColumnsExpression(columns) {
1693
+ const trimmed = columns.trim();
1694
+ if (!trimmed || trimmed === "*") return trimmed || "*";
1695
+ const tokens = splitTopLevelCommaSeparated(trimmed);
1696
+ if (!tokens || tokens.length === 0) {
1697
+ return trimmed;
1698
+ }
1699
+ if (!tokens.every(canAutoQuoteToken)) {
1700
+ return trimmed;
1701
+ }
1702
+ return tokens.map(quoteSelectToken).join(", ");
1703
+ }
1704
+
1705
+ // src/auth/client.ts
1706
+ var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
1707
+ var FALLBACK_SDK_VERSION2 = "1.0.0";
1708
+ var SDK_NAME2 = "xylex-group/athena-auth";
1709
+ var SDK_VERSION2 = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION2;
1710
+ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
1711
+ function normalizeBaseUrl(baseUrl) {
1712
+ return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
1713
+ }
1714
+ function isRecord3(value) {
1715
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1716
+ }
1717
+ function normalizeHeaderValue2(value) {
1718
+ return value ? value : void 0;
1719
+ }
1720
+ function parseResponseBody2(rawText, contentType) {
1721
+ if (!rawText) {
1722
+ return { parsed: null, parseFailed: false };
1723
+ }
1724
+ const contentTypeSuggestsJson = contentType?.toLowerCase().includes("application/json") ?? false;
1725
+ const looksJson = contentTypeSuggestsJson || rawText.startsWith("{") || rawText.startsWith("[");
1726
+ if (!looksJson) {
1727
+ return { parsed: rawText, parseFailed: false };
1728
+ }
1729
+ try {
1730
+ return { parsed: JSON.parse(rawText), parseFailed: false };
1731
+ } catch {
1732
+ return { parsed: rawText, parseFailed: true };
1733
+ }
1734
+ }
1735
+ function resolveRequestId2(headers) {
1736
+ return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
1737
+ }
1738
+ function resolveErrorMessage2(payload, fallback) {
1739
+ if (isRecord3(payload)) {
1740
+ const messageCandidates = [payload.error, payload.message, payload.details];
1741
+ for (const candidate of messageCandidates) {
1742
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
1743
+ return candidate.trim();
1744
+ }
1745
+ }
1746
+ }
1747
+ if (typeof payload === "string" && payload.trim().length > 0) {
1748
+ return payload.trim();
1749
+ }
1750
+ return fallback;
1751
+ }
1752
+ function toErrorDetails(input) {
1753
+ return {
1754
+ code: input.code,
1755
+ message: input.message,
1756
+ status: input.status,
1757
+ endpoint: input.endpoint,
1758
+ method: input.method,
1759
+ requestId: input.requestId,
1760
+ hint: input.hint,
1761
+ cause: input.cause
1762
+ };
1763
+ }
1764
+ function mergeCallOptions(base, override) {
1765
+ if (!base && !override) return void 0;
1766
+ return {
1767
+ ...base,
1768
+ ...override,
1769
+ headers: {
1770
+ ...base?.headers ?? {},
1771
+ ...override?.headers ?? {}
1772
+ }
1773
+ };
1774
+ }
1775
+ function extractFetchOptions(input) {
1776
+ if (!input) {
1777
+ return {
1778
+ payload: void 0,
1779
+ fetchOptions: void 0
1780
+ };
1781
+ }
1782
+ const { fetchOptions, ...rest } = input;
1783
+ const hasPayloadKeys = Object.keys(rest).length > 0;
1784
+ return {
1785
+ payload: hasPayloadKeys ? rest : void 0,
1786
+ fetchOptions
1787
+ };
1788
+ }
1789
+ function buildHeaders2(config, options) {
1790
+ const headers = {
1791
+ "Content-Type": "application/json",
1792
+ "X-Athena-Sdk": SDK_HEADER_VALUE2
1793
+ };
1794
+ const apiKey = options?.apiKey ?? config.apiKey;
1795
+ if (apiKey) {
1796
+ headers.apikey = apiKey;
1797
+ headers["x-api-key"] = apiKey;
1798
+ }
1799
+ const bearerToken = options?.bearerToken ?? config.bearerToken;
1800
+ if (bearerToken) {
1801
+ headers.Authorization = `Bearer ${bearerToken}`;
1802
+ }
1803
+ const mergedExtraHeaders = {
1804
+ ...config.headers ?? {},
1805
+ ...options?.headers ?? {}
1806
+ };
1807
+ Object.entries(mergedExtraHeaders).forEach(([key, value]) => {
1808
+ const normalized = normalizeHeaderValue2(value);
1809
+ if (normalized) {
1810
+ headers[key] = normalized;
1811
+ }
1812
+ });
1813
+ return headers;
1814
+ }
1815
+ function appendQueryParam(searchParams, key, value) {
1816
+ if (value === void 0 || value === null) return;
1817
+ if (Array.isArray(value)) {
1818
+ value.forEach((item) => {
1819
+ searchParams.append(key, String(item));
1820
+ });
1821
+ return;
1822
+ }
1823
+ searchParams.append(key, String(value));
1824
+ }
1825
+ function buildRequestUrl(baseUrl, endpoint, query) {
1826
+ const url = `${baseUrl}${endpoint}`;
1827
+ if (!query || Object.keys(query).length === 0) return url;
1828
+ const searchParams = new URLSearchParams();
1829
+ Object.entries(query).forEach(([key, value]) => appendQueryParam(searchParams, key, value));
1830
+ const queryText = searchParams.toString();
1831
+ return queryText ? `${url}?${queryText}` : url;
1832
+ }
1833
+ function inferDefaultMethod(endpoint) {
1834
+ if (endpoint.startsWith("/reset-password/")) {
1835
+ return "GET";
1836
+ }
1837
+ switch (endpoint) {
1838
+ case "/get-session":
1839
+ case "/list-sessions":
1840
+ case "/verify-email":
1841
+ case "/change-email/verify":
1842
+ case "/delete-user/verify":
1843
+ case "/email-list":
1844
+ case "/email/list":
1845
+ case "/delete-user/callback":
1846
+ case "/list-accounts":
1847
+ case "/passkey/generate-register-options":
1848
+ case "/passkey/list-user-passkeys":
1849
+ case "/.well-known/webauthn":
1850
+ case "/admin/list-users":
1851
+ case "/admin/athena-client/list":
1852
+ case "/admin/audit-log/list":
1853
+ case "/admin/email/get":
1854
+ case "/admin/email-failure/list":
1855
+ case "/admin/email-failure/get":
1856
+ case "/admin/email-template/get":
1857
+ case "/admin/email-template/list":
1858
+ case "/admin/email/list":
1859
+ case "/api-key/get":
1860
+ case "/api-key/list":
1861
+ case "/organization/get-full-organization":
1862
+ case "/organization/list":
1863
+ case "/organization/get-invitation":
1864
+ case "/organization/list-invitations":
1865
+ case "/organization/list-user-invitations":
1866
+ case "/organization/list-members":
1867
+ case "/organization/get-active-member":
1868
+ case "/health":
1869
+ case "/ok":
1870
+ case "/error":
1871
+ return "GET";
1872
+ default:
1873
+ return "POST";
1874
+ }
1875
+ }
1876
+ async function callAuthEndpoint(config, context, body, query, options) {
1877
+ const baseUrl = normalizeBaseUrl(options?.baseUrl ?? config.baseUrl);
1878
+ const url = buildRequestUrl(baseUrl, context.endpoint, query);
1879
+ const headers = buildHeaders2(config, options);
1880
+ const credentials = options?.credentials ?? config.credentials ?? "include";
1881
+ const requestInit = {
1882
+ method: context.method,
1883
+ headers,
1884
+ credentials,
1885
+ signal: options?.signal
1886
+ };
1887
+ if (context.method !== "GET") {
1888
+ requestInit.body = JSON.stringify(body ?? {});
1889
+ }
1890
+ const fetcher = config.fetch ?? globalThis.fetch;
1891
+ if (!fetcher) {
1892
+ const details = toErrorDetails({
1893
+ code: "UNKNOWN_ERROR",
1894
+ message: "No fetch implementation available for auth client",
1895
+ status: 0,
1896
+ endpoint: context.endpoint,
1897
+ method: context.method,
1898
+ hint: "Use Node 18+ or provide `fetch` via createClient(..., { auth: { fetch } }) or createAuthClient({ fetch })"
1899
+ });
1900
+ return {
1901
+ ok: false,
1902
+ status: 0,
1903
+ data: null,
1904
+ error: details.message,
1905
+ errorDetails: details,
1906
+ raw: null
1907
+ };
1908
+ }
1909
+ try {
1910
+ const response = await fetcher(url, requestInit);
1911
+ const rawText = await response.text();
1912
+ const requestId = resolveRequestId2(response.headers);
1913
+ const parsedBody = parseResponseBody2(rawText ?? "", response.headers.get("content-type"));
1914
+ if (parsedBody.parseFailed) {
1915
+ const details = toErrorDetails({
1916
+ code: "INVALID_JSON",
1917
+ message: "Auth server returned malformed JSON",
1918
+ status: response.status,
1919
+ endpoint: context.endpoint,
1920
+ method: context.method,
1921
+ requestId,
1922
+ hint: "Verify the auth endpoint response body is valid JSON.",
1923
+ cause: rawText.slice(0, 300)
1924
+ });
1925
+ return {
1926
+ ok: false,
1927
+ status: response.status,
1928
+ data: null,
1929
+ error: details.message,
1930
+ errorDetails: details,
1931
+ raw: parsedBody.parsed
1932
+ };
1933
+ }
1934
+ const parsed = parsedBody.parsed;
1935
+ if (!response.ok) {
1936
+ const details = toErrorDetails({
1937
+ code: "HTTP_ERROR",
1938
+ message: resolveErrorMessage2(
1939
+ parsed,
1940
+ `Auth endpoint ${context.method} ${context.endpoint} failed with status ${response.status}`
1941
+ ),
1942
+ status: response.status,
1943
+ endpoint: context.endpoint,
1944
+ method: context.method,
1945
+ requestId
1946
+ });
1947
+ return {
1948
+ ok: false,
1949
+ status: response.status,
1950
+ data: null,
1951
+ error: details.message,
1952
+ errorDetails: details,
1953
+ raw: parsed
1954
+ };
1955
+ }
1956
+ return {
1957
+ ok: true,
1958
+ status: response.status,
1959
+ data: parsed ?? null,
1960
+ error: null,
1961
+ errorDetails: null,
1962
+ raw: parsed
1963
+ };
1964
+ } catch (callError) {
1965
+ const message = callError instanceof Error ? callError.message : String(callError);
1966
+ const details = toErrorDetails({
1967
+ code: "NETWORK_ERROR",
1968
+ message: `Network error while calling ${context.method} ${context.endpoint}: ${message}`,
1969
+ status: 0,
1970
+ endpoint: context.endpoint,
1971
+ method: context.method,
1972
+ cause: message,
1973
+ hint: "Check auth server URL, DNS, and network reachability."
1974
+ });
1975
+ return {
1976
+ ok: false,
1977
+ status: 0,
1978
+ data: null,
1979
+ error: details.message,
1980
+ errorDetails: details,
1981
+ raw: null
1982
+ };
1983
+ }
1984
+ }
1985
+ function executePostWithCompatibleInput(config, context, input, options) {
1986
+ const { payload, fetchOptions } = extractFetchOptions(input);
1987
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
1988
+ return callAuthEndpoint(config, context, payload ?? {}, void 0, mergedOptions);
1092
1989
  }
1093
- function quoteQualifiedIdentifier(identifier) {
1094
- return identifier.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
1990
+ function executePostWithOptionalInput(config, context, input, options) {
1991
+ const { fetchOptions } = extractFetchOptions(input);
1992
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
1993
+ return callAuthEndpoint(config, context, {}, void 0, mergedOptions);
1095
1994
  }
1096
- function quoteSelectToken(token) {
1097
- if (token === "*") return token;
1098
- if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
1099
- return quoteQualifiedIdentifier(token);
1100
- }
1101
- const aliasMatch = ALIAS_PATTERN.exec(token);
1102
- if (!aliasMatch) {
1103
- return token;
1104
- }
1105
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
1106
- if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
1107
- return token;
1108
- }
1109
- return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
1995
+ function executeGetWithCompatibleInput(config, context, input, options) {
1996
+ const { fetchOptions } = extractFetchOptions(input);
1997
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
1998
+ return callAuthEndpoint(config, context, void 0, void 0, mergedOptions);
1110
1999
  }
1111
- function canAutoQuoteToken(token) {
1112
- if (token === "*") return true;
1113
- if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
1114
- const aliasMatch = ALIAS_PATTERN.exec(token);
1115
- if (!aliasMatch) return false;
1116
- const [, baseIdentifier, aliasIdentifier] = aliasMatch;
1117
- return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
2000
+ function executeGetWithQueryCompatibleInput(config, context, input, options) {
2001
+ const { payload, fetchOptions } = extractFetchOptions(input);
2002
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
2003
+ const query = payload?.query;
2004
+ return callAuthEndpoint(
2005
+ config,
2006
+ context,
2007
+ void 0,
2008
+ query,
2009
+ mergedOptions
2010
+ );
1118
2011
  }
1119
- function splitTopLevelCommaSeparated(input) {
1120
- const parts = [];
1121
- let buffer = "";
1122
- let singleQuoted = false;
1123
- let doubleQuoted = false;
1124
- let depth = 0;
1125
- for (let index = 0; index < input.length; index += 1) {
1126
- const char = input[index];
1127
- const next = index + 1 < input.length ? input[index + 1] : "";
1128
- if (singleQuoted) {
1129
- buffer += char;
1130
- if (char === "'" && next === "'") {
1131
- buffer += next;
1132
- index += 1;
1133
- continue;
2012
+ function createAuthClient(config = {}) {
2013
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
2014
+ const resolvedConfig = {
2015
+ ...config,
2016
+ baseUrl: normalizedBaseUrl
2017
+ };
2018
+ const request = (input, options) => {
2019
+ const method = input.method ?? (input.body !== void 0 ? "POST" : inferDefaultMethod(input.endpoint));
2020
+ const mergedOptions = mergeCallOptions(input.fetchOptions, options);
2021
+ return callAuthEndpoint(
2022
+ resolvedConfig,
2023
+ { endpoint: input.endpoint, method },
2024
+ input.body,
2025
+ input.query,
2026
+ mergedOptions
2027
+ );
2028
+ };
2029
+ const postGeneric = (endpoint, input, options) => {
2030
+ const { payload, fetchOptions } = extractFetchOptions(input);
2031
+ return request(
2032
+ {
2033
+ endpoint,
2034
+ method: "POST",
2035
+ body: payload ?? {},
2036
+ fetchOptions
2037
+ },
2038
+ options
2039
+ );
2040
+ };
2041
+ const getGeneric = (endpoint, input, options) => {
2042
+ const { fetchOptions } = extractFetchOptions(input);
2043
+ return request(
2044
+ {
2045
+ endpoint,
2046
+ method: "GET",
2047
+ fetchOptions
2048
+ },
2049
+ options
2050
+ );
2051
+ };
2052
+ const getWithQuery = (endpoint, input, options) => {
2053
+ const { payload, fetchOptions } = extractFetchOptions(input);
2054
+ const query = payload?.query;
2055
+ return request(
2056
+ {
2057
+ endpoint,
2058
+ method: "GET",
2059
+ query,
2060
+ fetchOptions
2061
+ },
2062
+ options
2063
+ );
2064
+ };
2065
+ const listUserEmailsWithFallback = async (input, options) => {
2066
+ const primary = await getWithQuery(
2067
+ "/email/list",
2068
+ input,
2069
+ options
2070
+ );
2071
+ if (primary.ok || primary.status !== 404 || primary.errorDetails?.code !== "HTTP_ERROR") {
2072
+ return primary;
2073
+ }
2074
+ return getWithQuery(
2075
+ "/email-list",
2076
+ input,
2077
+ options
2078
+ );
2079
+ };
2080
+ const healthWithFallback = async (input, options) => {
2081
+ const primary = await getGeneric("/health", input, options);
2082
+ if (primary.ok || primary.status !== 404 || primary.errorDetails?.code !== "HTTP_ERROR") {
2083
+ return primary;
2084
+ }
2085
+ const fallback = await getGeneric("/ok", input, options);
2086
+ if (!fallback.ok) {
2087
+ return {
2088
+ ...fallback,
2089
+ data: null
2090
+ };
2091
+ }
2092
+ const fallbackStatus = isRecord3(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
2093
+ return {
2094
+ ...fallback,
2095
+ data: {
2096
+ status: fallbackStatus
1134
2097
  }
1135
- if (char === "'") {
1136
- singleQuoted = false;
2098
+ };
2099
+ };
2100
+ const signOut = (input, options) => executePostWithOptionalInput(
2101
+ resolvedConfig,
2102
+ { endpoint: "/sign-out", method: "POST" },
2103
+ input,
2104
+ options
2105
+ );
2106
+ const revokeSessions = (input, options) => executePostWithOptionalInput(
2107
+ resolvedConfig,
2108
+ { endpoint: "/revoke-sessions", method: "POST" },
2109
+ input,
2110
+ options
2111
+ );
2112
+ const revokeOtherSessions = (input, options) => executePostWithOptionalInput(
2113
+ resolvedConfig,
2114
+ { endpoint: "/revoke-other-sessions", method: "POST" },
2115
+ input,
2116
+ options
2117
+ );
2118
+ const revokeSession = (input, options) => executePostWithCompatibleInput(
2119
+ resolvedConfig,
2120
+ { endpoint: "/revoke-session", method: "POST" },
2121
+ input,
2122
+ options
2123
+ );
2124
+ const deleteUser = (input, options) => {
2125
+ const { payload, fetchOptions } = extractFetchOptions(input);
2126
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
2127
+ return callAuthEndpoint(
2128
+ resolvedConfig,
2129
+ { endpoint: "/delete-user", method: "POST" },
2130
+ payload ?? {},
2131
+ void 0,
2132
+ mergedOptions
2133
+ );
2134
+ };
2135
+ const deleteUserCallback = (input, options) => {
2136
+ const { payload, fetchOptions } = extractFetchOptions(input);
2137
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
2138
+ const query = payload ?? {};
2139
+ return callAuthEndpoint(
2140
+ resolvedConfig,
2141
+ { endpoint: "/delete-user/callback", method: "GET" },
2142
+ void 0,
2143
+ {
2144
+ token: query.token,
2145
+ callbackURL: query.callbackURL
2146
+ },
2147
+ mergedOptions
2148
+ );
2149
+ };
2150
+ const resolveResetPasswordToken = (input, options) => {
2151
+ const { payload, fetchOptions } = extractFetchOptions(input);
2152
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
2153
+ const query = payload;
2154
+ const token = query?.token?.trim();
2155
+ if (!token) {
2156
+ throw new Error("resolveResetPasswordToken requires a non-empty token");
2157
+ }
2158
+ const endpoint = `/reset-password/${encodeURIComponent(token)}`;
2159
+ return callAuthEndpoint(
2160
+ resolvedConfig,
2161
+ { endpoint, method: "GET" },
2162
+ void 0,
2163
+ query?.callbackURL ? { callbackURL: query.callbackURL } : void 0,
2164
+ mergedOptions
2165
+ );
2166
+ };
2167
+ const organization = {
2168
+ create: (input, options) => executePostWithCompatibleInput(
2169
+ resolvedConfig,
2170
+ { endpoint: "/organization/create", method: "POST" },
2171
+ input,
2172
+ options
2173
+ ),
2174
+ update: (input, options) => executePostWithCompatibleInput(
2175
+ resolvedConfig,
2176
+ { endpoint: "/organization/update", method: "POST" },
2177
+ input,
2178
+ options
2179
+ ),
2180
+ delete: (input, options) => executePostWithCompatibleInput(
2181
+ resolvedConfig,
2182
+ { endpoint: "/organization/delete", method: "POST" },
2183
+ input,
2184
+ options
2185
+ ),
2186
+ setActive: (input, options) => executePostWithCompatibleInput(
2187
+ resolvedConfig,
2188
+ { endpoint: "/organization/set-active", method: "POST" },
2189
+ input,
2190
+ options
2191
+ ),
2192
+ list: (input, options) => getGeneric(
2193
+ "/organization/list",
2194
+ input,
2195
+ options
2196
+ ),
2197
+ getFull: (input, options) => executeGetWithQueryCompatibleInput(
2198
+ resolvedConfig,
2199
+ { endpoint: "/organization/get-full-organization", method: "GET" },
2200
+ input,
2201
+ options
2202
+ ),
2203
+ checkSlug: (input, options) => executePostWithCompatibleInput(
2204
+ resolvedConfig,
2205
+ { endpoint: "/organization/check-slug", method: "POST" },
2206
+ input,
2207
+ options
2208
+ ),
2209
+ leave: (input, options) => executePostWithCompatibleInput(
2210
+ resolvedConfig,
2211
+ { endpoint: "/organization/leave", method: "POST" },
2212
+ input,
2213
+ options
2214
+ ),
2215
+ listUserInvitations: (input, options) => executeGetWithQueryCompatibleInput(
2216
+ resolvedConfig,
2217
+ { endpoint: "/organization/list-user-invitations", method: "GET" },
2218
+ input,
2219
+ options
2220
+ ),
2221
+ hasPermission: (input, options) => postGeneric(
2222
+ "/organization/has-permission",
2223
+ input,
2224
+ options
2225
+ ),
2226
+ invitation: {
2227
+ cancel: (input, options) => executePostWithCompatibleInput(
2228
+ resolvedConfig,
2229
+ { endpoint: "/organization/cancel-invitation", method: "POST" },
2230
+ input,
2231
+ options
2232
+ ),
2233
+ accept: (input, options) => executePostWithCompatibleInput(
2234
+ resolvedConfig,
2235
+ { endpoint: "/organization/accept-invitation", method: "POST" },
2236
+ input,
2237
+ options
2238
+ ),
2239
+ get: (input, options) => executeGetWithQueryCompatibleInput(
2240
+ resolvedConfig,
2241
+ { endpoint: "/organization/get-invitation", method: "GET" },
2242
+ input,
2243
+ options
2244
+ ),
2245
+ reject: (input, options) => executePostWithCompatibleInput(
2246
+ resolvedConfig,
2247
+ { endpoint: "/organization/reject-invitation", method: "POST" },
2248
+ input,
2249
+ options
2250
+ ),
2251
+ list: (input, options) => executeGetWithQueryCompatibleInput(
2252
+ resolvedConfig,
2253
+ { endpoint: "/organization/list-invitations", method: "GET" },
2254
+ input,
2255
+ options
2256
+ )
2257
+ },
2258
+ member: {
2259
+ remove: (input, options) => executePostWithCompatibleInput(
2260
+ resolvedConfig,
2261
+ { endpoint: "/organization/remove-member", method: "POST" },
2262
+ input,
2263
+ options
2264
+ ),
2265
+ updateRole: (input, options) => executePostWithCompatibleInput(
2266
+ resolvedConfig,
2267
+ { endpoint: "/organization/update-member-role", method: "POST" },
2268
+ input,
2269
+ options
2270
+ ),
2271
+ invite: (input, options) => executePostWithCompatibleInput(
2272
+ resolvedConfig,
2273
+ { endpoint: "/organization/invite-member", method: "POST" },
2274
+ input,
2275
+ options
2276
+ ),
2277
+ getActive: (input, options) => executeGetWithCompatibleInput(
2278
+ resolvedConfig,
2279
+ { endpoint: "/organization/get-active-member", method: "GET" },
2280
+ input,
2281
+ options
2282
+ ),
2283
+ list: (input, options) => executeGetWithQueryCompatibleInput(
2284
+ resolvedConfig,
2285
+ { endpoint: "/organization/list-members", method: "GET" },
2286
+ input,
2287
+ options
2288
+ )
2289
+ }
2290
+ };
2291
+ const authResetPassword = Object.assign(
2292
+ (input, options) => executePostWithCompatibleInput(
2293
+ resolvedConfig,
2294
+ { endpoint: "/reset-password", method: "POST" },
2295
+ input,
2296
+ options
2297
+ ),
2298
+ {
2299
+ token: resolveResetPasswordToken
2300
+ }
2301
+ );
2302
+ const sessionRevokeBinding = (input, options) => {
2303
+ if (Array.isArray(input)) {
2304
+ if (input.length === 0) {
2305
+ throw new Error("session.revoke requires at least one session token");
1137
2306
  }
1138
- continue;
2307
+ if (input.length === 1) {
2308
+ return revokeSession(input[0], options);
2309
+ }
2310
+ return revokeSessions(void 0, options);
1139
2311
  }
1140
- if (doubleQuoted) {
1141
- buffer += char;
1142
- if (char === '"' && next === '"') {
1143
- buffer += next;
1144
- index += 1;
1145
- continue;
2312
+ const parsed = input;
2313
+ const tokens = Array.isArray(parsed.tokens) ? parsed.tokens.filter((token2) => token2.trim().length > 0) : void 0;
2314
+ if (tokens && tokens.length > 1) {
2315
+ return revokeSessions(
2316
+ parsed.fetchOptions ? { fetchOptions: parsed.fetchOptions } : void 0,
2317
+ options
2318
+ );
2319
+ }
2320
+ if (tokens && tokens.length === 1) {
2321
+ return revokeSession(
2322
+ { token: tokens[0], fetchOptions: parsed.fetchOptions },
2323
+ options
2324
+ );
2325
+ }
2326
+ const token = parsed.token?.trim();
2327
+ if (!token) {
2328
+ throw new Error("session.revoke requires a non-empty token or a non-empty token list");
2329
+ }
2330
+ return revokeSession(
2331
+ {
2332
+ token,
2333
+ fetchOptions: parsed.fetchOptions
2334
+ },
2335
+ options
2336
+ );
2337
+ };
2338
+ const adminUserSessionRevokeBinding = (input, options) => {
2339
+ const requireUserId = (userId) => {
2340
+ const trimmed = String(userId ?? "").trim();
2341
+ if (!trimmed) {
2342
+ throw new Error("admin.user.session.revoke requires a non-empty userId");
1146
2343
  }
1147
- if (char === '"') {
1148
- doubleQuoted = false;
2344
+ return trimmed;
2345
+ };
2346
+ const requireSinglePluralUserId = (sessions2) => {
2347
+ const uniqueUserIds = [...new Set(sessions2.map((session) => requireUserId(session.userId)))];
2348
+ if (uniqueUserIds.length !== 1) {
2349
+ throw new Error("admin.user.session.revoke requires the same userId across plural payloads");
1149
2350
  }
1150
- continue;
2351
+ return { userId: uniqueUserIds[0] };
2352
+ };
2353
+ if (Array.isArray(input)) {
2354
+ if (input.length === 0) {
2355
+ throw new Error("admin.user.session.revoke requires at least one payload item");
2356
+ }
2357
+ if (input.length === 1) {
2358
+ return postGeneric(
2359
+ "/admin/revoke-user-session",
2360
+ {
2361
+ ...input[0],
2362
+ userId: requireUserId(input[0].userId)
2363
+ },
2364
+ options
2365
+ );
2366
+ }
2367
+ return postGeneric(
2368
+ "/admin/revoke-user-sessions",
2369
+ requireSinglePluralUserId(input),
2370
+ options
2371
+ );
1151
2372
  }
1152
- if (char === "'") {
1153
- singleQuoted = true;
1154
- buffer += char;
1155
- continue;
2373
+ const parsed = input;
2374
+ const sessions = parsed.sessions;
2375
+ if (sessions && sessions.length === 0) {
2376
+ throw new Error("admin.user.session.revoke requires at least one payload item");
1156
2377
  }
1157
- if (char === '"') {
1158
- doubleQuoted = true;
1159
- buffer += char;
1160
- continue;
2378
+ if (sessions && sessions.length === 1) {
2379
+ return postGeneric(
2380
+ "/admin/revoke-user-session",
2381
+ {
2382
+ ...sessions[0],
2383
+ userId: requireUserId(sessions[0].userId),
2384
+ fetchOptions: parsed.fetchOptions
2385
+ },
2386
+ options
2387
+ );
1161
2388
  }
1162
- if (char === "(") {
1163
- depth += 1;
1164
- buffer += char;
1165
- continue;
2389
+ if (sessions && sessions.length > 1) {
2390
+ return postGeneric(
2391
+ "/admin/revoke-user-sessions",
2392
+ {
2393
+ ...requireSinglePluralUserId(sessions),
2394
+ fetchOptions: parsed.fetchOptions
2395
+ },
2396
+ options
2397
+ );
1166
2398
  }
1167
- if (char === ")") {
1168
- depth -= 1;
1169
- if (depth < 0) return null;
1170
- buffer += char;
1171
- continue;
2399
+ const normalizedUserId = requireUserId(parsed.userId);
2400
+ if (!parsed.sessionToken) {
2401
+ return postGeneric(
2402
+ "/admin/revoke-user-sessions",
2403
+ {
2404
+ userId: normalizedUserId,
2405
+ fetchOptions: parsed.fetchOptions
2406
+ },
2407
+ options
2408
+ );
1172
2409
  }
1173
- if (char === "," && depth === 0) {
1174
- parts.push(buffer.trim());
1175
- buffer = "";
1176
- continue;
2410
+ return postGeneric(
2411
+ "/admin/revoke-user-session",
2412
+ {
2413
+ ...parsed,
2414
+ userId: normalizedUserId
2415
+ },
2416
+ options
2417
+ );
2418
+ };
2419
+ const auth = {
2420
+ getSession: (input, options) => getGeneric("/get-session", input, options),
2421
+ signOut,
2422
+ forgetPassword: (input, options) => postGeneric("/forget-password", input, options),
2423
+ resetPassword: authResetPassword,
2424
+ setPassword: (input, options) => postGeneric("/set-password", input, options),
2425
+ verifyEmail: (input, options) => {
2426
+ const queryInput = {
2427
+ query: {
2428
+ token: input.token,
2429
+ callbackURL: input.callbackURL
2430
+ },
2431
+ fetchOptions: input.fetchOptions
2432
+ };
2433
+ return getWithQuery(
2434
+ "/verify-email",
2435
+ queryInput,
2436
+ options
2437
+ );
2438
+ },
2439
+ sendVerificationEmail: (input, options) => postGeneric("/send-verification-email", input, options),
2440
+ changeEmail: (input, options) => postGeneric("/change-email", input, options),
2441
+ changeEmailVerify: (input, options) => getWithQuery("/change-email/verify", input, options),
2442
+ deleteUserVerify: (input, options) => getWithQuery("/delete-user/verify", input, options),
2443
+ changePassword: (input, options) => postGeneric("/change-password", input, options),
2444
+ user: {
2445
+ update: (input, options) => postGeneric("/update-user", input, options),
2446
+ delete: (input, options) => postGeneric("/delete-user", input, options),
2447
+ email: {
2448
+ list: listUserEmailsWithFallback
2449
+ }
2450
+ },
2451
+ session: {
2452
+ list: (input, options) => getGeneric("/list-sessions", input, options),
2453
+ revoke: sessionRevokeBinding,
2454
+ revokeOther: revokeOtherSessions
2455
+ },
2456
+ social: {
2457
+ link: (input, options) => postGeneric("/link-social", input, options)
2458
+ },
2459
+ account: {
2460
+ list: (input, options) => getGeneric("/list-accounts", input, options),
2461
+ unlink: (input, options) => postGeneric("/unlink-account", input, options)
2462
+ },
2463
+ deleteUser: {
2464
+ callback: deleteUserCallback
2465
+ },
2466
+ refreshToken: (input, options) => postGeneric("/refresh-token", input, options),
2467
+ getAccessToken: (input, options) => postGeneric("/get-access-token", input, options),
2468
+ health: healthWithFallback,
2469
+ ok: (input, options) => getGeneric("/ok", input, options),
2470
+ error: (input, options) => getGeneric("/error", input, options),
2471
+ twoFactor: {
2472
+ getTotpUri: (input, options) => postGeneric("/two-factor/get-totp-uri", input, options),
2473
+ verifyTotp: (input, options) => postGeneric("/two-factor/verify-totp", input, options),
2474
+ sendOtp: (input, options) => postGeneric("/two-factor/send-otp", input, options),
2475
+ verifyOtp: (input, options) => postGeneric("/two-factor/verify-otp", input, options),
2476
+ verifyBackupCode: (input, options) => postGeneric("/two-factor/verify-backup-code", input, options),
2477
+ generateBackupCodes: (input, options) => executePostWithCompatibleInput(
2478
+ resolvedConfig,
2479
+ { endpoint: "/two-factor/generate-backup-codes", method: "POST" },
2480
+ input,
2481
+ options
2482
+ ),
2483
+ enable: (input, options) => postGeneric("/two-factor/enable", input, options),
2484
+ disable: (input, options) => postGeneric("/two-factor/disable", input, options)
2485
+ },
2486
+ passkey: {
2487
+ generateRegisterOptions: (input, options) => getGeneric("/passkey/generate-register-options", input, options),
2488
+ generateAuthenticateOptions: (input, options) => postGeneric("/passkey/generate-authenticate-options", input, options),
2489
+ verifyRegistration: (input, options) => postGeneric("/passkey/verify-registration", input, options),
2490
+ verifyAuthentication: (input, options) => postGeneric("/passkey/verify-authentication", input, options),
2491
+ listUserPasskeys: (input, options) => getGeneric("/passkey/list-user-passkeys", input, options),
2492
+ deletePasskey: (input, options) => postGeneric("/passkey/delete-passkey", input, options),
2493
+ updatePasskey: (input, options) => postGeneric("/passkey/update-passkey", input, options),
2494
+ getRelatedOrigins: (input, options) => getGeneric("/.well-known/webauthn", input, options)
2495
+ },
2496
+ admin: {
2497
+ role: {
2498
+ set: (input, options) => postGeneric("/admin/set-role", input, options)
2499
+ },
2500
+ user: {
2501
+ list: (input, options) => getWithQuery("/admin/list-users", input, options),
2502
+ create: (input, options) => postGeneric("/admin/create-user", input, options),
2503
+ unban: (input, options) => postGeneric("/admin/unban-user", input, options),
2504
+ ban: (input, options) => postGeneric("/admin/ban-user", input, options),
2505
+ impersonate: (input, options) => postGeneric("/admin/impersonate-user", input, options),
2506
+ stopImpersonating: (input, options) => postGeneric("/admin/stop-impersonating", input, options),
2507
+ remove: (input, options) => postGeneric("/admin/remove-user", input, options),
2508
+ setPassword: (input, options) => postGeneric("/admin/set-user-password", input, options),
2509
+ session: {
2510
+ list: (input, options) => postGeneric("/admin/list-user-sessions", input, options),
2511
+ revoke: adminUserSessionRevokeBinding
2512
+ }
2513
+ },
2514
+ hasPermission: (input, options) => postGeneric("/admin/has-permission", input, options),
2515
+ apiKey: {
2516
+ create: (input, options) => postGeneric("/admin/api-key/create", input, options)
2517
+ },
2518
+ athenaClient: {
2519
+ create: (input, options) => postGeneric("/admin/athena-client/create", input, options),
2520
+ list: (input, options) => getWithQuery("/admin/athena-client/list", input, options)
2521
+ },
2522
+ auditLog: {
2523
+ list: (input, options) => getWithQuery("/admin/audit-log/list", input, options)
2524
+ },
2525
+ email: {
2526
+ list: (input, options) => getWithQuery("/admin/email/list", input, options),
2527
+ get: (input, options) => getWithQuery("/admin/email/get", input, options),
2528
+ create: (input, options) => postGeneric("/admin/email/create", input, options),
2529
+ update: (input, options) => postGeneric("/admin/email/update", input, options),
2530
+ delete: (input, options) => postGeneric("/admin/email/delete", input, options),
2531
+ failure: {
2532
+ list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
2533
+ get: (input, options) => getWithQuery("/admin/email-failure/get", input, options),
2534
+ create: (input, options) => postGeneric("/admin/email-failure/create", input, options),
2535
+ update: (input, options) => postGeneric("/admin/email-failure/update", input, options),
2536
+ delete: (input, options) => postGeneric("/admin/email-failure/delete", input, options)
2537
+ },
2538
+ template: {
2539
+ list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
2540
+ get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
2541
+ create: (input, options) => postGeneric("/admin/email-template/create", input, options),
2542
+ update: (input, options) => postGeneric("/admin/email-template/update", input, options),
2543
+ delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
2544
+ }
2545
+ },
2546
+ emailTemplate: {
2547
+ get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
2548
+ create: (input, options) => postGeneric("/admin/email-template/create", input, options),
2549
+ delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
2550
+ list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
2551
+ update: (input, options) => postGeneric("/admin/email-template/update", input, options)
2552
+ }
2553
+ },
2554
+ apiKey: {
2555
+ create: (input, options) => postGeneric("/api-key/create", input, options),
2556
+ get: (input, options) => getWithQuery("/api-key/get", input, options),
2557
+ update: (input, options) => postGeneric("/api-key/update", input, options),
2558
+ delete: (input, options) => postGeneric("/api-key/delete", input, options),
2559
+ list: (input, options) => getWithQuery("/api-key/list", input, options),
2560
+ verify: (input, options) => postGeneric("/api-key/verify", input, options),
2561
+ deleteAllExpired: (input, options) => executePostWithOptionalInput(
2562
+ resolvedConfig,
2563
+ { endpoint: "/api-key/delete-all-expired-api-keys", method: "POST" },
2564
+ input,
2565
+ options
2566
+ )
2567
+ },
2568
+ signIn: {
2569
+ email: (input, options) => postGeneric("/sign-in/email", input, options),
2570
+ username: (input, options) => postGeneric("/sign-in/username", input, options),
2571
+ social: (input, options) => postGeneric("/sign-in/social", input, options)
2572
+ },
2573
+ signUp: {
2574
+ email: (input, options) => postGeneric("/sign-up/email", input, options)
2575
+ },
2576
+ organization,
2577
+ callback: {
2578
+ provider: (input, options) => {
2579
+ const { payload, fetchOptions } = extractFetchOptions(input);
2580
+ const parsed = payload;
2581
+ const provider = String(parsed?.provider ?? "").trim();
2582
+ if (!provider) {
2583
+ throw new Error("callback.provider requires a non-empty provider value");
2584
+ }
2585
+ const code = String(parsed?.code ?? "").trim();
2586
+ const state = String(parsed?.state ?? "").trim();
2587
+ if (!code || !state) {
2588
+ throw new Error("callback.provider requires non-empty code and state values");
2589
+ }
2590
+ const endpoint = `/callback/${encodeURIComponent(provider)}`;
2591
+ return request({
2592
+ endpoint,
2593
+ method: "GET",
2594
+ query: {
2595
+ code,
2596
+ state
2597
+ },
2598
+ fetchOptions
2599
+ }, options);
2600
+ }
1177
2601
  }
1178
- buffer += char;
1179
- }
1180
- if (singleQuoted || doubleQuoted || depth !== 0) {
1181
- return null;
1182
- }
1183
- if (buffer.trim().length > 0) {
1184
- parts.push(buffer.trim());
1185
- }
1186
- return parts;
2602
+ };
2603
+ return {
2604
+ baseUrl: normalizedBaseUrl,
2605
+ request,
2606
+ signIn: {
2607
+ email: (input, options) => executePostWithCompatibleInput(
2608
+ resolvedConfig,
2609
+ { endpoint: "/sign-in/email", method: "POST" },
2610
+ input,
2611
+ options
2612
+ ),
2613
+ username: (input, options) => executePostWithCompatibleInput(
2614
+ resolvedConfig,
2615
+ { endpoint: "/sign-in/username", method: "POST" },
2616
+ input,
2617
+ options
2618
+ ),
2619
+ social: (input, options) => executePostWithCompatibleInput(
2620
+ resolvedConfig,
2621
+ { endpoint: "/sign-in/social", method: "POST" },
2622
+ input,
2623
+ options
2624
+ )
2625
+ },
2626
+ signUp: {
2627
+ email: (input, options) => executePostWithCompatibleInput(
2628
+ resolvedConfig,
2629
+ { endpoint: "/sign-up/email", method: "POST" },
2630
+ input,
2631
+ options
2632
+ )
2633
+ },
2634
+ signOut,
2635
+ logout: signOut,
2636
+ getSession: (input, options) => executeGetWithCompatibleInput(
2637
+ resolvedConfig,
2638
+ { endpoint: "/get-session", method: "GET" },
2639
+ input,
2640
+ options
2641
+ ),
2642
+ listSessions: (input, options) => executeGetWithCompatibleInput(
2643
+ resolvedConfig,
2644
+ { endpoint: "/list-sessions", method: "GET" },
2645
+ input,
2646
+ options
2647
+ ),
2648
+ revokeSession,
2649
+ clearSession: revokeSession,
2650
+ revokeSessions,
2651
+ clearSessions: revokeSessions,
2652
+ revokeOtherSessions,
2653
+ clearOtherSessions: revokeOtherSessions,
2654
+ forgetPassword: (input, options) => executePostWithCompatibleInput(
2655
+ resolvedConfig,
2656
+ { endpoint: "/forget-password", method: "POST" },
2657
+ input,
2658
+ options
2659
+ ),
2660
+ resetPassword: (input, options) => executePostWithCompatibleInput(
2661
+ resolvedConfig,
2662
+ { endpoint: "/reset-password", method: "POST" },
2663
+ input,
2664
+ options
2665
+ ),
2666
+ resolveResetPasswordToken,
2667
+ verifyEmail: (input, options) => {
2668
+ const { payload, fetchOptions } = extractFetchOptions(input);
2669
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
2670
+ const query = payload;
2671
+ return callAuthEndpoint(
2672
+ resolvedConfig,
2673
+ { endpoint: "/verify-email", method: "GET" },
2674
+ void 0,
2675
+ query ? {
2676
+ token: query.token,
2677
+ callbackURL: query.callbackURL
2678
+ } : void 0,
2679
+ mergedOptions
2680
+ );
2681
+ },
2682
+ sendVerificationEmail: (input, options) => executePostWithCompatibleInput(
2683
+ resolvedConfig,
2684
+ { endpoint: "/send-verification-email", method: "POST" },
2685
+ input,
2686
+ options
2687
+ ),
2688
+ changeEmail: (input, options) => executePostWithCompatibleInput(
2689
+ resolvedConfig,
2690
+ { endpoint: "/change-email", method: "POST" },
2691
+ input,
2692
+ options
2693
+ ),
2694
+ changePassword: (input, options) => executePostWithCompatibleInput(
2695
+ resolvedConfig,
2696
+ { endpoint: "/change-password", method: "POST" },
2697
+ input,
2698
+ options
2699
+ ),
2700
+ updateUser: (input, options) => executePostWithCompatibleInput(
2701
+ resolvedConfig,
2702
+ { endpoint: "/update-user", method: "POST" },
2703
+ input,
2704
+ options
2705
+ ),
2706
+ deleteUser,
2707
+ deleteUserCallback,
2708
+ linkSocial: (input, options) => executePostWithCompatibleInput(
2709
+ resolvedConfig,
2710
+ { endpoint: "/link-social", method: "POST" },
2711
+ input,
2712
+ options
2713
+ ),
2714
+ listAccounts: (input, options) => executeGetWithCompatibleInput(
2715
+ resolvedConfig,
2716
+ { endpoint: "/list-accounts", method: "GET" },
2717
+ input,
2718
+ options
2719
+ ),
2720
+ unlinkAccount: (input, options) => executePostWithCompatibleInput(
2721
+ resolvedConfig,
2722
+ { endpoint: "/unlink-account", method: "POST" },
2723
+ input,
2724
+ options
2725
+ ),
2726
+ refreshToken: (input, options) => executePostWithCompatibleInput(
2727
+ resolvedConfig,
2728
+ { endpoint: "/refresh-token", method: "POST" },
2729
+ input,
2730
+ options
2731
+ ),
2732
+ getAccessToken: (input, options) => executePostWithCompatibleInput(
2733
+ resolvedConfig,
2734
+ { endpoint: "/get-access-token", method: "POST" },
2735
+ input,
2736
+ options
2737
+ ),
2738
+ organization,
2739
+ auth
2740
+ };
1187
2741
  }
1188
- function quoteSelectColumnsExpression(columns) {
1189
- const trimmed = columns.trim();
1190
- if (!trimmed || trimmed === "*") return trimmed || "*";
1191
- const tokens = splitTopLevelCommaSeparated(trimmed);
1192
- if (!tokens || tokens.length === 0) {
1193
- return trimmed;
1194
- }
1195
- if (!tokens.every(canAutoQuoteToken)) {
1196
- return trimmed;
1197
- }
1198
- return tokens.map(quoteSelectToken).join(", ");
2742
+
2743
+ // src/db/module.ts
2744
+ function createDbModule(input) {
2745
+ const db = {
2746
+ from(table) {
2747
+ return input.from(table);
2748
+ },
2749
+ select(table, columns, options) {
2750
+ return input.from(table).select(columns, options);
2751
+ },
2752
+ insert(table, values, options) {
2753
+ return Array.isArray(values) ? input.from(table).insert(values, options) : input.from(table).insert(values, options);
2754
+ },
2755
+ upsert(table, values, options) {
2756
+ return Array.isArray(values) ? input.from(table).upsert(values, options) : input.from(table).upsert(values, options);
2757
+ },
2758
+ update(table, values, options) {
2759
+ return input.from(table).update(values, options);
2760
+ },
2761
+ delete(table, options) {
2762
+ return input.from(table).delete(options);
2763
+ },
2764
+ rpc(fn, args, options) {
2765
+ return input.rpc(fn, args, options);
2766
+ },
2767
+ query(query, options) {
2768
+ return input.query(query, options);
2769
+ }
2770
+ };
2771
+ return db;
1199
2772
  }
1200
2773
 
1201
2774
  // src/client.ts
1202
2775
  var DEFAULT_COLUMNS = "*";
1203
2776
  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;
1204
2777
  var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
2778
+ var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
1205
2779
  function formatResult(response) {
1206
2780
  const result = {
1207
2781
  data: response.data ?? null,
@@ -1215,6 +2789,28 @@ function formatResult(response) {
1215
2789
  }
1216
2790
  return result;
1217
2791
  }
2792
+ function attachNormalizedError(result, normalizedError) {
2793
+ Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
2794
+ value: normalizedError,
2795
+ enumerable: false,
2796
+ configurable: true,
2797
+ writable: false
2798
+ });
2799
+ }
2800
+ function createResultFormatter(experimental) {
2801
+ if (!experimental?.enableErrorNormalization) {
2802
+ return formatResult;
2803
+ }
2804
+ return (response, context) => {
2805
+ const result = formatResult(response);
2806
+ if (result.error == null) {
2807
+ return result;
2808
+ }
2809
+ const normalizedError = normalizeAthenaError(result, context);
2810
+ attachNormalizedError(result, normalizedError);
2811
+ return result;
2812
+ };
2813
+ }
1218
2814
  function toSingleResult(response) {
1219
2815
  const payload = response.data;
1220
2816
  const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
@@ -1589,7 +3185,7 @@ function createRpcFilterMethods(filters, self) {
1589
3185
  }
1590
3186
  };
1591
3187
  }
1592
- function createRpcBuilder(functionName, args, baseOptions, client) {
3188
+ function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
1593
3189
  const state = {
1594
3190
  filters: []
1595
3191
  };
@@ -1611,7 +3207,7 @@ function createRpcBuilder(functionName, args, baseOptions, client) {
1611
3207
  order: state.order
1612
3208
  };
1613
3209
  const response = await client.rpcGateway(payload, mergedOptions);
1614
- return formatResult(response);
3210
+ return formatGatewayResult(response, { operation: "rpc" });
1615
3211
  };
1616
3212
  const run = (columns, options) => {
1617
3213
  const payloadColumns = columns ?? selectedColumns;
@@ -1665,7 +3261,7 @@ function createRpcBuilder(functionName, args, baseOptions, client) {
1665
3261
  });
1666
3262
  return builder;
1667
3263
  }
1668
- function createTableBuilder(tableName, client) {
3264
+ function createTableBuilder(tableName, client, formatGatewayResult) {
1669
3265
  const state = {
1670
3266
  conditions: []
1671
3267
  };
@@ -1722,7 +3318,7 @@ function createTableBuilder(tableName, client) {
1722
3318
  });
1723
3319
  if (query) {
1724
3320
  const queryResponse = await client.queryGateway({ query }, options);
1725
- return formatResult(queryResponse);
3321
+ return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
1726
3322
  }
1727
3323
  }
1728
3324
  const payload = {
@@ -1740,7 +3336,7 @@ function createTableBuilder(tableName, client) {
1740
3336
  head: options?.head
1741
3337
  };
1742
3338
  const response = await client.fetchGateway(payload, options);
1743
- return formatResult(response);
3339
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
1744
3340
  };
1745
3341
  const createSelectChain = (columns, options) => {
1746
3342
  const chain = {};
@@ -1795,7 +3391,7 @@ function createTableBuilder(tableName, client) {
1795
3391
  payload.default_to_null = mergedOptions.defaultToNull;
1796
3392
  }
1797
3393
  const response = await client.insertGateway(payload, mergedOptions);
1798
- return formatResult(response);
3394
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
1799
3395
  };
1800
3396
  return createMutationQuery(executeInsertMany);
1801
3397
  }
@@ -1813,7 +3409,7 @@ function createTableBuilder(tableName, client) {
1813
3409
  payload.default_to_null = mergedOptions.defaultToNull;
1814
3410
  }
1815
3411
  const response = await client.insertGateway(payload, mergedOptions);
1816
- return formatResult(response);
3412
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
1817
3413
  };
1818
3414
  return createMutationQuery(executeInsertOne);
1819
3415
  },
@@ -1835,7 +3431,7 @@ function createTableBuilder(tableName, client) {
1835
3431
  payload.default_to_null = mergedOptions.defaultToNull;
1836
3432
  }
1837
3433
  const response = await client.insertGateway(payload, mergedOptions);
1838
- return formatResult(response);
3434
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
1839
3435
  };
1840
3436
  return createMutationQuery(executeUpsertMany);
1841
3437
  }
@@ -1855,7 +3451,7 @@ function createTableBuilder(tableName, client) {
1855
3451
  payload.default_to_null = mergedOptions.defaultToNull;
1856
3452
  }
1857
3453
  const response = await client.insertGateway(payload, mergedOptions);
1858
- return formatResult(response);
3454
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
1859
3455
  };
1860
3456
  return createMutationQuery(executeUpsertOne);
1861
3457
  },
@@ -1876,7 +3472,7 @@ function createTableBuilder(tableName, client) {
1876
3472
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
1877
3473
  if (columns) payload.columns = columns;
1878
3474
  const response = await client.updateGateway(payload, mergedOptions);
1879
- return formatResult(response);
3475
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
1880
3476
  };
1881
3477
  const mutation = createMutationQuery(executeUpdate, null);
1882
3478
  const updateChain = {};
@@ -1904,7 +3500,7 @@ function createTableBuilder(tableName, client) {
1904
3500
  if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
1905
3501
  if (columns) payload.columns = columns;
1906
3502
  const response = await client.deleteGateway(payload, mergedOptions);
1907
- return formatResult(response);
3503
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
1908
3504
  };
1909
3505
  return createMutationQuery(executeDelete, null);
1910
3506
  },
@@ -1918,14 +3514,14 @@ function createTableBuilder(tableName, client) {
1918
3514
  });
1919
3515
  return builder;
1920
3516
  }
1921
- function createQueryBuilder(client) {
3517
+ function createQueryBuilder(client, formatGatewayResult) {
1922
3518
  return async function query(query, options) {
1923
3519
  const normalizedQuery = query.trim();
1924
3520
  if (!normalizedQuery) {
1925
3521
  throw new Error("query requires a non-empty string");
1926
3522
  }
1927
3523
  const response = await client.queryGateway({ query: normalizedQuery }, options);
1928
- return formatResult(response);
3524
+ return formatGatewayResult(response, { operation: "query" });
1929
3525
  };
1930
3526
  }
1931
3527
  function createClientFromConfig(config) {
@@ -1936,23 +3532,30 @@ function createClientFromConfig(config) {
1936
3532
  backend: config.backend,
1937
3533
  headers: config.headers
1938
3534
  });
3535
+ const formatGatewayResult = createResultFormatter(config.experimental);
3536
+ const auth = createAuthClient(config.auth);
3537
+ const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
3538
+ const rpc = (fn, args, options) => {
3539
+ const normalizedFn = fn.trim();
3540
+ if (!normalizedFn) {
3541
+ throw new Error("rpc requires a function name");
3542
+ }
3543
+ return createRpcBuilder(
3544
+ normalizedFn,
3545
+ args,
3546
+ options,
3547
+ gateway,
3548
+ formatGatewayResult
3549
+ );
3550
+ };
3551
+ const query = createQueryBuilder(gateway, formatGatewayResult);
3552
+ const db = createDbModule({ from, rpc, query });
1939
3553
  return {
1940
- from(table) {
1941
- return createTableBuilder(table, gateway);
1942
- },
1943
- rpc(fn, args, options) {
1944
- const normalizedFn = fn.trim();
1945
- if (!normalizedFn) {
1946
- throw new Error("rpc requires a function name");
1947
- }
1948
- return createRpcBuilder(
1949
- normalizedFn,
1950
- args,
1951
- options,
1952
- gateway
1953
- );
1954
- },
1955
- query: createQueryBuilder(gateway)
3554
+ from,
3555
+ db,
3556
+ rpc,
3557
+ query,
3558
+ auth: auth.auth
1956
3559
  };
1957
3560
  }
1958
3561
  var DEFAULT_BACKEND = { type: "athena" };
@@ -1960,73 +3563,16 @@ function toBackendConfig(b) {
1960
3563
  if (!b) return DEFAULT_BACKEND;
1961
3564
  return typeof b === "string" ? { type: b } : b;
1962
3565
  }
1963
- var AthenaClientBuilderImpl = class {
1964
- baseUrl;
1965
- apiKey;
1966
- backendConfig = DEFAULT_BACKEND;
1967
- clientName;
1968
- defaultHeaders;
1969
- isHealthTrackingEnabled = false;
1970
- url(url) {
1971
- this.baseUrl = url;
1972
- return this;
1973
- }
1974
- key(apiKey) {
1975
- this.apiKey = apiKey;
1976
- return this;
1977
- }
1978
- backend(backend) {
1979
- this.backendConfig = toBackendConfig(backend);
1980
- return this;
1981
- }
1982
- client(clientName) {
1983
- this.clientName = clientName;
1984
- return this;
1985
- }
1986
- headers(headers) {
1987
- this.defaultHeaders = headers;
1988
- return this;
1989
- }
1990
- healthTracking(enabled) {
1991
- this.isHealthTrackingEnabled = enabled;
1992
- return this;
1993
- }
1994
- build() {
1995
- if (!this.baseUrl || !this.apiKey) {
1996
- throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
1997
- }
1998
- return createClientFromConfig({
1999
- baseUrl: this.baseUrl,
2000
- apiKey: this.apiKey,
2001
- client: this.clientName,
2002
- backend: this.backendConfig,
2003
- headers: this.defaultHeaders,
2004
- healthTracking: this.isHealthTrackingEnabled
2005
- });
2006
- }
2007
- };
2008
- var AthenaClient = class _AthenaClient {
2009
- /** Create a fluent builder for a strongly-typed Athena SDK client. */
2010
- static builder() {
2011
- return new AthenaClientBuilderImpl();
2012
- }
2013
- /** Build a client from process environment variables. */
2014
- static fromEnvironment() {
2015
- const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
2016
- const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
2017
- if (!url || !key) {
2018
- throw new Error(
2019
- "ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
2020
- );
2021
- }
2022
- return _AthenaClient.builder().url(url).key(key).build();
2023
- }
2024
- };
2025
3566
  function createClient(url, apiKey, options) {
2026
- const b = AthenaClient.builder().url(url).key(apiKey).backend(toBackendConfig(options?.backend));
2027
- if (options?.client) b.client(options.client);
2028
- if (options?.headers && Object.keys(options.headers).length > 0) b.headers(options.headers);
2029
- return b.build();
3567
+ return createClientFromConfig({
3568
+ baseUrl: url,
3569
+ apiKey,
3570
+ client: options?.client,
3571
+ backend: toBackendConfig(options?.backend),
3572
+ headers: options?.headers,
3573
+ auth: options?.auth,
3574
+ experimental: options?.experimental
3575
+ });
2030
3576
  }
2031
3577
 
2032
3578
  // src/schema/postgres-introspection-core.ts
@@ -2376,6 +3922,23 @@ var PostgresCatalogSnapshotAssembler = class {
2376
3922
  table.relations[key] = relation;
2377
3923
  }
2378
3924
  };
3925
+
3926
+ // src/schema/postgres-provider.ts
3927
+ var pgPoolConstructorPromise;
3928
+ async function loadPgPoolConstructor() {
3929
+ if (!pgPoolConstructorPromise) {
3930
+ pgPoolConstructorPromise = import('pg').then((module) => {
3931
+ const poolConstructor = module.Pool ?? module.default?.Pool;
3932
+ if (!poolConstructor) {
3933
+ throw new Error(
3934
+ '@xylex-group/athena: Unable to load the PostgreSQL driver. Ensure "pg" is installed and this API runs in a Node.js server runtime.'
3935
+ );
3936
+ }
3937
+ return poolConstructor;
3938
+ });
3939
+ }
3940
+ return pgPoolConstructorPromise;
3941
+ }
2379
3942
  var PgCatalogClient = class {
2380
3943
  constructor(pool) {
2381
3944
  this.pool = pool;
@@ -2415,7 +3978,8 @@ var PostgresIntrospectionProvider = class {
2415
3978
  }
2416
3979
  async inspect(options) {
2417
3980
  const schemas = options?.schemas && options.schemas.length > 0 ? normalizePostgresCatalogSchemas(options.schemas) : this.schemas;
2418
- const pool = new Pool({
3981
+ const PoolConstructor = await loadPgPoolConstructor();
3982
+ const pool = new PoolConstructor({
2419
3983
  connectionString: this.connectionString
2420
3984
  });
2421
3985
  const catalogClient = new PgCatalogClient(pool);