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