@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/index.cjs CHANGED
@@ -65,13 +65,114 @@ function isAthenaGatewayError(error) {
65
65
  return error instanceof AthenaGatewayError;
66
66
  }
67
67
 
68
+ // src/gateway/url.ts
69
+ var ATHENA_DEFAULT_BASE_URL = "https://athena-db.com";
70
+ function describeReceivedValue(value) {
71
+ if (value === void 0) return "undefined";
72
+ if (value === null) return "null";
73
+ if (typeof value === "string") {
74
+ return value.trim().length > 0 ? JSON.stringify(value) : "an empty string";
75
+ }
76
+ return `${typeof value} ${JSON.stringify(value)}`;
77
+ }
78
+ function invalidBaseUrlError(message, hint) {
79
+ return new AthenaGatewayError({
80
+ code: "INVALID_URL",
81
+ message,
82
+ status: 0,
83
+ hint
84
+ });
85
+ }
86
+ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
87
+ const label = options.label ?? "Athena gateway base URL";
88
+ const candidate = input ?? options.defaultBaseUrl;
89
+ if (candidate === void 0 || candidate === null) {
90
+ throw invalidBaseUrlError(
91
+ `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(input)}.`,
92
+ 'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
93
+ );
94
+ }
95
+ const trimmed = candidate.trim();
96
+ if (!trimmed) {
97
+ throw invalidBaseUrlError(
98
+ `${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
99
+ 'Set ATHENA_URL (or pass createClient(url, ...)) to a full URL such as "https://mirror3.athena-db.com".'
100
+ );
101
+ }
102
+ let parsed;
103
+ try {
104
+ parsed = new URL(trimmed);
105
+ } catch {
106
+ throw invalidBaseUrlError(
107
+ `${label} must be a valid absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
108
+ 'Use a full URL including the protocol, for example "https://mirror3.athena-db.com".'
109
+ );
110
+ }
111
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
112
+ throw invalidBaseUrlError(
113
+ `${label} must use http or https. Received ${JSON.stringify(trimmed)}.`,
114
+ 'Use an Athena gateway URL such as "https://mirror3.athena-db.com".'
115
+ );
116
+ }
117
+ if (parsed.search || parsed.hash) {
118
+ throw invalidBaseUrlError(
119
+ `${label} must not include query parameters or hash fragments. Received ${JSON.stringify(trimmed)}.`,
120
+ 'Pass only the base URL. Endpoint paths such as "/gateway/fetch" are appended by the SDK.'
121
+ );
122
+ }
123
+ return parsed.toString().replace(/\/+$/, "");
124
+ }
125
+ function buildAthenaGatewayUrl(baseUrl, path) {
126
+ if (!path.startsWith("/")) {
127
+ throw invalidBaseUrlError(
128
+ `Athena gateway path must start with "/". Received ${JSON.stringify(path)}.`,
129
+ 'Use a leading slash such as "/gateway/fetch" or "/".'
130
+ );
131
+ }
132
+ return `${baseUrl}${path}`;
133
+ }
134
+
135
+ // src/cookies/cookie-utils.ts
136
+ var SECURE_COOKIE_PREFIX = "__Secure-";
137
+ function parseCookies(cookieHeader) {
138
+ const cookies = cookieHeader.split("; ");
139
+ const cookieMap = /* @__PURE__ */ new Map();
140
+ cookies.forEach((cookie) => {
141
+ const [name, value] = cookie.split(/=(.*)/s);
142
+ cookieMap.set(name, value);
143
+ });
144
+ return cookieMap;
145
+ }
146
+ var getSessionCookie = (request, config) => {
147
+ const cookies = (request instanceof Headers || !("headers" in request) ? request : request.headers).get("cookie");
148
+ if (!cookies) {
149
+ return null;
150
+ }
151
+ const { cookieName = "session_token", cookiePrefix = "athena-auth" } = {};
152
+ const parsedCookie = parseCookies(cookies);
153
+ const getCookie = (name) => parsedCookie.get(name) || parsedCookie.get(`${SECURE_COOKIE_PREFIX}${name}`);
154
+ const sessionToken = getCookie(`${cookiePrefix}.${cookieName}`) || getCookie(`${cookiePrefix}-${cookieName}`);
155
+ if (sessionToken) {
156
+ return sessionToken;
157
+ }
158
+ return null;
159
+ };
160
+
161
+ // package.json
162
+ var package_default = {
163
+ version: "2.4.1"
164
+ };
165
+
166
+ // src/sdk-version.ts
167
+ var PACKAGE_VERSION = package_default.version;
168
+ function buildSdkHeaderValue(sdkName) {
169
+ return `${sdkName} ${PACKAGE_VERSION}`;
170
+ }
171
+
68
172
  // src/gateway/client.ts
69
- var DEFAULT_BASE_URL = "https://athena-db.com";
70
173
  var DEFAULT_CLIENT = "railway_direct";
71
- var FALLBACK_SDK_VERSION = "1.3.0";
72
174
  var SDK_NAME = "xylex-group/athena";
73
- var SDK_VERSION = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION;
74
- var SDK_HEADER_VALUE = `${SDK_NAME} ${SDK_VERSION}`;
175
+ var SDK_HEADER_VALUE = buildSdkHeaderValue(SDK_NAME);
75
176
  function parseResponseBody(rawText, contentType) {
76
177
  if (!rawText) {
77
178
  return { parsed: null, parseFailed: false };
@@ -90,6 +191,37 @@ function parseResponseBody(rawText, contentType) {
90
191
  function normalizeHeaderValue(value) {
91
192
  return value ? value : void 0;
92
193
  }
194
+ function resolveHeaderValue(headers, candidates) {
195
+ for (const candidate of candidates) {
196
+ const direct = normalizeHeaderValue(headers[candidate]);
197
+ if (direct) return direct;
198
+ }
199
+ const loweredCandidates = new Set(candidates.map((candidate) => candidate.toLowerCase()));
200
+ for (const [key, value] of Object.entries(headers)) {
201
+ if (!loweredCandidates.has(key.toLowerCase())) {
202
+ continue;
203
+ }
204
+ const normalized = normalizeHeaderValue(value);
205
+ if (normalized) return normalized;
206
+ }
207
+ return void 0;
208
+ }
209
+ function resolveBearerTokenFromAuthorizationHeader(headers) {
210
+ const authorization = resolveHeaderValue(headers, ["Authorization"]);
211
+ if (!authorization) {
212
+ return void 0;
213
+ }
214
+ const match = authorization.match(/^Bearer\s+(.+)$/i);
215
+ const token = match?.[1]?.trim();
216
+ return token ? token : void 0;
217
+ }
218
+ function resolveSessionTokenFromCookieHeader(headers) {
219
+ const cookie = resolveHeaderValue(headers, ["Cookie"]);
220
+ if (!cookie) {
221
+ return void 0;
222
+ }
223
+ return getSessionCookie(new Headers({ cookie })) ?? void 0;
224
+ }
93
225
  function isRecord(value) {
94
226
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
95
227
  }
@@ -207,7 +339,7 @@ function buildRpcGetEndpoint(payload) {
207
339
  status: 0
208
340
  });
209
341
  }
210
- query.set(filter.column, toRpcFilterQueryValue(filter));
342
+ query.append(filter.column, toRpcFilterQueryValue(filter));
211
343
  }
