@xylex-group/athena 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +195 -106
  2. package/dist/browser.cjs +870 -154
  3. package/dist/browser.cjs.map +1 -1
  4. package/dist/browser.d.cts +7 -7
  5. package/dist/browser.d.ts +7 -7
  6. package/dist/browser.js +869 -155
  7. package/dist/browser.js.map +1 -1
  8. package/dist/cli/index.cjs +905 -144
  9. package/dist/cli/index.cjs.map +1 -1
  10. package/dist/cli/index.d.cts +3 -3
  11. package/dist/cli/index.d.ts +3 -3
  12. package/dist/cli/index.js +905 -144
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.cjs +870 -154
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +7 -7
  17. package/dist/index.d.ts +7 -7
  18. package/dist/index.js +869 -155
  19. package/dist/index.js.map +1 -1
  20. package/dist/{model-form-hoE2jHIi.d.cts → model-form-4LPnOPAF.d.cts} +9 -5
  21. package/dist/{model-form-BpDXlbxb.d.ts → model-form-CO4-LmNC.d.ts} +9 -5
  22. package/dist/{pipeline-BNIw8pDQ.d.ts → pipeline-CR4V15jF.d.ts} +1 -1
  23. package/dist/{pipeline-DNIpEsN8.d.cts → pipeline-DZeExYMA.d.cts} +1 -1
  24. package/dist/{react-email-qPA1wjFV.d.ts → react-email-6mOyxBo4.d.cts} +60 -13
  25. package/dist/{react-email-BvyCZnfW.d.cts → react-email-Buhcpglm.d.ts} +60 -13
  26. package/dist/react.cjs +333 -16
  27. package/dist/react.cjs.map +1 -1
  28. package/dist/react.d.cts +4 -4
  29. package/dist/react.d.ts +4 -4
  30. package/dist/react.js +333 -16
  31. package/dist/react.js.map +1 -1
  32. package/dist/{types-A5e97acl.d.cts → types-09Q4D86N.d.cts} +23 -2
  33. package/dist/{types-A5e97acl.d.ts → types-09Q4D86N.d.ts} +23 -2
  34. package/dist/{types-bDlr4u7p.d.cts → types-D1JvL21V.d.cts} +1 -1
  35. package/dist/{types-BnD22-vb.d.ts → types-DU3gNdFv.d.ts} +1 -1
  36. package/dist/utils.cjs +131 -0
  37. package/dist/utils.cjs.map +1 -1
  38. package/dist/utils.d.cts +42 -1
  39. package/dist/utils.d.ts +42 -1
  40. package/dist/utils.js +117 -1
  41. package/dist/utils.js.map +1 -1
  42. package/package.json +40 -40
package/dist/browser.js CHANGED
@@ -58,13 +58,114 @@ function isAthenaGatewayError(error) {
58
58
  return error instanceof AthenaGatewayError;
59
59
  }
60
60
 
61
+ // src/gateway/url.ts
62
+ var ATHENA_DEFAULT_BASE_URL = "https://athena-db.com";
63
+ function describeReceivedValue(value) {
64
+ if (value === void 0) return "undefined";
65
+ if (value === null) return "null";
66
+ if (typeof value === "string") {
67
+ return value.trim().length > 0 ? JSON.stringify(value) : "an empty string";
68
+ }
69
+ return `${typeof value} ${JSON.stringify(value)}`;
70
+ }
71
+ function invalidBaseUrlError(message, hint) {
72
+ return new AthenaGatewayError({
73
+ code: "INVALID_URL",
74
+ message,
75
+ status: 0,
76
+ hint
77
+ });
78
+ }
79
+ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
80
+ const label = options.label ?? "Athena gateway base URL";
81
+ const candidate = input ?? options.defaultBaseUrl;
82
+ if (candidate === void 0 || candidate === null) {
83
+ throw invalidBaseUrlError(
84
+ `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(input)}.`,
85
+ 'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
86
+ );
87
+ }
88
+ const trimmed = candidate.trim();
89
+ if (!trimmed) {
90
+ throw invalidBaseUrlError(
91
+ `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
92
+ 'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
93
+ );
94
+ }
95
+ let parsed;
96
+ try {
97
+ parsed = new URL(trimmed);
98
+ } catch {
99
+ throw invalidBaseUrlError(
100
+ `${label} must be a valid absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
101
+ 'Use a full URL including the protocol, for example "https://mirror3.athena-db.com".'
102
+ );
103
+ }
104
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
105
+ throw invalidBaseUrlError(
106
+ `${label} must use http or https. Received ${JSON.stringify(trimmed)}.`,
107
+ 'Use an Athena gateway URL such as "https://mirror3.athena-db.com".'
108
+ );
109
+ }
110
+ if (parsed.search || parsed.hash) {
111
+ throw invalidBaseUrlError(
112
+ `${label} must not include query parameters or hash fragments. Received ${JSON.stringify(trimmed)}.`,
113
+ 'Pass only the base URL. Endpoint paths such as "/gateway/fetch" are appended by the SDK.'
114
+ );
115
+ }
116
+ return parsed.toString().replace(/\/+$/, "");
117
+ }
118
+ function buildAthenaGatewayUrl(baseUrl, path) {
119
+ if (!path.startsWith("/")) {
120
+ throw invalidBaseUrlError(
121
+ `Athena gateway path must start with "/". Received ${JSON.stringify(path)}.`,
122
+ 'Use a leading slash such as "/gateway/fetch" or "/".'
123
+ );
124
+ }
125
+ return `${baseUrl}${path}`;
126
+ }
127
+
128
+ // src/cookies/cookie-utils.ts
129
+ var SECURE_COOKIE_PREFIX = "__Secure-";
130
+ function parseCookies(cookieHeader) {
131
+ const cookies = cookieHeader.split("; ");
132
+ const cookieMap = /* @__PURE__ */ new Map();
133
+ cookies.forEach((cookie) => {
134
+ const [name, value] = cookie.split(/=(.*)/s);
135
+ cookieMap.set(name, value);
136
+ });
137
+ return cookieMap;
138
+ }
139
+ var getSessionCookie = (request, config) => {
140
+ const cookies = (request instanceof Headers || !("headers" in request) ? request : request.headers).get("cookie");
141
+ if (!cookies) {
142
+ return null;
143
+ }
144
+ const { cookieName = "session_token", cookiePrefix = "athena-auth" } = {};
145
+ const parsedCookie = parseCookies(cookies);
146
+ const getCookie = (name) => parsedCookie.get(name) || parsedCookie.get(`${SECURE_COOKIE_PREFIX}${name}`);
147
+ const sessionToken = getCookie(`${cookiePrefix}.${cookieName}`) || getCookie(`${cookiePrefix}-${cookieName}`);
148
+ if (sessionToken) {
149
+ return sessionToken;
150
+ }
151
+ return null;
152
+ };
153
+
154
+ // package.json
155
+ var package_default = {
156
+ version: "2.4.1"
157
+ };
158
+
159
+ // src/sdk-version.ts
160
+ var PACKAGE_VERSION = package_default.version;
161
+ function buildSdkHeaderValue(sdkName) {
162
+ return `${sdkName} ${PACKAGE_VERSION}`;
163
+ }
164
+
61
165
  // src/gateway/client.ts
