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