212
344
  }
213
345
  const endpoint = `/rpc/${encodeURIComponent(functionName)}`;
@@ -253,6 +385,20 @@ function buildHeaders(config, options) {
253
385
  headers["apikey"] = finalApiKey;
254
386
  headers["x-api-key"] = headers["x-api-key"] ?? finalApiKey;
255
387
  }
388
+ const explicitSessionToken = resolveHeaderValue(extraHeaders, [
389
+ "X-Athena-Auth-Session-Token"
390
+ ]);
391
+ const derivedSessionToken = explicitSessionToken ?? resolveSessionTokenFromCookieHeader(extraHeaders);
392
+ if (derivedSessionToken) {
393
+ headers["X-Athena-Auth-Session-Token"] = derivedSessionToken;
394
+ }
395
+ const explicitBearerToken = resolveHeaderValue(extraHeaders, [
396
+ "X-Athena-Auth-Bearer-Token"
397
+ ]);
398
+ const derivedBearerToken = explicitBearerToken ?? resolveBearerTokenFromAuthorizationHeader(extraHeaders);
399
+ if (derivedBearerToken) {
400
+ headers["X-Athena-Auth-Bearer-Token"] = derivedBearerToken;
401
+ }
256
402
  const athenaClientKeys = ["x-athena-client", "X-Athena-Client"];
257
403
  Object.entries(extraHeaders).forEach(([key, value]) => {
258
404
  if (athenaClientKeys.includes(key)) return;
@@ -263,9 +409,172 @@ function buildHeaders(config, options) {
263
409
  });
264
410
  return headers;
265
411
  }