62
- var DEFAULT_BASE_URL = "https://athena-db.com";
63
166
  var DEFAULT_CLIENT = "railway_direct";
64
- var FALLBACK_SDK_VERSION = "1.3.0";
65
167
  var SDK_NAME = "xylex-group/athena";
66
- var SDK_VERSION = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION;
67
- var SDK_HEADER_VALUE = `${SDK_NAME} ${SDK_VERSION}`;
168
+ var SDK_HEADER_VALUE = buildSdkHeaderValue(SDK_NAME);
68
169
  function parseResponseBody(rawText, contentType) {
69
170
  if (!rawText) {
70
171
  return { parsed: null, parseFailed: false };
@@ -83,6 +184,37 @@ function parseResponseBody(rawText, contentType) {
83
184
  function normalizeHeaderValue(value) {
84
185
  return value ? value : void 0;
85
186
  }
187
+ function resolveHeaderValue(headers, candidates) {
188
+ for (const candidate of candidates) {
189
+ const direct = normalizeHeaderValue(headers[candidate]);
190
+ if (direct) return direct;
191
+ }
192
+ const loweredCandidates = new Set(candidates.map((candidate) => candidate.toLowerCase()));
193
+ for (const [key, value] of Object.entries(headers)) {
194
+ if (!loweredCandidates.has(key.toLowerCase())) {
195
+ continue;
196
+ }
197
+ const normalized = normalizeHeaderValue(value);
198
+ if (normalized) return normalized;
199
+ }
200
+ return void 0;
201
+ }
202
+ function resolveBearerTokenFromAuthorizationHeader(headers) {
203
+ const authorization = resolveHeaderValue(headers, ["Authorization"]);
204
+ if (!authorization) {
205
+ return void 0;
206
+ }
207
+ const match = authorization.match(/^Bearer\s+(.+)$/i);
208
+ const token = match?.[1]?.trim();
209
+ return token ? token : void 0;
210
+ }
211
+ function resolveSessionTokenFromCookieHeader(headers) {
212
+ const cookie = resolveHeaderValue(headers, ["Cookie"]);
213
+ if (!cookie) {
214
+ return void 0;
215
+ }
216
+ return getSessionCookie(new Headers({ cookie })) ?? void 0;
217
+ }
86
218
  function isRecord(value) {
87
219
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
88
220
  }
@@ -200,7 +332,7 @@ function buildRpcGetEndpoint(payload) {
200
332
  status: 0
201
333
  });
202
334
  }
203
- query.set(filter.column, toRpcFilterQueryValue(filter));
335
+ query.append(filter.column, toRpcFilterQueryValue(filter));
204
336
  }
205
337
  }
206
338
  const endpoint = `/rpc/${encodeURIComponent(functionName)}`;
@@ -246,6 +378,20 @@ function buildHeaders(config, options) {
246
378
  headers["apikey"] = finalApiKey;
247
379
  headers["x-api-key"] = headers["x-api-key"] ?? finalApiKey;
248
380
  }
381
+ const explicitSessionToken = resolveHeaderValue(extraHeaders, [
382
+ "X-Athena-Auth-Session-Token"
383
+ ]);
384
+ const derivedSessionToken = explicitSessionToken ?? resolveSessionTokenFromCookieHeader(extraHeaders);
385
+ if (derivedSessionToken) {
386
+ headers["X-Athena-Auth-Session-Token"] = derivedSessionToken;
387
+ }
388
+ const explicitBearerToken = resolveHeaderValue(extraHeaders, [
389
+ "X-Athena-Auth-Bearer-Token"
390
+ ]);
391
+ const derivedBearerToken = explicitBearerToken ?? resolveBearerTokenFromAuthorizationHeader(extraHeaders);
392
+ if (derivedBearerToken) {
393
+ headers["X-Athena-Auth-Bearer-Token"] = derivedBearerToken;
394
+ }
249
395
  const athenaClientKeys = ["x-athena-client", "X-Athena-Client"];
250
396
  Object.entries(extraHeaders).forEach(([key, value]) => {
251
397
  if (athenaClientKeys.includes(key)) return;
@@ -256,9 +402,172 @@ function buildHeaders(config, options) {
256
402
  });
257
403
  return headers;
258
404
  }