412
+ function toInvalidUrlResponse(error, endpoint, method) {
413
+ const message = error instanceof Error ? error.message : String(error);
414
+ const gatewayError = error instanceof AthenaGatewayError ? error : new AthenaGatewayError({
415
+ code: "INVALID_URL",
416
+ message,
417
+ status: 0,
418
+ endpoint,
419
+ method,
420
+ cause: message,
421
+ hint: "Set ATHENA_URL to a full http(s) URL before running queries."
422
+ });
423
+ return {
424
+ ok: false,
425
+ status: 0,
426
+ statusText: null,
427
+ data: null,
428
+ error: gatewayError.message,
429
+ errorDetails: detailsFromError(
430
+ new AthenaGatewayError({
431
+ code: gatewayError.code,
432
+ message: gatewayError.message,
433
+ status: gatewayError.status,
434
+ endpoint,
435
+ method,
436
+ requestId: gatewayError.requestId,
437
+ hint: gatewayError.hint,
438
+ cause: gatewayError.causeDetail
439
+ })
440
+ ),
441
+ raw: null
442
+ };
443
+ }
444
+ function resolveGatewayBaseUrl(input) {
445
+ return normalizeAthenaGatewayBaseUrl(input, {
446
+ defaultBaseUrl: ATHENA_DEFAULT_BASE_URL
447
+ });
448
+ }
449
+ function resolveProbePath(path) {
450
+ if (!path) return "/";
451
+ if (!path.startsWith("/")) {
452
+ throw new AthenaGatewayError({
453
+ code: "INVALID_URL",
454
+ message: `Athena gateway probe path must start with "/". Received ${JSON.stringify(path)}.`,
455
+ status: 0,
456
+ hint: 'Use a leading slash such as "/" or "/health".'
457
+ });
458
+ }
459
+ return path;
460
+ }
461
+ function mergeConnectionHeaders(baseHeaders, headers) {
462
+ const merged = {
463
+ ...baseHeaders,
464
+ ...headers ?? {}
465
+ };
466
+ if (!merged["X-Athena-Sdk"] && !merged["x-athena-sdk"]) {
467
+ merged["X-Athena-Sdk"] = SDK_HEADER_VALUE;
468
+ }
469
+ return merged;
470
+ }
471
+ async function performConnectionCheck(baseUrl, requestHeaders, options) {
472
+ const path = resolveProbePath(options?.path);
473
+ const url = buildAthenaGatewayUrl(baseUrl, path);
474
+ try {
475
+ const response = await fetch(url, {
476
+ method: "GET",
477
+ headers: mergeConnectionHeaders(requestHeaders, options?.headers),
478
+ signal: options?.signal
479
+ });
480
+ const rawText = await response.text();
481
+ const requestId = resolveRequestId(response.headers);
482
+ const parsedBody = parseResponseBody(
483
+ rawText ?? "",
484
+ response.headers.get("content-type")
485
+ );
486
+ if (parsedBody.parseFailed) {
487
+ const invalidJsonError = new AthenaGatewayError({
488
+ code: "INVALID_JSON",
489
+ message: "Gateway probe returned malformed JSON",
490
+ status: response.status,
491
+ method: "GET",
492
+ requestId,
493
+ hint: "Verify the gateway response body is valid JSON.",
494
+ cause: rawText.slice(0, 300)
495
+ });
496
+ return {
497
+ ok: false,
498
+ reachable: true,
499
+ status: response.status,
500
+ statusText: resolveStatusText(response, parsedBody.parsed),
501
+ baseUrl,
502
+ url,
503
+ error: invalidJsonError.message,
504
+ errorDetails: detailsFromError(invalidJsonError),
505
+ raw: parsedBody.parsed
506
+ };
507
+ }
508
+ const parsed = parsedBody.parsed;
509
+ if (!response.ok) {
510
+ const httpError = new AthenaGatewayError({
511
+ code: "HTTP_ERROR",
512
+ message: resolveErrorMessage(
513
+ parsed,
514
+ `Athena gateway GET ${path} failed with status ${response.status}`
515
+ ),
516
+ status: response.status,
517
+ method: "GET",
518
+ requestId,
519
+ hint: resolveErrorHint(parsed)
520
+ });
521
+ return {
522
+ ok: false,
523
+ reachable: true,
524
+ status: response.status,
525
+ statusText: resolveStatusText(response, parsed),
526
+ baseUrl,
527
+ url,
528
+ error: httpError.message,
529
+ errorDetails: detailsFromError(httpError),
530
+ raw: parsed
531
+ };
532
+ }
533
+ return {
534
+ ok: true,
535
+ reachable: true,
536
+ status: response.status,
537
+ statusText: resolveStatusText(response, parsed),
538
+ baseUrl,
539
+ url,
540
+ error: void 0,
541
+ errorDetails: null,
542
+ raw: parsed
543
+ };
544
+ } catch (callError) {
545
+ const message = callError instanceof Error ? callError.message : String(callError);
546
+ const networkError = new AthenaGatewayError({
547
+ code: "NETWORK_ERROR",
548
+ message: `Network error while probing Athena gateway ${url}: ${message}`,
549
+ method: "GET",
550
+ cause: message,
551
+ hint: "Check gateway URL, DNS, and network reachability."
552
+ });
553
+ return {
554
+ ok: false,
555
+ reachable: false,
556
+ status: 0,
557
+ statusText: null,
558
+ baseUrl,
559
+ url,
560
+ error: networkError.message,
561
+ errorDetails: detailsFromError(networkError),
562
+ raw: null
563
+ };
564
+ }
565
+ }
566
+ async function verifyAthenaGatewayUrl(baseUrl, options) {
567
+ const normalizedBaseUrl = normalizeAthenaGatewayBaseUrl(baseUrl);
568
+ return performConnectionCheck(normalizedBaseUrl, { "X-Athena-Sdk": SDK_HEADER_VALUE }, options);
569
+ }
266
570
  async function callAthena(config, endpoint, method, payload, options) {
267
- const baseUrl = (options?.baseUrl ?? config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
268
- const url = `${baseUrl}${endpoint}`;
571
+ let baseUrl;
572
+ try {
573
+ baseUrl = resolveGatewayBaseUrl(options?.baseUrl ?? config.baseUrl);
574
+ } catch (error) {
575
+ return toInvalidUrlResponse(error, endpoint, method);
576
+ }
577
+ const url = buildAthenaGatewayUrl(baseUrl, endpoint);
269
578
  const headers = buildHeaders(config, options);
270
579
  try {
271
580
  const requestInit = {
@@ -362,32 +671,44 @@ async function callAthena(config, endpoint, method, payload, options) {
362
671
  }
363
672
  }
364
673
  function createAthenaGatewayClient(config = {}) {
674
+ const normalizedBaseUrl = resolveGatewayBaseUrl(config.baseUrl);
675
+ const normalizedConfig = {
676
+ ...config,
677
+ baseUrl: normalizedBaseUrl
678
+ };
365
679
  return {
366
- baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, ""),
680
+ baseUrl: normalizedBaseUrl,
367
681
  buildHeaders(options) {
368
- return buildHeaders(config, options);
682
+ return buildHeaders(normalizedConfig, options);
683
+ },
684
+ verifyConnection(options) {
685
+ return performConnectionCheck(
686
+ normalizedBaseUrl,
687
+ buildHeaders(normalizedConfig),
688
+ options
689
+ );
369
690
  },
370
691
  fetchGateway(payload, options) {
371
- return callAthena(config, "/gateway/fetch", "POST", payload, options);
692
+ return callAthena(normalizedConfig, "/gateway/fetch", "POST", payload, options);
372
693
  },
373
694
  insertGateway(payload, options) {
374
- return callAthena(config, "/gateway/insert", "PUT", payload, options);
695
+ return callAthena(normalizedConfig, "/gateway/insert", "PUT", payload, options);
375
696
  },
376
697
  updateGateway(payload, options) {
377
- return callAthena(config, "/gateway/update", "POST", payload, options);
698
+ return callAthena(normalizedConfig, "/gateway/update", "POST", payload, options);
378
699
  },
379
700
  deleteGateway(payload, options) {
380
- return callAthena(config, "/gateway/delete", "DELETE", payload, options);
701
+ return callAthena(normalizedConfig, "/gateway/delete", "DELETE", payload, options);
381
702
  },
382
703
  rpcGateway(payload, options) {
383
704
  if (options?.get) {
384
705
  const endpoint = buildRpcGetEndpoint(payload);
385
- return callAthena(config, endpoint, "GET", null, options);
706
+ return callAthena(normalizedConfig, endpoint, "GET", null, options);
386
707
  }
387
- return callAthena(config, "/gateway/rpc", "POST", payload, options);
708
+ return callAthena(normalizedConfig, "/gateway/rpc", "POST", payload, options);
388
709
  },
389
710
  queryGateway(payload, options) {
390
- return callAthena(config, "/gateway/query", "POST", payload, options);
711
+ return callAthena(normalizedConfig, "/gateway/query", "POST", payload, options);
391
712
  }
392
713
  };
393
714
  }
@@ -773,10 +1094,8 @@ async function resolveReactEmailPayloadFields(input, fields, options) {
773
1094
 
774
1095
  // src/auth/client.ts
775
1096
  var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
776
- var FALLBACK_SDK_VERSION2 = "1.0.0";
777
1097
  var SDK_NAME2 = "xylex-group/athena-auth";
778
- var SDK_VERSION2 = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION2;
779
- var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
1098
+ var SDK_HEADER_VALUE2 = buildSdkHeaderValue(SDK_NAME2);
780
1099
  function normalizeBaseUrl(baseUrl) {
781
1100
  return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
782
1101
  }
@@ -2029,6 +2348,7 @@ function classifyKind(status, code, message) {
2029
2348
  if (status === 404 || hasNotFoundPattern) return "not_found";
2030
2349
  if (status === 401 || status === 403 || hasAuthPattern) return "auth";
2031
2350
  if (status === 429 || hasRateLimitPattern) return "rate_limit";
2351
+ if (code === "INVALID_URL") return "validation";
2032
2352
  if (status === 400 || status === 422 || hasValidationPattern) return "validation";
2033
2353
  if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
2034
2354
  return "transient";
@@ -2036,6 +2356,9 @@ function classifyKind(status, code, message) {
2036
2356
  return "unknown";
2037
2357
  }
2038
2358
  function toAthenaErrorCode(kind, status, gatewayCode) {
2359
+ if (gatewayCode === "INVALID_URL") {
2360
+ return AthenaErrorCode.ValidationFailed;
2361
+ }
2039
2362
  if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
2040
2363
  return AthenaErrorCode.NetworkUnavailable;
2041
2364
  }
@@ -2384,8 +2707,8 @@ async function withRetry(config, fn) {
2384
2707
  // src/db/module.ts
2385
2708
  function createDbModule(input) {
2386
2709
  const db = {
2387
- from(table) {
2388
- return input.from(table);
2710
+ from(table, options) {
2711
+ return input.from(table, options);
2389
2712
  },
2390
2713
  select(table, columns, options) {
2391
2714
  return input.from(table).select(columns, options);
@@ -2490,7 +2813,19 @@ function buildGatewayCondition(operator, column, value) {
2490
2813
  function compileRelationToken(key, node) {
2491
2814
  const nested = compileSelectShape(node.select);
2492
2815
  const propertyKey = normalizeIdentifier(key, "select relation key");
2493
- const relationToken = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
2816
+ if (node.schema && node.via) {
2817
+ throw new Error(
2818
+ `findMany relation "${propertyKey}" cannot combine schema and via yet; use schema with the relation key, or use via without schema`
2819
+ );
2820
+ }
2821
+ const relationTokenBase = normalizeIdentifier(node.via ?? propertyKey, "select relation token");
2822
+ if (node.schema && relationTokenBase.includes(".")) {
2823
+ throw new Error(
2824
+ `findMany relation "${propertyKey}" already resolves to a qualified relation token; do not also set schema`
2825
+ );
2826
+ }
2827
+ const relationSchema = node.schema?.trim();
2828
+ const relationToken = relationSchema ? `${normalizeIdentifier(relationSchema, "select relation schema")}.${relationTokenBase}` : relationTokenBase;
2494
2829
  const alias = node.as?.trim() || (relationToken !== propertyKey ? propertyKey : "");
2495
2830
  const prefix = alias ? `${alias}:` : "";
2496
2831
  return `${prefix}${relationToken}(${nested})`;
@@ -2519,6 +2854,23 @@ function compileSelectShape(select) {
2519
2854
  }
2520
2855
  return tokens.join(",");
2521
2856
  }
2857
+ function selectShapeUsesRelationSchema(select) {
2858
+ if (!isRecord5(select)) {
2859
+ return false;
2860
+ }
2861
+ for (const rawValue of Object.values(select)) {
2862
+ if (!isRelationSelectNode(rawValue)) {
2863
+ continue;
2864
+ }
2865
+ if (typeof rawValue.schema === "string" && rawValue.schema.trim().length > 0) {
2866
+ return true;
2867
+ }
2868
+ if (selectShapeUsesRelationSchema(rawValue.select)) {
2869
+ return true;
2870
+ }
2871
+ }
2872
+ return false;
2873
+ }
2522
2874
  function compileColumnWhere(column, input) {
2523
2875
  const normalizedColumn = normalizeIdentifier(column, "where column");
2524
2876
  if (!isRecord5(input)) {
@@ -2655,6 +3007,356 @@ function compileOrderBy(orderBy) {
2655
3007
  };
2656
3008
  }
2657
3009
 
3010
+ // src/gateway/structured-select.ts
3011
+ var IDENTIFIER_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
3012
+ function isIdentifierPath(value) {
3013
+ const segments = value.split(".").map((segment) => segment.trim());
3014
+ return segments.length > 1 && segments.every((segment) => IDENTIFIER_SEGMENT_PATTERN.test(segment));
3015
+ }
3016
+ function extractRelationHead(raw) {
3017
+ const trimmed = raw.trim();
3018
+ if (!trimmed) return "";
3019
+ const aliasIndex = trimmed.indexOf(":");
3020
+ const withoutAlias = aliasIndex >= 0 ? trimmed.slice(aliasIndex + 1).trim() : trimmed;
3021
+ const modifierIndex = withoutAlias.indexOf("!");
3022
+ return (modifierIndex >= 0 ? withoutAlias.slice(0, modifierIndex) : withoutAlias).trim();
3023
+ }
3024
+ function hasSchemaQualifiedRelationToken(select) {
3025
+ let singleQuoted = false;
3026
+ let doubleQuoted = false;
3027
+ let tokenStart = 0;
3028
+ for (let index = 0; index < select.length; index += 1) {
3029
+ const char = select[index];
3030
+ const next = index + 1 < select.length ? select[index + 1] : "";
3031
+ if (singleQuoted) {
3032
+ if (char === "'" && next === "'") {
3033
+ index += 1;
3034
+ continue;
3035
+ }
3036
+ if (char === "'") {
3037
+ singleQuoted = false;
3038
+ }
3039
+ continue;
3040
+ }
3041
+ if (doubleQuoted) {
3042
+ if (char === '"' && next === '"') {
3043
+ index += 1;
3044
+ continue;
3045
+ }
3046
+ if (char === '"') {
3047
+ doubleQuoted = false;
3048
+ }
3049
+ continue;
3050
+ }
3051
+ if (char === "'") {
3052
+ singleQuoted = true;
3053
+ continue;
3054
+ }
3055
+ if (char === '"') {
3056
+ doubleQuoted = true;
3057
+ continue;
3058
+ }
3059
+ if (char === "(") {
3060
+ const relationHead = extractRelationHead(select.slice(tokenStart, index));
3061
+ if (isIdentifierPath(relationHead)) {
3062
+ return true;
3063
+ }
3064
+ tokenStart = index + 1;
3065
+ continue;
3066
+ }
3067
+ if (char === "," || char === ")") {
3068
+ tokenStart = index + 1;
3069
+ }
3070
+ }
3071
+ return false;
3072
+ }
3073
+ function toStructuredSelectString(columns) {
3074
+ return Array.isArray(columns) ? columns.join(",") : columns;
3075
+ }
3076
+ function buildStructuredWhere(conditions) {
3077
+ if (!conditions?.length) return void 0;
3078
+ const where = {};
3079
+ for (const condition of conditions) {
3080
+ if (!condition.column) {
3081
+ return null;
3082
+ }
3083
+ if (condition.value_cast !== void 0) {
3084
+ return null;
3085
+ }
3086
+ const operand = condition.value;
3087
+ const operator = condition.operator;
3088
+ if (operator === "eq") {
3089
+ if (operand === void 0) return null;
3090
+ } else if (operator === "neq" || operator === "gt" || operator === "lt") {
3091
+ if (operand === void 0) return null;
3092
+ } else if (operator === "in") {
3093
+ if (!Array.isArray(operand)) return null;
3094
+ } else {
3095
+ return null;
3096
+ }
3097
+ const existing = where[condition.column];
3098
+ if (existing !== void 0 && (typeof existing !== "object" || existing === null || Array.isArray(existing))) {
3099
+ return null;
3100
+ }
3101
+ const next = existing ?? {};
3102
+ if (Object.prototype.hasOwnProperty.call(next, operator)) {
3103
+ return null;
3104
+ }
3105
+ next[operator] = operand;
3106
+ where[condition.column] = next;
3107
+ }
3108
+ return where;
3109
+ }
3110
+ function buildStructuredOrderBy(order) {
3111
+ if (!order?.field) return void 0;
3112
+ return {
3113
+ [order.field]: order.direction === "descending" ? "desc" : "asc"
3114
+ };
3115
+ }
3116
+ function buildStructuredSelectTransport(input) {
3117
+ const select = toStructuredSelectString(input.columns).trim();
3118
+ if (!select || select === "*") {
3119
+ return null;
3120
+ }
3121
+ if (!hasSchemaQualifiedRelationToken(select)) {
3122
+ return null;
3123
+ }
3124
+ if (input.count !== void 0 || input.head !== void 0) {
3125
+ return {
3126
+ error: "Schema-qualified nested select strings require structured select transport, which does not support count/head options in athena-js yet."
3127
+ };
3128
+ }
3129
+ const where = buildStructuredWhere(input.conditions);
3130
+ if (where === null) {
3131
+ return {
3132
+ error: "Schema-qualified nested select strings only support eq, neq, gt, lt, and in filters in athena-js structured select transport."
3133
+ };
3134
+ }
3135
+ return {
3136
+ select,
3137
+ payload: {
3138
+ table_name: input.tableName,
3139
+ select,
3140
+ where,
3141
+ orderBy: buildStructuredOrderBy(input.order),
3142
+ limit: input.limit,
3143
+ offset: input.offset,
3144
+ strip_nulls: input.stripNulls
3145
+ }
3146
+ };
3147
+ }
3148
+
3149
+ // src/query-transport.ts
3150
+ function canUseFindManyAstTransport(state) {
3151
+ return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
3152
+ }
3153
+ function toFindManyAstOrder(order) {
3154
+ if (!order) {
3155
+ return void 0;
3156
+ }
3157
+ return {
3158
+ column: order.field,
3159
+ ascending: order.direction !== "descending"
3160
+ };
3161
+ }
3162
+ function isRecord6(value) {
3163
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3164
+ }
3165
+ function normalizeFindManyAstColumnPredicate(value) {
3166
+ if (!isRecord6(value)) {
3167
+ return {
3168
+ eq: value
3169
+ };
3170
+ }
3171
+ const normalized = {};
3172
+ for (const [key, operand] of Object.entries(value)) {
3173
+ if (operand !== void 0) {
3174
+ normalized[key] = operand;
3175
+ }
3176
+ }
3177
+ return normalized;
3178
+ }
3179
+ function normalizeFindManyAstBooleanOperand(clause) {
3180
+ const normalized = {};
3181
+ for (const [column, value] of Object.entries(clause)) {
3182
+ if (value === void 0) {
3183
+ continue;
3184
+ }
3185
+ normalized[column] = normalizeFindManyAstColumnPredicate(value);
3186
+ }
3187
+ return normalized;
3188
+ }
3189
+ function normalizeFindManyAstWhere(where) {
3190
+ if (!where || !isRecord6(where)) {
3191
+ return where;
3192
+ }
3193
+ const normalized = {};
3194
+ for (const [key, value] of Object.entries(where)) {
3195
+ if (value === void 0) {
3196
+ continue;
3197
+ }
3198
+ if (key === "or" && Array.isArray(value)) {
3199
+ normalized.or = value.map(
3200
+ (clause) => normalizeFindManyAstBooleanOperand(clause)
3201
+ );
3202
+ continue;
3203
+ }
3204
+ if (key === "not" && isRecord6(value)) {
3205
+ normalized.not = normalizeFindManyAstBooleanOperand(
3206
+ value
3207
+ );
3208
+ continue;
3209
+ }
3210
+ normalized[key] = normalizeFindManyAstColumnPredicate(value);
3211
+ }
3212
+ return normalized;
3213
+ }
3214
+ function predicateRequiresUuidQueryFallback(column, value) {
3215
+ if (!isRecord6(value)) {
3216
+ return shouldUseUuidTextComparison(column, value);
3217
+ }
3218
+ const eqValue = value.eq;
3219
+ return eqValue !== void 0 && shouldUseUuidTextComparison(column, eqValue);
3220
+ }
3221
+ function booleanOperandRequiresUuidQueryFallback(clause) {
3222
+ for (const [column, value] of Object.entries(clause)) {
3223
+ if (value === void 0) {
3224
+ continue;
3225
+ }
3226
+ if (predicateRequiresUuidQueryFallback(column, value)) {
3227
+ return true;
3228
+ }
3229
+ }
3230
+ return false;
3231
+ }
3232
+ function findManyAstWhereRequiresLegacyTransport(where) {
3233
+ if (!where || !isRecord6(where)) {
3234
+ return false;
3235
+ }
3236
+ for (const [key, value] of Object.entries(where)) {
3237
+ if (value === void 0) {
3238
+ continue;
3239
+ }
3240
+ if (key === "or" && Array.isArray(value)) {
3241
+ if (value.some(
3242
+ (clause) => booleanOperandRequiresUuidQueryFallback(clause)
3243
+ )) {
3244
+ return true;
3245
+ }
3246
+ continue;
3247
+ }
3248
+ if (key === "not" && isRecord6(value)) {
3249
+ if (booleanOperandRequiresUuidQueryFallback(value)) {
3250
+ return true;
3251
+ }
3252
+ continue;
3253
+ }
3254
+ if (predicateRequiresUuidQueryFallback(key, value)) {
3255
+ return true;
3256
+ }
3257
+ }
3258
+ return false;
3259
+ }
3260
+ function resolvePagination(input) {
3261
+ let limit = input.limit;
3262
+ let offset = input.offset;
3263
+ if (limit === void 0 && input.pageSize !== void 0) {
3264
+ limit = Math.max(0, Math.trunc(input.pageSize));
3265
+ }
3266
+ if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
3267
+ offset = (Math.trunc(input.currentPage) - 1) * Math.max(0, Math.trunc(input.pageSize));
3268
+ }
3269
+ return { limit, offset };
3270
+ }
3271
+ function hasTypedEqualityComparison(conditions) {
3272
+ return conditions?.some(
3273
+ (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
3274
+ ) ?? false;
3275
+ }
3276
+ function createSelectTransportPlan(input) {
3277
+ const conditions = input.state.conditions.length ? input.state.conditions.map((condition) => ({ ...condition })) : void 0;
3278
+ const pagination = resolvePagination({
3279
+ limit: input.state.limit,
3280
+ offset: input.state.offset,
3281
+ currentPage: input.state.currentPage,
3282
+ pageSize: input.state.pageSize
3283
+ });
3284
+ const stripNulls = input.options?.stripNulls ?? true;
3285
+ const structuredSelectTransport = buildStructuredSelectTransport({
3286
+ tableName: input.tableName,
3287
+ columns: input.columns,
3288
+ conditions,
3289
+ limit: pagination.limit,
3290
+ offset: pagination.offset,
3291
+ order: input.state.order,
3292
+ stripNulls,
3293
+ count: input.options?.count,
3294
+ head: input.options?.head
3295
+ });
3296
+ if (structuredSelectTransport && "error" in structuredSelectTransport) {
3297
+ throw new Error(structuredSelectTransport.error);
3298
+ }
3299
+ if (structuredSelectTransport) {
3300
+ const { payload, select } = structuredSelectTransport;
3301
+ return {
3302
+ kind: "fetch",
3303
+ payload,
3304
+ debug: {
3305
+ columns: select,
3306
+ conditions,
3307
+ limit: pagination.limit,
3308
+ offset: pagination.offset,
3309
+ order: input.state.order
3310
+ }
3311
+ };
3312
+ }
3313
+ if (hasTypedEqualityComparison(conditions) && !input.options?.head && !input.options?.count && conditions) {
3314
+ const query = input.buildTypedSelectQuery({
3315
+ tableName: input.tableName,
3316
+ columns: input.columns,
3317
+ conditions,
3318
+ limit: input.state.limit,
3319
+ offset: input.state.offset,
3320
+ currentPage: input.state.currentPage,
3321
+ pageSize: input.state.pageSize,
3322
+ order: input.state.order
3323
+ });
3324
+ if (query) {
3325
+ return {
3326
+ kind: "query",
3327
+ query,
3328
+ payload: { query }
3329
+ };
3330
+ }
3331
+ }
3332
+ return {
3333
+ kind: "fetch",
3334
+ payload: {
3335
+ table_name: input.tableName,
3336
+ columns: input.columns,
3337
+ conditions,
3338
+ limit: input.state.limit,
3339
+ offset: input.state.offset,
3340
+ current_page: input.state.currentPage,
3341
+ page_size: input.state.pageSize,
3342
+ total_pages: input.state.totalPages,
3343
+ sort_by: input.state.order,
3344
+ strip_nulls: stripNulls,
3345
+ count: input.options?.count,
3346
+ head: input.options?.head
3347
+ },
3348
+ debug: {
3349
+ columns: input.columns,
3350
+ conditions,
3351
+ limit: input.state.limit,
3352
+ offset: input.state.offset,
3353
+ currentPage: input.state.currentPage,
3354
+ pageSize: input.state.pageSize,
3355
+ order: input.state.order
3356
+ }
3357
+ };
3358
+ }
3359
+
2658
3360
  // src/client.ts
2659
3361
  var DEFAULT_COLUMNS = "*";
2660
3362
  var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
@@ -2669,18 +3371,6 @@ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
2669
3371
  "node:internal",
2670
3372
  "internal/process"
2671
3373
  ];
2672
- function canUseFindManyAstTransport(state) {
2673
- return state.conditions.length === 0 && state.offset === void 0 && state.currentPage === void 0 && state.pageSize === void 0 && state.totalPages === void 0;
2674
- }
2675
- function toFindManyAstOrder(order) {
2676
- if (!order) {
2677
- return void 0;
2678
- }
2679
- return {
2680
- column: order.field,
2681
- ascending: order.direction !== "descending"
2682
- };
2683
- }
2684
3374
  function formatResult(response) {
2685
3375
  const result = {
2686
3376
  data: response.data ?? null,
@@ -2695,6 +3385,13 @@ function formatResult(response) {
2695
3385
  }
2696
3386
  return result;
2697
3387
  }
3388
+ var EXPERIMENTAL_READ_RETRY_CONFIG = {
3389
+ retries: 2,
3390
+ baseDelayMs: 100,
3391
+ maxDelayMs: 1e3,
3392
+ backoff: "exponential",
3393
+ jitter: true
3394
+ };
2698
3395
  function attachNormalizedError(result, normalizedError) {
2699
3396
  Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
2700
3397
  value: normalizedError,
@@ -2721,7 +3418,36 @@ function createResultFormatter(experimental) {
2721
3418
  return result;
2722
3419
  };
2723
3420
  }
2724
- function isRecord6(value) {
3421
+ async function executeExperimentalRead(experimental, runner) {
3422
+ if (!experimental?.retryReads) {
3423
+ return runner();
3424
+ }
3425
+ let lastRetryableResult;
3426
+ let lastRetrySignal = null;
3427
+ try {
3428
+ return await withRetry(
3429
+ {
3430
+ ...EXPERIMENTAL_READ_RETRY_CONFIG,
3431
+ shouldRetry: (error) => error === lastRetrySignal || normalizeAthenaError(error).retryable
3432
+ },
3433
+ async () => {
3434
+ const result = await runner();
3435
+ if (result.error?.retryable) {
3436
+ lastRetryableResult = result;
3437
+ lastRetrySignal = result.error;
3438
+ throw lastRetrySignal;
3439
+ }
3440
+ return result;
3441
+ }
3442
+ );
3443
+ } catch (error) {
3444
+ if (lastRetryableResult && error === lastRetrySignal) {
3445
+ return lastRetryableResult;
3446
+ }
3447
+ throw error;
3448
+ }
3449
+ }
3450
+ function isRecord7(value) {
2725
3451
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2726
3452
  }
2727
3453
  function firstNonEmptyString2(...values) {
@@ -2733,8 +3459,8 @@ function firstNonEmptyString2(...values) {
2733
3459
  return void 0;
2734
3460
  }
2735
3461
  function resolveStructuredErrorPayload2(raw) {
2736
- if (!isRecord6(raw)) return null;
2737
- return isRecord6(raw.error) ? raw.error : raw;
3462
+ if (!isRecord7(raw)) return null;
3463
+ return isRecord7(raw.error) ? raw.error : raw;
2738
3464
  }
2739
3465
  function resolveStructuredErrorDetails(payload, message) {
2740
3466
  if (!payload || !("details" in payload)) {
@@ -2750,7 +3476,7 @@ function resolveStructuredErrorDetails(payload, message) {
2750
3476
  return details;
2751
3477
  }
2752
3478
  function createResultError(response, result, normalized) {
2753
- const rawRecord = isRecord6(response.raw) ? response.raw : null;
3479
+ const rawRecord = isRecord7(response.raw) ? response.raw : null;
2754
3480
  const payload = resolveStructuredErrorPayload2(response.raw);
2755
3481
  const message = firstNonEmptyString2(
2756
3482
  response.error,
@@ -2945,7 +3671,14 @@ function toSingleResult(response) {
2945
3671
  function mergeOptions(...options) {
2946
3672
  return options.reduce((acc, next) => {
2947
3673
  if (!next) return acc;
2948
- return { ...acc, ...next };
3674
+ const merged = { ...acc ?? {}, ...next };
3675
+ if (acc?.headers || next.headers) {
3676
+ merged.headers = {
3677
+ ...acc?.headers ?? {},
3678
+ ...next.headers ?? {}
3679
+ };
3680
+ }
3681
+ return merged;
2949
3682
  }, void 0);
2950
3683
  }
2951
3684
  function asAthenaJsonObject(value) {
@@ -3226,17 +3959,6 @@ function conditionToDebugSqlClause(condition) {
3226
3959
  return `TRUE /* unsupported condition: ${rawCondition} */`;
3227
3960
  }
3228
3961
  }
3229
- function resolvePagination(input) {
3230
- let limit = input.limit;
3231
- let offset = input.offset;
3232
- if (limit === void 0 && input.pageSize !== void 0) {
3233
- limit = input.pageSize;
3234
- }
3235
- if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
3236
- offset = (input.currentPage - 1) * input.pageSize;
3237
- }
3238
- return { limit, offset };
3239
- }
3240
3962
  function appendOrderLimitOffset(sqlParts, order, limit, offset) {
3241
3963
  if (order?.field) {
3242
3964
  const direction = order.direction === "descending" ? "DESC" : "ASC";
@@ -3740,80 +4462,56 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
3740
4462
  );
3741
4463
  const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
3742
4464
  const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
3743
- const conditions = executionState.conditions.length ? executionState.conditions.map((condition) => ({ ...condition })) : void 0;
3744
- const hasTypedEqualityComparison = conditions?.some(
3745
- (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
3746
- ) ?? false;
3747
- if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
3748
- const query = buildTypedSelectQuery({
3749
- tableName: resolvedTableName,
3750
- columns,
3751
- conditions,
3752
- limit: executionState.limit,
3753
- offset: executionState.offset,
3754
- currentPage: executionState.currentPage,
3755
- pageSize: executionState.pageSize,
3756
- order: executionState.order
3757
- });
3758
- if (query) {
3759
- const payload2 = { query };
3760
- return executeWithQueryTrace(
4465
+ const plan = createSelectTransportPlan({
4466
+ tableName: resolvedTableName,
4467
+ columns,
4468
+ state: executionState,
4469
+ options,
4470
+ buildTypedSelectQuery
4471
+ });
4472
+ if (plan.kind === "query") {
4473
+ return executeExperimentalRead(
4474
+ experimental,
4475
+ () => executeWithQueryTrace(
3761
4476
  tracer,
3762
4477
  {
3763
4478
  operation: "select",
3764
4479
  endpoint: "/gateway/query",
3765
4480
  table: resolvedTableName,
3766
- sql: query,
3767
- payload: payload2,
4481
+ sql: plan.query,
4482
+ payload: plan.payload,
3768
4483
  options
3769
4484
  },
3770
4485
  async () => {
3771
- const queryResponse = await client.queryGateway(payload2, options);
4486
+ const queryResponse = await client.queryGateway(plan.payload, options);
3772
4487
  return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
3773
4488
  },
3774
4489
  callsite
3775
- );
3776
- }
4490
+ )
4491
+ );
3777
4492
  }
3778
- const payload = {
3779
- table_name: resolvedTableName,
3780
- columns,
3781
- conditions,
3782
- limit: executionState.limit,
3783
- offset: executionState.offset,
3784
- current_page: executionState.currentPage,
3785
- page_size: executionState.pageSize,
3786
- total_pages: executionState.totalPages,
3787
- sort_by: executionState.order,
3788
- strip_nulls: options?.stripNulls ?? true,
3789
- count: options?.count,
3790
- head: options?.head
3791
- };
3792
4493
  const sql = buildDebugSelectQuery({
3793
4494
  tableName: resolvedTableName,
3794
- columns,
3795
- conditions,
3796
- limit: executionState.limit,
3797
- offset: executionState.offset,
3798
- currentPage: executionState.currentPage,
3799
- pageSize: executionState.pageSize,
3800
- order: executionState.order
4495
+ ...plan.debug
3801
4496
  });
3802
- return executeWithQueryTrace(
3803
- tracer,
3804
- {
3805
- operation: "select",
3806
- endpoint: "/gateway/fetch",
3807
- table: resolvedTableName,
3808
- sql,
3809
- payload,
3810
- options
3811
- },
3812
- async () => {
3813
- const response = await client.fetchGateway(payload, options);
3814
- return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3815
- },
3816
- callsite
4497
+ return executeExperimentalRead(
4498
+ experimental,
4499
+ () => executeWithQueryTrace(
4500
+ tracer,
4501
+ {
4502
+ operation: "select",
4503
+ endpoint: "/gateway/fetch",
4504
+ table: resolvedTableName,
4505
+ sql,
4506
+ payload: plan.payload,
4507
+ options
4508
+ },
4509
+ async () => {
4510
+ const response = await client.fetchGateway(plan.payload, options);
4511
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4512
+ },
4513
+ callsite
4514
+ )
3817
4515
  );
3818
4516
  };
3819
4517
  const createSelectChain = (columns, options, initialCallsite) => {
@@ -3883,14 +4581,14 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
3883
4581
  if (options.limit !== void 0) {
3884
4582
  executionState.limit = options.limit;
3885
4583
  }
3886
- if (experimental?.findManyAst && canUseFindManyAstTransport(baseState)) {
4584
+ if (experimental?.findManyAst && canUseFindManyAstTransport(baseState) && !selectShapeUsesRelationSchema(options.select) && !findManyAstWhereRequiresLegacyTransport(options.where)) {
3887
4585
  const resolvedTableName = resolveTableNameForCall(tableName, void 0);
3888
4586
  const payload = {
3889
4587
  table_name: resolvedTableName,
3890
4588
  select: options.select
3891
4589
  };
3892
4590
  if (options.where !== void 0) {
3893
- payload.where = options.where;
4591
+ payload.where = normalizeFindManyAstWhere(options.where);
3894
4592
  }
3895
4593
  const astOrder = toFindManyAstOrder(executionState.order);
3896
4594
  if (astOrder !== void 0) {
@@ -3906,22 +4604,25 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
3906
4604
  limit: executionState.limit,
3907
4605
  order: executionState.order
3908
4606
  });
3909
- return executeWithQueryTrace(
3910
- tracer,
3911
- {
3912
- operation: "select",
3913
- endpoint: "/gateway/fetch",
3914
- table: resolvedTableName,
3915
- sql,
3916
- payload
3917
- },
3918
- async () => {
3919
- const response = await client.fetchGateway(
4607
+ return executeExperimentalRead(
4608
+ experimental,
4609
+ () => executeWithQueryTrace(
4610
+ tracer,
4611
+ {
4612
+ operation: "select",
4613
+ endpoint: "/gateway/fetch",
4614
+ table: resolvedTableName,
4615
+ sql,
3920
4616
  payload
3921
- );
3922
- return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
3923
- },
3924
- callsite
4617
+ },
4618
+ async () => {
4619
+ const response = await client.fetchGateway(
4620
+ payload
4621
+ );
4622
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
4623
+ },
4624
+ callsite
4625
+ )
3925
4626
  );
3926
4627
  }
3927
4628
  return runSelect(
@@ -4169,7 +4870,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
4169
4870
  });
4170
4871
  return builder;
4171
4872
  }
4172
- function createQueryBuilder(client, formatGatewayResult, tracer) {
4873
+ function createQueryBuilder(client, formatGatewayResult, experimental, tracer) {
4173
4874
  return async function query(query, options) {
4174
4875
  const normalizedQuery = query.trim();
4175
4876
  if (!normalizedQuery) {
@@ -4177,35 +4878,50 @@ function createQueryBuilder(client, formatGatewayResult, tracer) {
4177
4878
  }
4178
4879
  const payload = { query: normalizedQuery };
4179
4880
  const callsite = captureTraceCallsite(tracer);
4180
- return executeWithQueryTrace(
4181
- tracer,
4182
- {
4183
- operation: "query",
4184
- endpoint: "/gateway/query",
4185
- sql: normalizedQuery,
4186
- payload,
4187
- options
4188
- },
4189
- async () => {
4190
- const response = await client.queryGateway(payload, options);
4191
- return formatGatewayResult(response, { operation: "query" });
4192
- },
4193
- callsite
4881
+ return executeExperimentalRead(
4882
+ experimental,
4883
+ () => executeWithQueryTrace(
4884
+ tracer,
4885
+ {
4886
+ operation: "query",
4887
+ endpoint: "/gateway/query",
4888
+ sql: normalizedQuery,
4889
+ payload,
4890
+ options
4891
+ },
4892
+ async () => {
4893
+ const response = await client.queryGateway(payload, options);
4894
+ return formatGatewayResult(response, { operation: "query" });
4895
+ },
4896
+ callsite
4897
+ )
4194
4898
  );
4195
4899
  };
4196
4900
  }
4197
4901
  function createClientFromConfig(config) {
4902
+ const gatewayHeaders = {
4903
+ ...config.headers ?? {}
4904
+ };
4905
+ if (config.auth?.bearerToken && gatewayHeaders["X-Athena-Auth-Bearer-Token"] === void 0 && gatewayHeaders["x-athena-auth-bearer-token"] === void 0) {
4906
+ gatewayHeaders["X-Athena-Auth-Bearer-Token"] = config.auth.bearerToken;
4907
+ }
4198
4908
  const gateway = createAthenaGatewayClient({
4199
4909
  baseUrl: config.baseUrl,
4200
4910
  apiKey: config.apiKey,
4201
4911
  client: config.client,
4202
4912
  backend: config.backend,
4203
- headers: config.headers
4913
+ headers: gatewayHeaders
4204
4914
  });
4205
4915
  const formatGatewayResult = createResultFormatter(config.experimental);
4206
4916
  const queryTracer = createQueryTracer(config.experimental);
4207
4917
  const auth = createAuthClient(config.auth);
4208
- const from = (table) => createTableBuilder(table, gateway, formatGatewayResult, queryTracer, config.experimental);
4918
+ const from = (table, options) => createTableBuilder(
4919
+ resolveTableNameForCall(table, options?.schema),
4920
+ gateway,
4921
+ formatGatewayResult,
4922
+ queryTracer,
4923
+ config.experimental
4924
+ );
4209
4925
  const rpc = (fn, args, options) => {
4210
4926
  const normalizedFn = fn.trim();
4211
4927
  if (!normalizedFn) {
@@ -4221,13 +4937,14 @@ function createClientFromConfig(config) {
4221
4937
  captureTraceCallsite(queryTracer)
4222
4938
  );
4223
4939
  };
4224
- const query = createQueryBuilder(gateway, formatGatewayResult, queryTracer);
4940
+ const query = createQueryBuilder(gateway, formatGatewayResult, config.experimental, queryTracer);
4225
4941
  const db = createDbModule({ from, rpc, query });
4226
4942
  return {
4227
4943
  from,
4228
4944
  db,
4229
4945
  rpc,
4230
4946
  query,
4947
+ verifyConnection: gateway.verifyConnection,
4231
4948
  auth: auth.auth
4232
4949
  };
4233
4950
  }
@@ -4270,7 +4987,6 @@ var AthenaClientBuilderImpl = class {
4270
4987
  defaultHeaders;
4271
4988
  authConfig;
4272
4989
  experimentalOptions;
4273
- isHealthTrackingEnabled = false;
4274
4990
  url(url) {
4275
4991
  this.baseUrl = url;
4276
4992
  return this;
@@ -4320,10 +5036,6 @@ var AthenaClientBuilderImpl = class {
4320
5036
  }
4321
5037
  return this;
4322
5038
  }
4323
- healthTracking(enabled) {
4324
- this.isHealthTrackingEnabled = enabled;
4325
- return this;
4326
- }
4327
5039
  build() {
4328
5040
  if (!this.baseUrl || !this.apiKey) {
4329
5041
  throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
@@ -4334,7 +5046,6 @@ var AthenaClientBuilderImpl = class {
4334
5046
  client: this.clientName,
4335
5047
  backend: this.backendConfig,
4336
5048
  headers: this.defaultHeaders,
4337
- healthTracking: this.isHealthTrackingEnabled,
4338
5049
  auth: this.authConfig,
4339
5050
  experimental: this.experimentalOptions
4340
5051
  });
@@ -4471,8 +5182,8 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
4471
5182
  });
4472
5183
  this.db = this.baseClient.db;
4473
5184
  }
4474
- from(table) {
4475
- return this.baseClient.from(table);
5185
+ from(table, options) {
5186
+ return this.baseClient.from(table, options);
4476
5187
  }
4477
5188
  rpc(fn, args, options) {
4478
5189
  return this.baseClient.rpc(fn, args, options);
@@ -4480,6 +5191,9 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
4480
5191
  query(query, options) {
4481
5192
  return this.baseClient.query(query, options);
4482
5193
  }
5194
+ verifyConnection(options) {
5195
+ return this.baseClient.verifyConnection(options);
5196
+ }
4483
5197
  withTenantContext(context) {
4484
5198
  return new _TypedAthenaClientImpl({
4485
5199
  registry: this.registry,
@@ -4951,7 +5665,7 @@ function resolveNullishValue(mode) {
4951
5665
  if (mode === "null") return null;
4952
5666
  return "";
4953
5667
  }
4954
- function isRecord7(value) {
5668
+ function isRecord8(value) {
4955
5669
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4956
5670
  }
4957
5671
  function isNullableColumn(model, key) {
@@ -4960,7 +5674,7 @@ function isNullableColumn(model, key) {
4960
5674
  }
4961
5675
  function toModelFormDefaults(model, values, options) {
4962
5676
  const source = values;
4963
- if (!isRecord7(source)) {
5677
+ if (!isRecord8(source)) {
4964
5678
  return {};
4965
5679
  }
4966
5680
  const mode = options?.nullishMode ?? "empty-string";
@@ -6177,6 +6891,7 @@ exports.isAthenaGatewayError = isAthenaGatewayError;
6177
6891
  exports.isOk = isOk;
6178
6892
  exports.loadGeneratorConfig = loadGeneratorConfig;
6179
6893
  exports.normalizeAthenaError = normalizeAthenaError;
6894
+ exports.normalizeAthenaGatewayBaseUrl = normalizeAthenaGatewayBaseUrl;
6180
6895
  exports.normalizeGeneratorConfig = normalizeGeneratorConfig;
6181
6896
  exports.normalizeSchemaSelection = normalizeSchemaSelection;
6182
6897
  exports.parseBooleanFlag = parseBooleanFlag2;
@@ -6192,6 +6907,7 @@ exports.toModelPayload = toModelPayload;
6192
6907
  exports.unwrap = unwrap;
6193
6908
  exports.unwrapOne = unwrapOne;
6194
6909
  exports.unwrapRows = unwrapRows;
6910
+ exports.verifyAthenaGatewayUrl = verifyAthenaGatewayUrl;
6195
6911
  exports.withRetry = withRetry;
6196
6912
  //# sourceMappingURL=index.cjs.map
6197
6913
  //# sourceMappingURL=index.cjs.map