405
+ function toInvalidUrlResponse(error, endpoint, method) {
406
+ const message = error instanceof Error ? error.message : String(error);
407
+ const gatewayError = error instanceof AthenaGatewayError ? error : new AthenaGatewayError({
408
+ code: "INVALID_URL",
409
+ message,
410
+ status: 0,
411
+ endpoint,
412
+ method,
413
+ cause: message,
414
+ hint: "Set ATHENA_URL to a full http(s) URL before running queries."
415
+ });
416
+ return {
417
+ ok: false,
418
+ status: 0,
419
+ statusText: null,
420
+ data: null,
421
+ error: gatewayError.message,
422
+ errorDetails: detailsFromError(
423
+ new AthenaGatewayError({
424
+ code: gatewayError.code,
425
+ message: gatewayError.message,
426
+ status: gatewayError.status,
427
+ endpoint,
428
+ method,
429
+ requestId: gatewayError.requestId,
430
+ hint: gatewayError.hint,
431
+ cause: gatewayError.causeDetail
432
+ })
433
+ ),
434
+ raw: null
435
+ };
436
+ }
437
+ function resolveGatewayBaseUrl(input) {
438
+ return normalizeAthenaGatewayBaseUrl(input, {
439
+ defaultBaseUrl: ATHENA_DEFAULT_BASE_URL
440
+ });
441
+ }
442
+ function resolveProbePath(path) {
443
+ if (!path) return "/";
444
+ if (!path.startsWith("/")) {
445
+ throw new AthenaGatewayError({
446
+ code: "INVALID_URL",
447
+ message: `Athena gateway probe path must start with "/". Received ${JSON.stringify(path)}.`,
448
+ status: 0,
449
+ hint: 'Use a leading slash such as "/" or "/health".'
450
+ });
451
+ }
452
+ return path;
453
+ }
454
+ function mergeConnectionHeaders(baseHeaders, headers) {
455
+ const merged = {
456
+ ...baseHeaders,
457
+ ...headers ?? {}
458
+ };
459
+ if (!merged["X-Athena-Sdk"] && !merged["x-athena-sdk"]) {
460
+ merged["X-Athena-Sdk"] = SDK_HEADER_VALUE;
461
+ }
462
+ return merged;
463
+ }
464
+ async function performConnectionCheck(baseUrl, requestHeaders, options) {
465
+ const path = resolveProbePath(options?.path);
466
+ const url = buildAthenaGatewayUrl(baseUrl, path);
467
+ try {
468
+ const response = await fetch(url, {
469
+ method: "GET",
470
+ headers: mergeConnectionHeaders(requestHeaders, options?.headers),
471
+ signal: options?.signal
472
+ });
473
+ const rawText = await response.text();
474
+ const requestId = resolveRequestId(response.headers);
475
+ const parsedBody = parseResponseBody(
476
+ rawText ?? "",
477
+ response.headers.get("content-type")
478
+ );
479
+ if (parsedBody.parseFailed) {
480
+ const invalidJsonError = new AthenaGatewayError({
481
+ code: "INVALID_JSON",
482
+ message: "Gateway probe returned malformed JSON",
483
+ status: response.status,
484
+ method: "GET",
485
+ requestId,
486
+ hint: "Verify the gateway response body is valid JSON.",
487
+ cause: rawText.slice(0, 300)
488
+ });
489
+ return {
490
+ ok: false,
491
+ reachable: true,
492
+ status: response.status,
493
+ statusText: resolveStatusText(response, parsedBody.parsed),
494
+ baseUrl,
495
+ url,
496
+ error: invalidJsonError.message,
497
+ errorDetails: detailsFromError(invalidJsonError),
498
+ raw: parsedBody.parsed
499
+ };
500
+ }
501
+ const parsed = parsedBody.parsed;
502
+ if (!response.ok) {
503
+ const httpError = new AthenaGatewayError({
504
+ code: "HTTP_ERROR",
505
+ message: resolveErrorMessage(
506
+ parsed,
507
+ `Athena gateway GET ${path} failed with status ${response.status}`
508
+ ),
509
+ status: response.status,
510
+ method: "GET",
511
+ requestId,
512
+ hint: resolveErrorHint(parsed)
513
+ });
514
+ return {
515
+ ok: false,
516
+ reachable: true,
517
+ status: response.status,
518
+ statusText: resolveStatusText(response, parsed),
519
+ baseUrl,
520
+ url,
521
+ error: httpError.message,
522
+ errorDetails: detailsFromError(httpError),
523
+ raw: parsed
524
+ };
525
+ }
526
+ return {
527
+ ok: true,
528
+ reachable: true,
529
+ status: response.status,
530
+ statusText: resolveStatusText(response, parsed),
531
+ baseUrl,
532
+ url,
533
+ error: void 0,
534
+ errorDetails: null,
535
+ raw: parsed
536
+ };
537
+ } catch (callError) {
538
+ const message = callError instanceof Error ? callError.message : String(callError);
539
+ const networkError = new AthenaGatewayError({
540
+ code: "NETWORK_ERROR",
541
+ message: `Network error while probing Athena gateway ${url}: ${message}`,
542
+ method: "GET",
543
+ cause: message,
544
+ hint: "Check gateway URL, DNS, and network reachability."
545
+ });
546
+ return {
547
+ ok: false,
548
+ reachable: false,
549
+ status: 0,
550
+ statusText: null,
551
+ baseUrl,
552
+ url,
553
+ error: networkError.message,
554
+ errorDetails: detailsFromError(networkError),
555
+ raw: null
556
+ };
557
+ }
558
+ }
559
+ async function verifyAthenaGatewayUrl(baseUrl, options) {
560
+ const normalizedBaseUrl = normalizeAthenaGatewayBaseUrl(baseUrl);
561
+ return performConnectionCheck(normalizedBaseUrl, { "X-Athena-Sdk": SDK_HEADER_VALUE }, options);
562
+ }
259
563
  async function callAthena(config, endpoint, method, payload, options) {
260
- const baseUrl = (options?.baseUrl ?? config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
261
- const url = `${baseUrl}${endpoint}`;
564
+ let baseUrl;
565
+ try {
566
+ baseUrl = resolveGatewayBaseUrl(options?.baseUrl ?? config.baseUrl);
567
+ } catch (error) {
568
+ return toInvalidUrlResponse(error, endpoint, method);
569
+ }
570
+ const url = buildAthenaGatewayUrl(baseUrl, endpoint);
262
571
  const headers = buildHeaders(config, options);
263
572
  try {
264
573
  const requestInit = {
@@ -355,32 +664,44 @@ async function callAthena(config, endpoint, method, payload, options) {
355
664
  }
356
665
  }
357
666
  function createAthenaGatewayClient(config = {}) {
667
+ const normalizedBaseUrl = resolveGatewayBaseUrl(config.baseUrl);
668
+ const normalizedConfig = {
669
+ ...config,
670
+ baseUrl: normalizedBaseUrl
671
+ };
358
672
  return {
359
- baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, ""),
673
+ baseUrl: normalizedBaseUrl,
360
674
  buildHeaders(options) {
361
- return buildHeaders(config, options);
675
+ return buildHeaders(normalizedConfig, options);
676
+ },
677
+ verifyConnection(options) {
678
+ return performConnectionCheck(
679
+ normalizedBaseUrl,
680
+ buildHeaders(normalizedConfig),
681
+ options
682
+ );
362
683
  },
363
684
  fetchGateway(payload, options) {
364
- return callAthena(config, "/gateway/fetch", "POST", payload, options);
685
+ return callAthena(normalizedConfig, "/gateway/fetch", "POST", payload, options);
365
686
  },
366
687
  insertGateway(payload, options) {
367
- return callAthena(config, "/gateway/insert", "PUT", payload, options);
688
+ return callAthena(normalizedConfig, "/gateway/insert", "PUT", payload, options);
368
689
  },
369
690
  updateGateway(payload, options) {
370
- return callAthena(config, "/gateway/update", "POST", payload, options);
691
+ return callAthena(normalizedConfig, "/gateway/update", "POST", payload, options);
371
692
  },
372
693
  deleteGateway(payload, options) {
373
- return callAthena(config, "/gateway/delete", "DELETE", payload, options);
694
+ return callAthena(normalizedConfig, "/gateway/delete", "DELETE", payload, options);
374
695
  },
375
696
  rpcGateway(payload, options) {
376
697
  if (options?.get) {
377
698
  const endpoint = buildRpcGetEndpoint(payload);
378
- return callAthena(config, endpoint, "GET", null, options);
699
+ return callAthena(normalizedConfig, endpoint, "GET", null, options);
379
700
  }
380
- return callAthena(config, "/gateway/rpc", "POST", payload, options);
701
+ return callAthena(normalizedConfig, "/gateway/rpc", "POST", payload, options);
381
702
  },
382
703
  queryGateway(payload, options) {
383
- return callAthena(config, "/gateway/query", "POST", payload, options);
704
+ return callAthena(normalizedConfig, "/gateway/query", "POST", payload, options);
384
705
  }
385
706
  };
386
707
  }
@@ -766,10 +1087,8 @@ async function resolveReactEmailPayloadFields(input, fields, options) {
766
1087
 
767
1088
  // src/auth/client.ts
768
1089
  var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
769
- var FALLBACK_SDK_VERSION2 = "1.0.0";
770
1090
  var SDK_NAME2 = "xylex-group/athena-auth";
771
- var SDK_VERSION2 = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION2;
772
- var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
1091
+ var SDK_HEADER_VALUE2 = buildSdkHeaderValue(SDK_NAME2);
773
1092
  function normalizeBaseUrl(baseUrl) {
774
1093
  return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
775
1094
  }
@@ -2022,6 +2341,7 @@ function classifyKind(status, code, message) {
2022
2341
  if (status === 404 || hasNotFoundPattern) return "not_found";
2023
2342
  if (status === 401 || status === 403 || hasAuthPattern) return "auth";
2024
2343
  if (status === 429 || hasRateLimitPattern) return "rate_limit";
2344
+ if (code === "INVALID_URL") return "validation";
2025
2345
  if (status === 400 || status === 422 || hasValidationPattern) return "validation";
2026
2346
  if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
2027
2347
  return "transient";
@@ -2029,6 +2349,9 @@ function classifyKind(status, code, message) {
2029
2349
  return "unknown";
2030
2350
  }
2031
2351
  function toAthenaErrorCode(kind, status, gatewayCode) {
2352
+ if (gatewayCode === "INVALID_URL") {
2353
+ return AthenaErrorCode.ValidationFailed;
2354
+ }
2032
2355
  if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
2033
2356
  return AthenaErrorCode.NetworkUnavailable;
2034
2357
  }
@@ -2377,8 +2700,8 @@ async function withRetry(config, fn) {
2377
2700
  // src/db/module.ts
2378
2701
  function createDbModule(input) {
2379
2702
  const db = {
2380
- from(table) {
2381
- return input.from(table);
2703
+ from(table, options) {
2704
+ return input.from(table, options);
2382
2705
  },
2383
2706
  select(table, columns, options) {
2384
2707
  return input.from(table).select(columns, options);
@@ -2483,7 +2806,19 @@ function buildGatewayCondition(operator, column, value) {
2483
2806
  function compileRelationToken(key, node) {
2484
2807
  const nested = compileSelectShape(node.select);
2485
2808
  const propertyKey = normalizeIdentifier(key, "select relation key");
2486
- const relationToken = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
2809
+ if (node.schema && node.via) {
2810
+ throw new Error(
2811
+ `findMany relation "${propertyKey}" cannot combine schema and via yet; use schema with the relation key, or use via without schema`
2812
+ );
2813
+ }
2814
+ const relationTokenBase = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
2815
+ if (node.schema && relationTokenBase.includes(".")) {
2816
+ throw new Error(
2817
+ `findMany relation "${propertyKey}" already resolves to a qualified relation token; do not also set schema`
2818
+ );
2819
+ }
2820
+ const relationSchema = node.schema?.trim();
2821
+ const relationToken = relationSchema ? `${normalizeIdentifier(relationSchema, "select relation schema")}.${relationTokenBase}` : relationTokenBase;
2487
2822
  const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
2488
2823
  const prefix = alias ? `${alias}:` : "";
2489
2824
  return `${prefix}${relationToken}(${nested})`;
@@ -2512,6 +2847,23 @@ function compileSelectShape(select) {
2512
2847
  }
2513
2848
  return tokens.join(",");
2514
2849
  }
2850
+ function selectShapeUsesRelationSchema(select) {
2851
+ if (!isRecord5(select)) {
2852
+ return false;
2853
+ }
2854
+ for (const rawValue of Object.values(select)) {
2855
+ if (!isRelationSelectNode(rawValue)) {
2856
+ continue;
2857
+ }
2858
+ if (typeof rawValue.schema === "string" && rawValue.schema.trim().length > 0) {
2859
+ return true;
2860
+ }
2861
+ if (selectShapeUsesRelationSchema(rawValue.select)) {
2862
+ return true;
2863
+ }
2864
+ }
2865
+ return false;
2866
+ }
2515
2867
  function compileColumnWhere(column, input) {
2516
2868
  const normalizedColumn = normalizeIdentifier(column, "where column");
2517
2869
  if (!isRecord5(input)) {
@@ -2648,6 +3000,356 @@ function compileOrderBy(orderBy) {
2648
3000
  };
2649
3001
  }
2650
3002
 
3003
+ // src/gateway/structured-select.ts
3004
+ var IDENTIFIER_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
3005
+ function isIdentifierPath(value) {
3006
+ const segments = value.split(".").map((segment) => segment.trim());
3007
+ return segments.length > 1 && segments.every((segment) => IDENTIFIER_SEGMENT_PATTERN.test(segment));
3008
+ }
3009
+ function extractRelationHead(raw) {
3010
+ const trimmed = raw.trim();
3011
+ if (!trimmed) return "";
3012
+ const aliasIndex = trimmed.indexOf(":");
3013
+ const withoutAlias = aliasIndex >= 0 ? trimmed.slice(aliasIndex + 1).trim() : trimmed;
3014
+ const modifierIndex = withoutAlias.indexOf("!");
3015
+ return (modifierIndex >= 0 ? withoutAlias.slice(0, modifierIndex) : withoutAlias).trim();
3016
+ }
3017
+ function hasSchemaQualifiedRelationToken(select) {
3018
+ let singleQuoted = false;
3019
+ let doubleQuoted = false;
3020
+ let tokenStart = 0;
3021
+ for (let index = 0; index < select.length; index += 1) {
3022
+ const char = select[index];
3023
+ const next = index + 1 < select.length ? select[index + 1] : "";
3024
+ if (singleQuoted) {
3025
+ if (char === "'" && next === "'") {
3026
+ index += 1;
3027
+ continue;
3028
+ }
3029
+ if (char === "'") {
3030
+ singleQuoted = false;
3031
+ }
3032
+ continue;
3033
+ }
3034
+ if (doubleQuoted) {
3035
+ if (char === '"' && next === '"') {
3036
+ index += 1;
3037
+ continue;
3038
+ }
3039
+ if (char === '"') {
3040
+ doubleQuoted = false;
3041
+ }
3042
+ continue;
3043
+ }
3044
+ if (char === "'") {
3045
+ singleQuoted = true;
3046
+ continue;
3047
+ }
3048
+ if (char === '"') {
3049
+ doubleQuoted = true;
3050
+ continue;
3051
+ }
3052
+ if (char === "(") {
3053
+ const relationHead = extractRelationHead(select.slice(tokenStart, index));
3054
+ if (isIdentifierPath(relationHead)) {
3055
+ return true;
3056
+ }
3057
+ tokenStart = index + 1;
3058
+ continue;
3059
+ }
3060
+ if (char === "," || char === ")") {
3061
+ tokenStart = index + 1;
3062
+ }
3063
+ }
3064
+ return false;
3065
+ }
3066
+ function toStructuredSelectString(columns) {
3067
+ return Array.isArray(columns) ? columns.join(",") : columns;
3068
+ }
3069
+ function buildStructuredWhere(conditions) {
3070
+ if (!conditions?.length) return void 0;
3071
+ const where = {};
3072
+ for (const condition of conditions) {
3073
+ if (!condition.column) {
3074
+ return null;
3075
+ }
3076
+ if (condition.value_cast !== void 0) {
3077
+ return null;
3078
+ }
3079
+ const operand = condition.value;
3080
+ const operator = condition.operator;
3081
+ if (operator === "eq") {
3082
+ if (operand === void 0) return null;
3083
+ } else if (operator === "neq" || operator === "gt" || operator === "lt") {
3084
+ if (operand === void 0) return null;
3085
+ } else if (operator === "in") {
3086
+ if (!Array.isArray(operand)) return null;
3087
+ } else {
3088
+ return null;
3089
+ }
3090
+ const existing = where[condition.column];
3091
+ if (existing !== void 0 && (typeof existing !== "object" || existing === null || Array.isArray(existing))) {
3092
+ return null;
3093
+ }
3094
+ const next = existing ?? {};
3095
+ if (Object.prototype.hasOwnProperty.call(next, operator)) {
3096
+ return null;
3097
+ }
3098
+ next[operator] = operand;
3099
+ where[condition.column] = next;
3100
+ }
3101
+ return where;
3102
+ }
3103
+ function buildStructuredOrderBy(order) {
3104
+ if (!order?.field) return void 0;
3105
+ return {
3106
+ [order.field]: order.direction === "descending" ? "desc" : "asc"
3107
+ };
3108
+ }
3109
+ function buildStructuredSelectTransport(input) {
3110
+ const select = toStructuredSelectString(input.columns).trim();
3111
+ if (!select || select === "*") {
3112
+ return null;
3113
+ }
3114
+ if (!hasSchemaQualifiedRelationToken(select)) {
3115
+ return null;
3116
+ }
3117
+ if (input.count !== void 0 || input.head !== void 0) {
3118
+ return {
3119
+ error: "Schema-qualified nested select strings require structured select transport, which does not support count/head options in athena-js yet."
3120
+ };
3121
+ }
3122
+ const where = buildStructuredWhere(input.conditions);
3123
+ if (where === null) {
3124
+ return {
3125
+ error: "Schema-qualified nested select strings only support eq, neq, gt, lt, and in filters in athena-js structured select transport."
3126
+ };
3127
+ }
3128
+ return {
3129
+ select,
3130
+ payload: {
3131
+ table_name: input.tableName,
3132
+ select,
3133
+ where,
3134
+ orderBy: buildStructuredOrderBy(input.order),
3135
+ limit: input.limit,
3136
+ offset: input.offset,
3137
+ strip_nulls: input.stripNulls
3138
+ }
3139
+ };
3140
+ }
3141
+
3142
+ // src/query-transport.ts
3143
+ function canUseFindManyAstTransport(state) {
3144
+ return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
3145
+ }
3146
+ function toFindManyAstOrder(order) {
3147
+ if (!order) {
3148
+ return void 0;
3149
+ }
3150
+ return {
3151
+ column: order.field,
3152
+ ascending: order.direction !== "descending"
3153
+ };
3154
+ }
3155
+ function isRecord6(value) {
3156
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3157
+ }
3158
+ function normalizeFindManyAstColumnPredicate(value) {
3159
+ if (!isRecord6(value)) {
3160
+ return {
3161
+ eq: value
3162
+ };
3163
+ }
3164
+ const normalized = {};
3165
+ for (const [key, operand] of Object.entries(value)) {
3166
+ if (operand !== void 0) {
3167
+ normalized[key] = operand;
3168
+ }
3169
+ }
3170
+ return normalized;
3171
+ }
3172
+ function normalizeFindManyAstBooleanOperand(clause) {
3173
+ const normalized = {};
3174
+ for (const [column, value] of Object.entries(clause)) {
3175
+ if (value === void 0) {
3176
+ continue;
3177
+ }
3178
+ normalized[column] = normalizeFindManyAstColumnPredicate(value);
3179
+ }
3180
+ return normalized;
3181
+ }
3182
+ function normalizeFindManyAstWhere(where) {
3183
+ if (!where || !isRecord6(where)) {
3184
+ return where;
3185
+ }
3186
+ const normalized = {};
3187
+ for (const [key, value] of Object.entries(where)) {
3188
+ if (value === void 0) {
3189
+ continue;
3190
+ }
3191
+ if (key === "or" && Array.isArray(value)) {
3192
+ normalized.or = value.map(
3193
+ (clause) => normalizeFindManyAstBooleanOperand(clause)
3194
+ );
3195
+ continue;
3196
+ }
3197
+ if (key === "not" && isRecord6(value)) {
3198
+ normalized.not = normalizeFindManyAstBooleanOperand(
3199
+ value
3200
+ );
3201
+ continue;
3202
+ }
3203
+ normalized[key] = normalizeFindManyAstColumnPredicate(value);
3204
+ }
3205
+ return normalized;
3206
+ }
3207
+ function predicateRequiresUuidQueryFallback(column, value) {
3208
+ if (!isRecord6(value)) {
3209
+ return shouldUseUuidTextComparison(column, value);
3210
+ }
3211
+ const eqValue = value.eq;
3212
+ return eqValue !== void 0 && shouldUseUuidTextComparison(column, eqValue);
3213
+ }
3214
+ function booleanOperandRequiresUuidQueryFallback(clause) {
3215
+ for (const [column, value] of Object.entries(clause)) {
3216
+ if (value === void 0) {
3217
+ continue;
3218
+ }
3219
+ if (predicateRequiresUuidQueryFallback(column, value)) {
3220
+ return true;
3221
+ }
3222
+ }
3223
+ return false;
3224
+ }
3225
+ function findManyAstWhereRequiresLegacyTransport(where) {
3226
+ if (!where || !isRecord6(where)) {
3227
+ return false;
3228
+ }
3229
+ for (const [key, value] of Object.entries(where)) {
3230
+ if (value === void 0) {
3231
+ continue;
3232
+ }
3233
+ if (key === "or" && Array.isArray(value)) {
3234
+ if (value.some(
3235
+ (clause) => booleanOperandRequiresUuidQueryFallback(clause)
3236
+ )) {
3237
+ return true;
3238
+ }
3239
+ continue;
3240
+ }
3241
+ if (key === "not" && isRecord6(value)) {
3242
+ if (booleanOperandRequiresUuidQueryFallback(value)) {
3243
+ return true;
3244
+ }
3245
+ continue;
3246
+ }
3247
+ if (predicateRequiresUuidQueryFallback(key, value)) {
3248
+ return true;
3249
+ }
3250
+ }
3251
+ return false;
3252
+ }
3253
+ function resolvePagination(input) {
3254
+ let limit = input.limit;
3255
+ let offset = input.offset;
3256
+ if (limit === void 0 && input.pageSize !== void 0) {
3257
+ limit = Math.max(0, Math.trunc(input.pageSize));
3258
+ }
3259
+ if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
3260
+ offset = (Math.trunc(input.currentPage) - 1) * Math.max(0, Math.trunc(input.pageSize));
3261
+ }
3262
+ return { limit, offset };
3263
+ }
3264
+ function hasTypedEqualityComparison(conditions) {
3265
+ return conditions?.some(
3266
+ (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
3267
+ ) ?? false;
3268
+ }
3269
+ function createSelectTransportPlan(input) {
3270
+ const conditions = input.state.conditions.length ? input.state.conditions.map((condition) => ({ ...condition })) : void 0;
3271
+ const pagination = resolvePagination({
3272
+ limit: input.state.limit,
3273
+ offset: input.state.offset,
3274
+ currentPage: input.state.currentPage,
3275
+ pageSize: input.state.pageSize
3276
+ });
3277
+ const stripNulls = input.options?.stripNulls ?? true;
3278
+ const structuredSelectTransport = buildStructuredSelectTransport({
3279
+ tableName: input.tableName,
3280
+ columns: input.columns,
3281
+ conditions,
3282
+ limit: pagination.limit,
3283
+ offset: pagination.offset,
3284
+ order: input.state.order,
3285
+ stripNulls,
3286
+ count: input.options?.count,
3287
+ head: input.options?.head
3288
+ });
3289
+ if (structuredSelectTransport && "error" in structuredSelectTransport) {
3290
+ throw new Error(structuredSelectTransport.error);
3291
+ }
3292
+ if (structuredSelectTransport) {
3293
+ const { payload, select } = structuredSelectTransport;
3294
+ return {
3295
+ kind: "fetch",
3296
+ payload,
3297
+ debug: {
3298
+ columns: select,
3299
+ conditions,
3300
+ limit: pagination.limit,
3301
+ offset: pagination.offset,
3302
+ order: input.state.order
3303
+ }
3304
+ };
3305
+ }
3306
+ if (hasTypedEqualityComparison(conditions) && !input.options?.head && !input.options?.count && conditions) {
3307
+ const query = input.buildTypedSelectQuery({
3308
+ tableName: input.tableName,
3309
+ columns: input.columns,
3310
+ conditions,
3311
+ limit: input.state.limit,
3312
+ offset: input.state.offset,
3313
+ currentPage: input.state.currentPage,
3314
+ pageSize: input.state.pageSize,
3315
+ order: input.state.order
3316
+ });
3317
+ if (query) {
3318
+ return {
3319
+ kind: "query",
3320
+ query,
3321
+ payload: { query }
3322
+ };
3323
+ }
3324
+ }
3325
+ return {
3326
+ kind: "fetch",
3327
+ payload: {
3328
+ table_name: input.tableName,
3329
+ columns: input.columns,
3330
+ conditions,
3331
+ limit: input.state.limit,
3332
+ offset: input.state.offset,
3333
+ current_page: input.state.currentPage,
3334
+ page_size: input.state.pageSize,
3335
+ total_pages: input.state.totalPages,
3336
+ sort_by: input.state.order,
3337
+ strip_nulls: stripNulls,
3338
+ count: input.options?.count,
3339
+ head: input.options?.head
3340
+ },
3341
+ debug: {
3342
+ columns: input.columns,
3343
+ conditions,
3344
+ limit: input.state.limit,
3345
+ offset: input.state.offset,
3346
+ currentPage: input.state.currentPage,
3347
+ pageSize: input.state.pageSize,
3348
+ order: input.state.order
3349
+ }
3350
+ };
3351
+ }
3352
+
2651
3353
  // src/client.ts
2652
3354
  var DEFAULT_COLUMNS = "*";
2653
3355
  var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
@@ -2662,18 +3364,6 @@ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
2662
3364
  "node:internal",
2663
3365
  "internal/process"
2664
3366
  ];
2665
- function canUseFindManyAstTransport(state) {
2666
- return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
2667
- }
2668
- function toFindManyAstOrder(order) {
2669
- if (!order) {
2670
- return void 0;
2671
- }
2672
- return {
2673
- column: order.field,
2674
- ascending: order.direction !== "descending"
2675
- };
2676
- }
2677
3367
  function formatResult(response) {
2678
3368
  const result = {
2679
3369
  data: response.data ?? null,
@@ -2688,6 +3378,13 @@ function formatResult(response) {
2688
3378
  }
2689
3379
  return result;
2690
3380
  }
3381
+ var EXPERIMENTAL_READ_RETRY_CONFIG = {
3382
+ retries: 2,
3383
+ baseDelayMs: 100,
3384
+ maxDelayMs: 1e3,
3385
+ backoff: "exponential",
3386
+ jitter: true
3387
+ };
2691
3388
  function attachNormalizedError(result, normalizedError) {
2692
3389
  Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
2693
3390
  value: normalizedError,
@@ -2714,7 +3411,36 @@ function createResultFormatter(experimental) {
2714
3411
  return result;
2715
3412
  };
2716
3413
  }
2717
- function isRecord6(value) {
3414
+ async function executeExperimentalRead(experimental, runner) {
3415
+ if (!experimental?.retryReads) {
3416
+ return runner();
3417
+ }
3418
+ let lastRetryableResult;
3419
+ let lastRetrySignal = null;
3420
+ try {
3421
+ return await withRetry(
3422
+ {
3423
+ ...EXPERIMENTAL_READ_RETRY_CONFIG,
3424
+ shouldRetry: (error) => error === lastRetrySignal || normalizeAthenaError(error).retryable
3425
+ },
3426
+ async () => {
3427
+ const result = await runner();
3428
+ if (result.error?.retryable) {
3429
+ lastRetryableResult = result;
3430
+ lastRetrySignal = result.error;
3431
+ throw lastRetrySignal;
3432
+ }
3433
+ return result;
3434
+ }
3435
+ );
3436
+ } catch (error) {
3437
+ if (lastRetryableResult && error === lastRetrySignal) {
3438
+ return lastRetryableResult;
3439
+ }
3440
+ throw error;
3441
+ }
3442
+ }
3443
+ function isRecord7(value) {
2718
3444
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2719
3445
  }
2720
3446
  function firstNonEmptyString2(...values) {
@@ -2726,8 +3452,8 @@ function firstNonEmptyString2(...values) {
2726
3452
  return void 0;
2727
3453
  }
2728
3454
  function resolveStructuredErrorPayload2(raw) {
2729
- if (!isRecord6(raw)) return null;
2730
- return isRecord6(raw.error) ? raw.error : raw;
3455
+ if (!isRecord7(raw)) return null;
3456
+ return isRecord7(raw.error) ? raw.error : raw;
2731
3457
  }
2732
3458
  function resolveStructuredErrorDetails(payload, message) {
2733
3459
  if (!payload || !("details" in payload)) {
@@ -2743,7 +3469,7 @@ function resolveStructuredErrorDetails(payload, message) {
2743
3469
  return details;
2744
3470
  }
2745
3471
  function createResultError(response, result, normalized) {
2746
- const rawRecord = isRecord6(response.raw) ? response.raw : null;
3472
+ const rawRecord = isRecord7(response.raw) ? response.raw : null;
2747
3473
  const payload = resolveStructuredErrorPayload2(response.raw);
2748
3474
  const message = firstNonEmptyString2(
2749
3475
  response.error,
@@ -2938,7 +3664,14 @@ function toSingleResult(response) {
2938
3664
  function mergeOptions(...options) {
2939
3665
  return options.reduce((acc, next) => {
2940
3666
  if (!next) return acc;
2941
- return { ...acc, ...next };
3667
+ const merged = { ...acc ?? {}, ...next };
3668
+ if (acc?.headers || next.headers) {
3669
+ merged.headers = {
3670
+ ...acc?.headers ?? {},
3671
+ ...next.headers ?? {}
3672
+ };
3673
+ }
3674
+ return merged;
2942
3675
  }, void 0);
2943
3676
  }
2944
3677
  function asAthenaJsonObject(value) {
@@ -3219,17 +3952,6 @@ function conditionToDebugSqlClause(condition) {
3219
3952
  return `TRUE /* unsupported condition: ${rawCondition} */`;
3220
3953
  }
3221
3954
  }
3222
- function resolvePagination(input) {
3223
- let limit = input.limit;
3224
- let offset = input.offset;
3225
- if (limit === void 0 && input.pageSize !== void 0) {
3226
- limit = input.pageSize;
3227
- }
3228
- if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
3229
- offset = (input.currentPage - 1) * input.pageSize;
3230
- }
3231
- return { limit, offset };
3232
- }
3233
3955
  function appendOrderLimitOffset(sqlParts, order, limit, offset) {
3234
3956
  if (order?.field) {
3235
3957
  const direction = order.direction === "descending" ? "DESC" : "ASC";
@@ -3733,80 +4455,56 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
3733
4455
  );
3734
4456
  const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
3735
4457
  const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
3736
- const conditions = executionState.conditions.length ? executionState.conditions.map((condition) => ({ ...condition })) : void 0;
3737
- const hasTypedEqualityComparison = conditions?.some(
3738
- (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
3739
- ) ?? false;
3740
- if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
3741
- const query = buildTypedSelectQuery({
3742
- tableName: resolvedTableName,
3743
- columns,
3744
- conditions,
3745
- limit: executionState.limit,
3746
- offset: executionState.offset,
3747
- currentPage: executionState.currentPage,
3748
- pageSize: executionState.pageSize,
3749
- order: executionState.order
3750
- });
3751
- if (query) {
3752
- const payload2 = { query };
3753
- return executeWithQueryTrace(
4458
+ const plan = createSelectTransportPlan({
4459
+ tableName: resolvedTableName,
4460
+ columns,
4461
+ state: executionState,
4462
+ options,
4463
+ buildTypedSelectQuery
4464
+ });
4465
+ if (plan.kind === "query") {
4466
+ return executeExperimentalRead(
4467
+ experimental,
4468
+ () => executeWithQueryTrace(
3754
4469
  tracer,
3755
4470
  {
3756
4471
  operation: "select",
3757
4472
  endpoint: "/gateway/query",
3758
4473
  table: resolvedTableName,
3759
- sql: query,
3760
- payload: payload2,
4474
+ sql: plan.query,
4475
+ payload: plan.payload,
3761
4476
  options
3762
4477
  },
3763
4478
  async () => {
3764
- const queryResponse = await client.queryGateway(payload2, options);
4479
+ const queryResponse = await client.queryGateway(plan.payload, options);
3765
4480
  return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
3766
4481
  },
3767
4482
  callsite
3768
- );
3769
- }
4483
+ )
4484
+ );
3770
4485
  }
3771
- const payload = {
3772
- table_name: resolvedTableName,
3773
- columns,
3774
- conditions,
3775
- limit: executionState.limit,
3776
- offset: executionState.offset,
3777
- current_page: executionState.currentPage,
3778
- page_size: executionState.pageSize,
3779
- total_pages: executionState.totalPages,
3780
- sort_by: executionState.order,
3781
- strip_nulls: options?.stripNulls ?? true,
3782
- count: options?.count,
3783
- head: options?.head
3784
- };
3785
4486
  const sql = buildDebugSelectQuery({
3786
4487
  tableName: resolvedTableName,
3787
- columns,
3788
- conditions,
3789
- limit: executionState.limit,
3790
- offset: executionState.offset,
3791
- currentPage: executionState.currentPage,
3792
- pageSize: executionState.pageSize,
3793
- order: executionState.order
4488
+ ...plan.debug
3794
4489
  });
3795
- return executeWithQueryTrace(
3796
- tracer,
3797
- {
3798
- operation: "select",
3799
- endpoint: "/gateway/fetch",
3800
- table: resolvedTableName,
3801
- sql,
3802
- payload,
3803
- options
3804
- },
3805
- async () => {
3806
- const response = await client.fetchGateway(payload, options);
3807
- return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3808
- },
3809
- callsite
4490
+ return executeExperimentalRead(
4491
+ experimental,
4492
+ () => executeWithQueryTrace(
4493
+ tracer,
4494
+ {
4495
+ operation: "select",
4496
+ endpoint: "/gateway/fetch",
4497
+ table: resolvedTableName,
4498
+ sql,
4499
+ payload: plan.payload,
4500
+ options
4501
+ },
4502
+ async () => {
4503
+ const response = await client.fetchGateway(plan.payload, options);
4504
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4505
+ },
4506
+ callsite
4507
+ )
3810
4508
  );
3811
4509
  };
3812
4510
  const createSelectChain = (columns, options, initialCallsite) => {
@@ -3876,14 +4574,14 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
3876
4574
  if (options.limit !== void 0) {
3877
4575
  executionState.limit = options.limit;
3878
4576
  }
3879
- if (experimental?.findManyAst && canUseFindManyAstTransport(baseState)) {
4577
+ if (experimental?.findManyAst && canUseFindManyAstTransport(baseState) && !selectShapeUsesRelationSchema(options.select) && !findManyAstWhereRequiresLegacyTransport(options.where)) {
3880
4578
  const resolvedTableName = resolveTableNameForCall(tableName, void 0);
3881
4579
  const payload = {
3882
4580
  table_name: resolvedTableName,
3883
4581
  select: options.select
3884
4582
  };
3885
4583
  if (options.where !== void 0) {
3886
- payload.where = options.where;
4584
+ payload.where = normalizeFindManyAstWhere(options.where);
3887
4585
  }
3888
4586
  const astOrder = toFindManyAstOrder(executionState.order);
3889
4587
  if (astOrder !== void 0) {
@@ -3899,22 +4597,25 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
3899
4597
  limit: executionState.limit,
3900
4598
  order: executionState.order
3901
4599
  });
3902
- return executeWithQueryTrace(
3903
- tracer,
3904
- {
3905
- operation: "select",
3906
- endpoint: "/gateway/fetch",
3907
- table: resolvedTableName,
3908
- sql,
3909
- payload
3910
- },
3911
- async () => {
3912
- const response = await client.fetchGateway(
4600
+ return executeExperimentalRead(
4601
+ experimental,
4602
+ () => executeWithQueryTrace(
4603
+ tracer,
4604
+ {
4605
+ operation: "select",
4606
+ endpoint: "/gateway/fetch",
4607
+ table: resolvedTableName,
4608
+ sql,
3913
4609
  payload
3914
- );
3915
- return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3916
- },
3917
- callsite
4610
+ },
4611
+ async () => {
4612
+ const response = await client.fetchGateway(
4613
+ payload
4614
+ );
4615
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4616
+ },
4617
+ callsite
4618
+ )
3918
4619
  );
3919
4620
  }
3920
4621
  return runSelect(
@@ -4162,7 +4863,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
4162
4863
  });
4163
4864
  return builder;
4164
4865
  }
4165
- function createQueryBuilder(client, formatGatewayResult, tracer) {
4866
+ function createQueryBuilder(client, formatGatewayResult, experimental, tracer) {
4166
4867
  return async function query(query, options) {
4167
4868
  const normalizedQuery = query.trim();
4168
4869
  if (!normalizedQuery) {
@@ -4170,35 +4871,50 @@ function createQueryBuilder(client, formatGatewayResult, tracer) {
4170
4871
  }
4171
4872
  const payload = { query: normalizedQuery };
4172
4873
  const callsite = captureTraceCallsite(tracer);
4173
- return executeWithQueryTrace(
4174
- tracer,
4175
- {
4176
- operation: "query",
4177
- endpoint: "/gateway/query",
4178
- sql: normalizedQuery,
4179
- payload,
4180
- options
4181
- },
4182
- async () => {
4183
- const response = await client.queryGateway(payload, options);
4184
- return formatGatewayResult(response, { operation: "query" });
4185
- },
4186
- callsite
4874
+ return executeExperimentalRead(
4875
+ experimental,
4876
+ () => executeWithQueryTrace(
4877
+ tracer,
4878
+ {
4879
+ operation: "query",
4880
+ endpoint: "/gateway/query",
4881
+ sql: normalizedQuery,
4882
+ payload,
4883
+ options
4884
+ },
4885
+ async () => {
4886
+ const response = await client.queryGateway(payload, options);
4887
+ return formatGatewayResult(response, { operation: "query" });
4888
+ },
4889
+ callsite
4890
+ )
4187
4891
  );
4188
4892
  };
4189
4893
  }
4190
4894
  function createClientFromConfig(config) {
4895
+ const gatewayHeaders = {
4896
+ ...config.headers ?? {}
4897
+ };
4898
+ if (config.auth?.bearerToken && gatewayHeaders["X-Athena-Auth-Bearer-Token"] === void 0 && gatewayHeaders["x-athena-auth-bearer-token"] === void 0) {
4899
+ gatewayHeaders["X-Athena-Auth-Bearer-Token"] = config.auth.bearerToken;
4900
+ }
4191
4901
  const gateway = createAthenaGatewayClient({
4192
4902
  baseUrl: config.baseUrl,
4193
4903
  apiKey: config.apiKey,
4194
4904
  client: config.client,
4195
4905
  backend: config.backend,
4196
- headers: config.headers
4906
+ headers: gatewayHeaders
4197
4907
  });
4198
4908
  const formatGatewayResult = createResultFormatter(config.experimental);
4199
4909
  const queryTracer = createQueryTracer(config.experimental);
4200
4910
  const auth = createAuthClient(config.auth);
4201
- const from = (table) => createTableBuilder(table, gateway, formatGatewayResult, queryTracer, config.experimental);
4911
+ const from = (table, options) => createTableBuilder(
4912
+ resolveTableNameForCall(table, options?.schema),
4913
+ gateway,
4914
+ formatGatewayResult,
4915
+ queryTracer,
4916
+ config.experimental
4917
+ );
4202
4918
  const rpc = (fn, args, options) => {
4203
4919
  const normalizedFn = fn.trim();
4204
4920
  if (!normalizedFn) {
@@ -4214,13 +4930,14 @@ function createClientFromConfig(config) {
4214
4930
  captureTraceCallsite(queryTracer)
4215
4931
  );
4216
4932
  };
4217
- const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
4933
+ const query = createQueryBuilder(gateway, formatGatewayResult, config.experimental, queryTracer);
4218
4934
  const db = createDbModule({ from, rpc, query });
4219
4935
  return {
4220
4936
  from,
4221
4937
  db,
4222
4938
  rpc,
4223
4939
  query,
4940
+ verifyConnection: gateway.verifyConnection,
4224
4941
  auth: auth.auth
4225
4942
  };
4226
4943
  }
@@ -4263,7 +4980,6 @@ var AthenaClientBuilderImpl = class {
4263
4980
  defaultHeaders;
4264
4981
  authConfig;
4265
4982
  experimentalOptions;
4266
- isHealthTrackingEnabled = false;
4267
4983
  url(url) {
4268
4984
  this.baseUrl = url;
4269
4985
  return this;
@@ -4313,10 +5029,6 @@ var AthenaClientBuilderImpl = class {
4313
5029
  }
4314
5030
  return this;
4315
5031
  }
4316
- healthTracking(enabled) {
4317
- this.isHealthTrackingEnabled = enabled;
4318
- return this;
4319
- }
4320
5032
  build() {
4321
5033
  if (!this.baseUrl || !this.apiKey) {
4322
5034
  throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
@@ -4327,7 +5039,6 @@ var AthenaClientBuilderImpl = class {
4327
5039
  client: this.clientName,
4328
5040
  backend: this.backendConfig,
4329
5041
  headers: this.defaultHeaders,
4330
- healthTracking: this.isHealthTrackingEnabled,
4331
5042
  auth: this.authConfig,
4332
5043
  experimental: this.experimentalOptions
4333
5044
  });
@@ -4464,8 +5175,8 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
4464
5175
  });
4465
5176
  this.db = this.baseClient.db;
4466
5177
  }
4467
- from(table) {
4468
- return this.baseClient.from(table);
5178
+ from(table, options) {
5179
+ return this.baseClient.from(table, options);
4469
5180
  }
4470
5181
  rpc(fn, args, options) {
4471
5182
  return this.baseClient.rpc(fn, args, options);
@@ -4473,6 +5184,9 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
4473
5184
  query(query, options) {
4474
5185
  return this.baseClient.query(query, options);
4475
5186
  }
5187
+ verifyConnection(options) {
5188
+ return this.baseClient.verifyConnection(options);
5189
+ }
4476
5190
  withTenantContext(context) {
4477
5191
  return new _TypedAthenaClientImpl({
4478
5192
  registry: this.registry,
@@ -4509,7 +5223,7 @@ function resolveNullishValue(mode) {
4509
5223
  if (mode === "null") return null;
4510
5224
  return "";
4511
5225
  }
4512
- function isRecord7(value) {
5226
+ function isRecord8(value) {
4513
5227
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4514
5228
  }
4515
5229
  function isNullableColumn(model, key) {
@@ -4518,7 +5232,7 @@ function isNullableColumn(model, key) {
4518
5232
  }
4519
5233
  function toModelFormDefaults(model, values, options) {
4520
5234
  const source = values;
4521
- if (!isRecord7(source)) {
5235
+ if (!isRecord8(source)) {
4522
5236
  return {};
4523
5237
  }
4524
5238
  const mode = options?.nullishMode ?? "empty-string";
@@ -4740,6 +5454,6 @@ async function runSchemaGenerator(options = {}) {
4740
5454
  return throwBrowserUnsupported("runSchemaGenerator");
4741
5455
  }
4742
5456
 
4743
- export { AthenaClient, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, Backend, DEFAULT_POSTGRES_SCHEMAS, assertInt, coerceInt, createAuthClient, createAuthReactEmailInput, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createTypedClient, defineAuthEmailTemplate, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, findGeneratorConfigPath, generateArtifactsFromSnapshot, identifier, isAthenaGatewayError, isOk, loadGeneratorConfig, normalizeAthenaError, normalizeGeneratorConfig, normalizeSchemaSelection, parseBooleanFlag2 as parseBooleanFlag, renderAthenaReactEmail, requireAffected, requireSuccess, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, runSchemaGenerator, toModelFormDefaults, toModelPayload, unwrap, unwrapOne, unwrapRows, withRetry };
5457
+ export { AthenaClient, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, Backend, DEFAULT_POSTGRES_SCHEMAS, assertInt, coerceInt, createAuthClient, createAuthReactEmailInput, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createTypedClient, defineAuthEmailTemplate, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, findGeneratorConfigPath, generateArtifactsFromSnapshot, identifier, isAthenaGatewayError, isOk, loadGeneratorConfig, normalizeAthenaError, normalizeAthenaGatewayBaseUrl, normalizeGeneratorConfig, normalizeSchemaSelection, parseBooleanFlag2 as parseBooleanFlag, renderAthenaReactEmail, requireAffected, requireSuccess, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, runSchemaGenerator, toModelFormDefaults, toModelPayload, unwrap, unwrapOne, unwrapRows, verifyAthenaGatewayUrl, withRetry };
4744
5458
  //# sourceMappingURL=browser.js.map
4745
5459
  //# sourceMappingURL=browser.js.map