@xylex-group/athena 1.9.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +86 -68
  2. package/bin/athena-js.js +0 -0
  3. package/dist/browser.cjs +3319 -0
  4. package/dist/browser.cjs.map +1 -0
  5. package/dist/browser.d.cts +25 -0
  6. package/dist/browser.d.ts +25 -0
  7. package/dist/browser.js +3276 -0
  8. package/dist/browser.js.map +1 -0
  9. package/dist/cli/index.cjs +1839 -275
  10. package/dist/cli/index.cjs.map +1 -1
  11. package/dist/cli/index.d.cts +3 -2
  12. package/dist/cli/index.d.ts +3 -2
  13. package/dist/cli/index.js +1840 -276
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/client-BX0NQqOn.d.ts +435 -0
  16. package/dist/client-dpAp-NZK.d.cts +435 -0
  17. package/dist/cookies.cjs +890 -0
  18. package/dist/cookies.cjs.map +1 -0
  19. package/dist/cookies.d.cts +174 -0
  20. package/dist/cookies.d.ts +174 -0
  21. package/dist/cookies.js +869 -0
  22. package/dist/cookies.js.map +1 -0
  23. package/dist/index.cjs +2724 -1777
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +8 -641
  26. package/dist/index.d.ts +8 -641
  27. package/dist/index.js +2725 -1779
  28. package/dist/index.js.map +1 -1
  29. package/dist/model-form-2hqmoOUX.d.ts +1284 -0
  30. package/dist/model-form-Cy-zaO0u.d.cts +1284 -0
  31. package/dist/pipeline-BOPszLsL.d.ts +8 -0
  32. package/dist/pipeline-E3FDbs4W.d.cts +8 -0
  33. package/dist/react.cjs +93 -0
  34. package/dist/react.cjs.map +1 -1
  35. package/dist/react.d.cts +38 -4
  36. package/dist/react.d.ts +38 -4
  37. package/dist/react.js +93 -1
  38. package/dist/react.js.map +1 -1
  39. package/dist/{types-BnzoaNRC.d.cts → types-BaBzjwXr.d.cts} +1 -1
  40. package/dist/{types-BnzoaNRC.d.ts → types-BaBzjwXr.d.ts} +1 -1
  41. package/dist/{pipeline-CQgV-Yfo.d.ts → types-CeBPrnGj.d.ts} +2 -7
  42. package/dist/{pipeline-C-cN0ACi.d.cts → types-CpqL-pZx.d.cts} +2 -7
  43. package/package.json +36 -17
  44. package/dist/model-form-Bm_kqCn2.d.ts +0 -92
  45. package/dist/model-form-DkS48fsh.d.cts +0 -92
package/dist/index.cjs CHANGED
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- var pg = require('pg');
4
3
  var fs = require('fs');
5
4
  var path = require('path');
6
5
  var url = require('url');
@@ -503,1264 +502,2411 @@ function identifier(...segments) {
503
502
  return new SqlIdentifierPath(expandedSegments);
504
503
  }
505
504
 
506
- // src/client.ts
507
- var DEFAULT_COLUMNS = "*";
508
- var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
509
- var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
510
- function formatResult(response) {
511
- const result = {
512
- data: response.data ?? null,
513
- error: response.error ?? null,
514
- errorDetails: response.errorDetails ?? null,
515
- status: response.status,
516
- raw: response.raw
517
- };
518
- if (response.count !== void 0) {
519
- result.count = response.count;
520
- }
521
- return result;
505
+ // src/auth/client.ts
506
+ var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
507
+ var FALLBACK_SDK_VERSION2 = "1.0.0";
508
+ var SDK_NAME2 = "xylex-group/athena-auth";
509
+ var SDK_VERSION2 = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION2;
510
+ var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
511
+ function normalizeBaseUrl(baseUrl) {
512
+ return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
522
513
  }
523
- function toSingleResult(response) {
524
- const payload = response.data;
525
- const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
526
- return {
527
- ...response,
528
- data: singleData
529
- };
514
+ function isRecord2(value) {
515
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
530
516
  }
531
- function mergeOptions(...options) {
532
- return options.reduce((acc, next) => {
533
- if (!next) return acc;
534
- return { ...acc, ...next };
535
- }, void 0);
517
+ function normalizeHeaderValue2(value) {
518
+ return value ? value : void 0;
536
519
  }
537
- function asAthenaJsonObject(value) {
538
- return value;
520
+ function parseResponseBody2(rawText, contentType) {
521
+ if (!rawText) {
522
+ return { parsed: null, parseFailed: false };
523
+ }
524
+ const contentTypeSuggestsJson = contentType?.toLowerCase().includes("application/json") ?? false;
525
+ const looksJson = contentTypeSuggestsJson || rawText.startsWith("{") || rawText.startsWith("[");
526
+ if (!looksJson) {
527
+ return { parsed: rawText, parseFailed: false };
528
+ }
529
+ try {
530
+ return { parsed: JSON.parse(rawText), parseFailed: false };
531
+ } catch {
532
+ return { parsed: rawText, parseFailed: true };
533
+ }
539
534
  }
540
- function asAthenaJsonObjectArray(values) {
541
- return values;
535
+ function resolveRequestId2(headers) {
536
+ return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
542
537
  }
543
- function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
544
- let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
545
- let selectedOptions;
546
- let promise = null;
547
- const run = (columns, options) => {
548
- const payloadColumns = columns ?? selectedColumns;
549
- const payloadOptions = options ?? selectedOptions;
550
- if (!promise) {
551
- promise = executor(payloadColumns, payloadOptions);
538
+ function resolveErrorMessage2(payload, fallback) {
539
+ if (isRecord2(payload)) {
540
+ const messageCandidates = [payload.error, payload.message, payload.details];
541
+ for (const candidate of messageCandidates) {
542
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
543
+ return candidate.trim();
544
+ }
552
545
  }
553
- return promise;
546
+ }
547
+ if (typeof payload === "string" && payload.trim().length > 0) {
548
+ return payload.trim();
549
+ }
550
+ return fallback;
551
+ }
552
+ function toErrorDetails(input) {
553
+ return {
554
+ code: input.code,
555
+ message: input.message,
556
+ status: input.status,
557
+ endpoint: input.endpoint,
558
+ method: input.method,
559
+ requestId: input.requestId,
560
+ hint: input.hint,
561
+ cause: input.cause
554
562
  };
555
- const mutationQuery = {
556
- select(columns = selectedColumns, options) {
557
- selectedColumns = columns;
558
- selectedOptions = options ?? selectedOptions;
559
- return run(columns, options);
560
- },
561
- returning(columns = selectedColumns, options) {
562
- return mutationQuery.select(columns, options);
563
- },
564
- single(columns = selectedColumns, options) {
565
- selectedColumns = columns;
566
- selectedOptions = options ?? selectedOptions;
567
- return run(columns, options).then(toSingleResult);
568
- },
569
- maybeSingle(columns = selectedColumns, options) {
570
- return mutationQuery.single(columns, options);
571
- },
572
- then(onfulfilled, onrejected) {
573
- return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
574
- },
575
- catch(onrejected) {
576
- return run(selectedColumns, selectedOptions).catch(onrejected);
577
- },
578
- finally(onfinally) {
579
- return run(selectedColumns, selectedOptions).finally(onfinally);
563
+ }
564
+ function mergeCallOptions(base, override) {
565
+ if (!base && !override) return void 0;
566
+ return {
567
+ ...base,
568
+ ...override,
569
+ headers: {
570
+ ...base?.headers ?? {},
571
+ ...override?.headers ?? {}
580
572
  }
581
573
  };
582
- return mutationQuery;
583
- }
584
- function getResourceId(state) {
585
- const candidate = state.conditions.find(
586
- (condition) => condition.operator === "eq" && (condition.column === "resource_id" || condition.column === "id")
587
- );
588
- return candidate?.value?.toString();
589
574
  }
590
- function stringifyFilterValue(value) {
591
- if (Array.isArray(value)) {
592
- return value.join(",");
575
+ function extractFetchOptions(input) {
576
+ if (!input) {
577
+ return {
578
+ payload: void 0,
579
+ fetchOptions: void 0
580
+ };
593
581
  }
594
- return String(value);
595
- }
596
- function isUuidString(value) {
597
- return UUID_PATTERN.test(value.trim());
598
- }
599
- function isUuidIdentifierColumn(column) {
600
- return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
601
- }
602
- function shouldUseUuidTextComparison(column, value) {
603
- return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
582
+ const { fetchOptions, ...rest } = input;
583
+ const hasPayloadKeys = Object.keys(rest).length > 0;
584
+ return {
585
+ payload: hasPayloadKeys ? rest : void 0,
586
+ fetchOptions
587
+ };
604
588
  }
605
- function normalizeCast(cast) {
606
- const normalized = cast.trim().toLowerCase();
607
- if (!SAFE_CAST_PATTERN.test(normalized)) {
608
- throw new Error(`Invalid cast type "${cast}"`);
589
+ function buildHeaders2(config, options) {
590
+ const headers = {
591
+ "Content-Type": "application/json",
592
+ "X-Athena-Sdk": SDK_HEADER_VALUE2
593
+ };
594
+ const apiKey = options?.apiKey ?? config.apiKey;
595
+ if (apiKey) {
596
+ headers.apikey = apiKey;
597
+ headers["x-api-key"] = apiKey;
609
598
  }
610
- return normalized;
611
- }
612
- function escapeSqlStringLiteral(value) {
613
- return value.replace(/'/g, "''");
614
- }
615
- function toSqlLiteral(value) {
616
- if (value === null) return "NULL";
617
- if (typeof value === "number") return Number.isFinite(value) ? String(value) : "NULL";
618
- if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
619
- return `'${escapeSqlStringLiteral(value)}'`;
620
- }
621
- function withCast(expression, cast) {
622
- if (!cast) return expression;
623
- return `${expression}::${normalizeCast(cast)}`;
599
+ const bearerToken = options?.bearerToken ?? config.bearerToken;
600
+ if (bearerToken) {
601
+ headers.Authorization = `Bearer ${bearerToken}`;
602
+ }
603
+ const mergedExtraHeaders = {
604
+ ...config.headers ?? {},
605
+ ...options?.headers ?? {}
606
+ };
607
+ Object.entries(mergedExtraHeaders).forEach(([key, value]) => {
608
+ const normalized = normalizeHeaderValue2(value);
609
+ if (normalized) {
610
+ headers[key] = normalized;
611
+ }
612
+ });
613
+ return headers;
624
614
  }
625
- function buildSelectColumnsClause(columns) {
626
- if (Array.isArray(columns)) {
627
- return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
615
+ function appendQueryParam(searchParams, key, value) {
616
+ if (value === void 0 || value === null) return;
617
+ if (Array.isArray(value)) {
618
+ value.forEach((item) => {
619
+ searchParams.append(key, String(item));
620
+ });
621
+ return;
628
622
  }
629
- return quoteSelectColumnsExpression(columns);
623
+ searchParams.append(key, String(value));
630
624
  }
631
- function resolveTableNameForCall(tableName, schema) {
632
- if (!schema) return tableName;
633
- const normalizedSchema = schema.trim();
634
- if (!normalizedSchema) {
635
- throw new Error("schema option must be a non-empty string");
625
+ function buildRequestUrl(baseUrl, endpoint, query) {
626
+ const url = `${baseUrl}${endpoint}`;
627
+ if (!query || Object.keys(query).length === 0) return url;
628
+ const searchParams = new URLSearchParams();
629
+ Object.entries(query).forEach(([key, value]) => appendQueryParam(searchParams, key, value));
630
+ const queryText = searchParams.toString();
631
+ return queryText ? `${url}?${queryText}` : url;
632
+ }
633
+ function inferDefaultMethod(endpoint) {
634
+ if (endpoint.startsWith("/reset-password/")) {
635
+ return "GET";
636
636
  }
637
- if (tableName.includes(".")) {
638
- if (tableName.startsWith(`${normalizedSchema}.`)) {
639
- return tableName;
640
- }
641
- throw new Error(
642
- `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
643
- );
637
+ switch (endpoint) {
638
+ case "/get-session":
639
+ case "/list-sessions":
640
+ case "/verify-email":
641
+ case "/change-email/verify":
642
+ case "/delete-user/verify":
643
+ case "/email-list":
644
+ case "/email/list":
645
+ case "/delete-user/callback":
646
+ case "/list-accounts":
647
+ case "/passkey/generate-register-options":
648
+ case "/passkey/list-user-passkeys":
649
+ case "/.well-known/webauthn":
650
+ case "/admin/list-users":
651
+ case "/admin/athena-client/list":
652
+ case "/admin/audit-log/list":
653
+ case "/admin/email/get":
654
+ case "/admin/email-failure/list":
655
+ case "/admin/email-failure/get":
656
+ case "/admin/email-template/get":
657
+ case "/admin/email-template/list":
658
+ case "/admin/email/list":
659
+ case "/api-key/get":
660
+ case "/api-key/list":
661
+ case "/organization/get-full-organization":
662
+ case "/organization/list":
663
+ case "/organization/get-invitation":
664
+ case "/organization/list-invitations":
665
+ case "/organization/list-user-invitations":
666
+ case "/organization/list-members":
667
+ case "/organization/get-active-member":
668
+ case "/health":
669
+ case "/ok":
670
+ case "/error":
671
+ return "GET";
672
+ default:
673
+ return "POST";
644
674
  }
645
- return `${normalizedSchema}.${tableName}`;
646
675
  }
647
- function conditionToSqlClause(condition) {
648
- if (!condition.column) return null;
649
- const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
650
- const value = condition.value;
651
- const sqlOperator = {
652
- eq: "=",
653
- neq: "!=",
654
- gt: ">",
655
- gte: ">=",
656
- lt: "<",
657
- lte: "<=",
658
- like: "LIKE",
659
- ilike: "ILIKE"
676
+ async function callAuthEndpoint(config, context, body, query, options) {
677
+ const baseUrl = normalizeBaseUrl(options?.baseUrl ?? config.baseUrl);
678
+ const url = buildRequestUrl(baseUrl, context.endpoint, query);
679
+ const headers = buildHeaders2(config, options);
680
+ const credentials = options?.credentials ?? config.credentials ?? "include";
681
+ const requestInit = {
682
+ method: context.method,
683
+ headers,
684
+ credentials,
685
+ signal: options?.signal
660
686
  };
661
- switch (condition.operator) {
662
- case "eq":
663
- case "neq":
664
- case "gt":
665
- case "gte":
666
- case "lt":
667
- case "lte":
668
- case "like":
669
- case "ilike": {
670
- if (Array.isArray(value) || value === void 0) return null;
671
- const rhs = withCast(toSqlLiteral(value), condition.value_cast);
672
- return `${column} ${sqlOperator[condition.operator]} ${rhs}`;
673
- }
674
- case "is": {
675
- if (value === null) return `${column} IS NULL`;
676
- if (value === true) return `${column} IS TRUE`;
677
- if (value === false) return `${column} IS FALSE`;
678
- return null;
687
+ if (context.method !== "GET") {
688
+ requestInit.body = JSON.stringify(body ?? {});
689
+ }
690
+ const fetcher = config.fetch ?? globalThis.fetch;
691
+ if (!fetcher) {
692
+ const details = toErrorDetails({
693
+ code: "UNKNOWN_ERROR",
694
+ message: "No fetch implementation available for auth client",
695
+ status: 0,
696
+ endpoint: context.endpoint,
697
+ method: context.method,
698
+ hint: "Use Node 18+ or provide `fetch` via createClient(..., { auth: { fetch } }) or createAuthClient({ fetch })"
699
+ });
700
+ return {
701
+ ok: false,
702
+ status: 0,
703
+ data: null,
704
+ error: details.message,
705
+ errorDetails: details,
706
+ raw: null
707
+ };
708
+ }
709
+ try {
710
+ const response = await fetcher(url, requestInit);
711
+ const rawText = await response.text();
712
+ const requestId = resolveRequestId2(response.headers);
713
+ const parsedBody = parseResponseBody2(rawText ?? "", response.headers.get("content-type"));
714
+ if (parsedBody.parseFailed) {
715
+ const details = toErrorDetails({
716
+ code: "INVALID_JSON",
717
+ message: "Auth server returned malformed JSON",
718
+ status: response.status,
719
+ endpoint: context.endpoint,
720
+ method: context.method,
721
+ requestId,
722
+ hint: "Verify the auth endpoint response body is valid JSON.",
723
+ cause: rawText.slice(0, 300)
724
+ });
725
+ return {
726
+ ok: false,
727
+ status: response.status,
728
+ data: null,
729
+ error: details.message,
730
+ errorDetails: details,
731
+ raw: parsedBody.parsed
732
+ };
679
733
  }
680
- case "in": {
681
- if (!Array.isArray(value)) return null;
682
- if (value.length === 0) return "FALSE";
683
- const values = value.map((item) => withCast(toSqlLiteral(item), condition.value_cast));
684
- return `${column} IN (${values.join(", ")})`;
734
+ const parsed = parsedBody.parsed;
735
+ if (!response.ok) {
736
+ const details = toErrorDetails({
737
+ code: "HTTP_ERROR",
738
+ message: resolveErrorMessage2(
739
+ parsed,
740
+ `Auth endpoint ${context.method} ${context.endpoint} failed with status ${response.status}`
741
+ ),
742
+ status: response.status,
743
+ endpoint: context.endpoint,
744
+ method: context.method,
745
+ requestId
746
+ });
747
+ return {
748
+ ok: false,
749
+ status: response.status,
750
+ data: null,
751
+ error: details.message,
752
+ errorDetails: details,
753
+ raw: parsed
754
+ };
685
755
  }
686
- default:
687
- return null;
756
+ return {
757
+ ok: true,
758
+ status: response.status,
759
+ data: parsed ?? null,
760
+ error: null,
761
+ errorDetails: null,
762
+ raw: parsed
763
+ };
764
+ } catch (callError) {
765
+ const message = callError instanceof Error ? callError.message : String(callError);
766
+ const details = toErrorDetails({
767
+ code: "NETWORK_ERROR",
768
+ message: `Network error while calling ${context.method} ${context.endpoint}: ${message}`,
769
+ status: 0,
770
+ endpoint: context.endpoint,
771
+ method: context.method,
772
+ cause: message,
773
+ hint: "Check auth server URL, DNS, and network reachability."
774
+ });
775
+ return {
776
+ ok: false,
777
+ status: 0,
778
+ data: null,
779
+ error: details.message,
780
+ errorDetails: details,
781
+ raw: null
782
+ };
688
783
  }
689
784
  }
690
- function buildTypedSelectQuery(input) {
691
- const whereClauses = [];
692
- for (const condition of input.conditions) {
693
- const clause = conditionToSqlClause(condition);
694
- if (!clause) return null;
695
- whereClauses.push(clause);
696
- }
697
- let limit = input.limit;
698
- let offset = input.offset;
699
- if (limit === void 0 && input.pageSize !== void 0) {
700
- limit = input.pageSize;
701
- }
702
- if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
703
- offset = (input.currentPage - 1) * input.pageSize;
704
- }
705
- const sqlParts = [
706
- `SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
707
- ];
708
- if (whereClauses.length > 0) {
709
- sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
710
- }
711
- if (input.order?.field) {
712
- const direction = input.order.direction === "descending" ? "DESC" : "ASC";
713
- sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(input.order.field)} ${direction}`);
714
- }
715
- if (limit !== void 0) {
716
- sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
717
- }
718
- if (offset !== void 0) {
719
- sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
720
- }
721
- return `${sqlParts.join(" ")};`;
785
+ function executePostWithCompatibleInput(config, context, input, options) {
786
+ const { payload, fetchOptions } = extractFetchOptions(input);
787
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
788
+ return callAuthEndpoint(config, context, payload ?? {}, void 0, mergedOptions);
722
789
  }
723
- function createFilterMethods(state, addCondition, self) {
724
- return {
725
- eq(column, value) {
726
- const columnName = String(column);
727
- if (shouldUseUuidTextComparison(columnName, value)) {
728
- addCondition("eq", columnName, value, { columnCast: "text" });
729
- } else {
730
- addCondition("eq", columnName, value);
790
+ function executePostWithOptionalInput(config, context, input, options) {
791
+ const { fetchOptions } = extractFetchOptions(input);
792
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
793
+ return callAuthEndpoint(config, context, {}, void 0, mergedOptions);
794
+ }
795
+ function executeGetWithCompatibleInput(config, context, input, options) {
796
+ const { fetchOptions } = extractFetchOptions(input);
797
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
798
+ return callAuthEndpoint(config, context, void 0, void 0, mergedOptions);
799
+ }
800
+ function executeGetWithQueryCompatibleInput(config, context, input, options) {
801
+ const { payload, fetchOptions } = extractFetchOptions(input);
802
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
803
+ const query = payload?.query;
804
+ return callAuthEndpoint(
805
+ config,
806
+ context,
807
+ void 0,
808
+ query,
809
+ mergedOptions
810
+ );
811
+ }
812
+ function createAuthClient(config = {}) {
813
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
814
+ const resolvedConfig = {
815
+ ...config,
816
+ baseUrl: normalizedBaseUrl
817
+ };
818
+ const request = (input, options) => {
819
+ const method = input.method ?? (input.body !== void 0 ? "POST" : inferDefaultMethod(input.endpoint));
820
+ const mergedOptions = mergeCallOptions(input.fetchOptions, options);
821
+ return callAuthEndpoint(
822
+ resolvedConfig,
823
+ { endpoint: input.endpoint, method },
824
+ input.body,
825
+ input.query,
826
+ mergedOptions
827
+ );
828
+ };
829
+ const postGeneric = (endpoint, input, options) => {
830
+ const { payload, fetchOptions } = extractFetchOptions(input);
831
+ return request(
832
+ {
833
+ endpoint,
834
+ method: "POST",
835
+ body: payload ?? {},
836
+ fetchOptions
837
+ },
838
+ options
839
+ );
840
+ };
841
+ const getGeneric = (endpoint, input, options) => {
842
+ const { fetchOptions } = extractFetchOptions(input);
843
+ return request(
844
+ {
845
+ endpoint,
846
+ method: "GET",
847
+ fetchOptions
848
+ },
849
+ options
850
+ );
851
+ };
852
+ const getWithQuery = (endpoint, input, options) => {
853
+ const { payload, fetchOptions } = extractFetchOptions(input);
854
+ const query = payload?.query;
855
+ return request(
856
+ {
857
+ endpoint,
858
+ method: "GET",
859
+ query,
860
+ fetchOptions
861
+ },
862
+ options
863
+ );
864
+ };
865
+ const listUserEmailsWithFallback = async (input, options) => {
866
+ const primary = await getWithQuery(
867
+ "/email/list",
868
+ input,
869
+ options
870
+ );
871
+ if (primary.ok || primary.status !== 404 || primary.errorDetails?.code !== "HTTP_ERROR") {
872
+ return primary;
873
+ }
874
+ return getWithQuery(
875
+ "/email-list",
876
+ input,
877
+ options
878
+ );
879
+ };
880
+ const healthWithFallback = async (input, options) => {
881
+ const primary = await getGeneric("/health", input, options);
882
+ if (primary.ok || primary.status !== 404 || primary.errorDetails?.code !== "HTTP_ERROR") {
883
+ return primary;
884
+ }
885
+ const fallback = await getGeneric("/ok", input, options);
886
+ if (!fallback.ok) {
887
+ return {
888
+ ...fallback,
889
+ data: null
890
+ };
891
+ }
892
+ const fallbackStatus = isRecord2(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
893
+ return {
894
+ ...fallback,
895
+ data: {
896
+ status: fallbackStatus
731
897
  }
732
- return self;
733
- },
734
- eqCast(column, value, cast) {
735
- addCondition("eq", String(column), value, { valueCast: cast });
736
- return self;
737
- },
738
- eqUuid(column, value) {
739
- addCondition("eq", String(column), value, { valueCast: "uuid" });
740
- return self;
741
- },
742
- match(filters) {
743
- Object.entries(filters).forEach(([column, value]) => {
744
- if (value === void 0) {
745
- return;
746
- }
747
- if (shouldUseUuidTextComparison(column, value)) {
748
- addCondition("eq", column, value, { columnCast: "text" });
749
- } else {
750
- addCondition("eq", column, value);
751
- }
752
- });
753
- return self;
898
+ };
899
+ };
900
+ const signOut = (input, options) => executePostWithOptionalInput(
901
+ resolvedConfig,
902
+ { endpoint: "/sign-out", method: "POST" },
903
+ input,
904
+ options
905
+ );
906
+ const revokeSessions = (input, options) => executePostWithOptionalInput(
907
+ resolvedConfig,
908
+ { endpoint: "/revoke-sessions", method: "POST" },
909
+ input,
910
+ options
911
+ );
912
+ const revokeOtherSessions = (input, options) => executePostWithOptionalInput(
913
+ resolvedConfig,
914
+ { endpoint: "/revoke-other-sessions", method: "POST" },
915
+ input,
916
+ options
917
+ );
918
+ const revokeSession = (input, options) => executePostWithCompatibleInput(
919
+ resolvedConfig,
920
+ { endpoint: "/revoke-session", method: "POST" },
921
+ input,
922
+ options
923
+ );
924
+ const deleteUser = (input, options) => {
925
+ const { payload, fetchOptions } = extractFetchOptions(input);
926
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
927
+ return callAuthEndpoint(
928
+ resolvedConfig,
929
+ { endpoint: "/delete-user", method: "POST" },
930
+ payload ?? {},
931
+ void 0,
932
+ mergedOptions
933
+ );
934
+ };
935
+ const deleteUserCallback = (input, options) => {
936
+ const { payload, fetchOptions } = extractFetchOptions(input);
937
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
938
+ const query = payload ?? {};
939
+ return callAuthEndpoint(
940
+ resolvedConfig,
941
+ { endpoint: "/delete-user/callback", method: "GET" },
942
+ void 0,
943
+ {
944
+ token: query.token,
945
+ callbackURL: query.callbackURL
946
+ },
947
+ mergedOptions
948
+ );
949
+ };
950
+ const resolveResetPasswordToken = (input, options) => {
951
+ const { payload, fetchOptions } = extractFetchOptions(input);
952
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
953
+ const query = payload;
954
+ const token = query?.token?.trim();
955
+ if (!token) {
956
+ throw new Error("resolveResetPasswordToken requires a non-empty token");
957
+ }
958
+ const endpoint = `/reset-password/${encodeURIComponent(token)}`;
959
+ return callAuthEndpoint(
960
+ resolvedConfig,
961
+ { endpoint, method: "GET" },
962
+ void 0,
963
+ query?.callbackURL ? { callbackURL: query.callbackURL } : void 0,
964
+ mergedOptions
965
+ );
966
+ };
967
+ const organization = {
968
+ create: (input, options) => executePostWithCompatibleInput(
969
+ resolvedConfig,
970
+ { endpoint: "/organization/create", method: "POST" },
971
+ input,
972
+ options
973
+ ),
974
+ update: (input, options) => executePostWithCompatibleInput(
975
+ resolvedConfig,
976
+ { endpoint: "/organization/update", method: "POST" },
977
+ input,
978
+ options
979
+ ),
980
+ delete: (input, options) => executePostWithCompatibleInput(
981
+ resolvedConfig,
982
+ { endpoint: "/organization/delete", method: "POST" },
983
+ input,
984
+ options
985
+ ),
986
+ setActive: (input, options) => executePostWithCompatibleInput(
987
+ resolvedConfig,
988
+ { endpoint: "/organization/set-active", method: "POST" },
989
+ input,
990
+ options
991
+ ),
992
+ list: (input, options) => getGeneric(
993
+ "/organization/list",
994
+ input,
995
+ options
996
+ ),
997
+ getFull: (input, options) => executeGetWithQueryCompatibleInput(
998
+ resolvedConfig,
999
+ { endpoint: "/organization/get-full-organization", method: "GET" },
1000
+ input,
1001
+ options
1002
+ ),
1003
+ checkSlug: (input, options) => executePostWithCompatibleInput(
1004
+ resolvedConfig,
1005
+ { endpoint: "/organization/check-slug", method: "POST" },
1006
+ input,
1007
+ options
1008
+ ),
1009
+ leave: (input, options) => executePostWithCompatibleInput(
1010
+ resolvedConfig,
1011
+ { endpoint: "/organization/leave", method: "POST" },
1012
+ input,
1013
+ options
1014
+ ),
1015
+ listUserInvitations: (input, options) => executeGetWithQueryCompatibleInput(
1016
+ resolvedConfig,
1017
+ { endpoint: "/organization/list-user-invitations", method: "GET" },
1018
+ input,
1019
+ options
1020
+ ),
1021
+ hasPermission: (input, options) => postGeneric(
1022
+ "/organization/has-permission",
1023
+ input,
1024
+ options
1025
+ ),
1026
+ invitation: {
1027
+ cancel: (input, options) => executePostWithCompatibleInput(
1028
+ resolvedConfig,
1029
+ { endpoint: "/organization/cancel-invitation", method: "POST" },
1030
+ input,
1031
+ options
1032
+ ),
1033
+ accept: (input, options) => executePostWithCompatibleInput(
1034
+ resolvedConfig,
1035
+ { endpoint: "/organization/accept-invitation", method: "POST" },
1036
+ input,
1037
+ options
1038
+ ),
1039
+ get: (input, options) => executeGetWithQueryCompatibleInput(
1040
+ resolvedConfig,
1041
+ { endpoint: "/organization/get-invitation", method: "GET" },
1042
+ input,
1043
+ options
1044
+ ),
1045
+ reject: (input, options) => executePostWithCompatibleInput(
1046
+ resolvedConfig,
1047
+ { endpoint: "/organization/reject-invitation", method: "POST" },
1048
+ input,
1049
+ options
1050
+ ),
1051
+ list: (input, options) => executeGetWithQueryCompatibleInput(
1052
+ resolvedConfig,
1053
+ { endpoint: "/organization/list-invitations", method: "GET" },
1054
+ input,
1055
+ options
1056
+ )
754
1057
  },
755
- range(from, to) {
756
- state.offset = from;
757
- state.limit = to - from + 1;
758
- return self;
1058
+ member: {
1059
+ remove: (input, options) => executePostWithCompatibleInput(
1060
+ resolvedConfig,
1061
+ { endpoint: "/organization/remove-member", method: "POST" },
1062
+ input,
1063
+ options
1064
+ ),
1065
+ updateRole: (input, options) => executePostWithCompatibleInput(
1066
+ resolvedConfig,
1067
+ { endpoint: "/organization/update-member-role", method: "POST" },
1068
+ input,
1069
+ options
1070
+ ),
1071
+ invite: (input, options) => executePostWithCompatibleInput(
1072
+ resolvedConfig,
1073
+ { endpoint: "/organization/invite-member", method: "POST" },
1074
+ input,
1075
+ options
1076
+ ),
1077
+ getActive: (input, options) => executeGetWithCompatibleInput(
1078
+ resolvedConfig,
1079
+ { endpoint: "/organization/get-active-member", method: "GET" },
1080
+ input,
1081
+ options
1082
+ ),
1083
+ list: (input, options) => executeGetWithQueryCompatibleInput(
1084
+ resolvedConfig,
1085
+ { endpoint: "/organization/list-members", method: "GET" },
1086
+ input,
1087
+ options
1088
+ )
1089
+ }
1090
+ };
1091
+ const authResetPassword = Object.assign(
1092
+ (input, options) => executePostWithCompatibleInput(
1093
+ resolvedConfig,
1094
+ { endpoint: "/reset-password", method: "POST" },
1095
+ input,
1096
+ options
1097
+ ),
1098
+ {
1099
+ token: resolveResetPasswordToken
1100
+ }
1101
+ );
1102
+ const sessionRevokeBinding = (input, options) => {
1103
+ if (Array.isArray(input)) {
1104
+ if (input.length === 0) {
1105
+ throw new Error("session.revoke requires at least one session token");
1106
+ }
1107
+ if (input.length === 1) {
1108
+ return revokeSession(input[0], options);
1109
+ }
1110
+ return revokeSessions(void 0, options);
1111
+ }
1112
+ const parsed = input;
1113
+ const tokens = Array.isArray(parsed.tokens) ? parsed.tokens.filter((token2) => token2.trim().length > 0) : void 0;
1114
+ if (tokens && tokens.length > 1) {
1115
+ return revokeSessions(
1116
+ parsed.fetchOptions ? { fetchOptions: parsed.fetchOptions } : void 0,
1117
+ options
1118
+ );
1119
+ }
1120
+ if (tokens && tokens.length === 1) {
1121
+ return revokeSession(
1122
+ { token: tokens[0], fetchOptions: parsed.fetchOptions },
1123
+ options
1124
+ );
1125
+ }
1126
+ const token = parsed.token?.trim();
1127
+ if (!token) {
1128
+ throw new Error("session.revoke requires a non-empty token or a non-empty token list");
1129
+ }
1130
+ return revokeSession(
1131
+ {
1132
+ token,
1133
+ fetchOptions: parsed.fetchOptions
1134
+ },
1135
+ options
1136
+ );
1137
+ };
1138
+ const adminUserSessionRevokeBinding = (input, options) => {
1139
+ const requireUserId = (userId) => {
1140
+ const trimmed = String(userId ?? "").trim();
1141
+ if (!trimmed) {
1142
+ throw new Error("admin.user.session.revoke requires a non-empty userId");
1143
+ }
1144
+ return trimmed;
1145
+ };
1146
+ const requireSinglePluralUserId = (sessions2) => {
1147
+ const uniqueUserIds = [...new Set(sessions2.map((session) => requireUserId(session.userId)))];
1148
+ if (uniqueUserIds.length !== 1) {
1149
+ throw new Error("admin.user.session.revoke requires the same userId across plural payloads");
1150
+ }
1151
+ return { userId: uniqueUserIds[0] };
1152
+ };
1153
+ if (Array.isArray(input)) {
1154
+ if (input.length === 0) {
1155
+ throw new Error("admin.user.session.revoke requires at least one payload item");
1156
+ }
1157
+ if (input.length === 1) {
1158
+ return postGeneric(
1159
+ "/admin/revoke-user-session",
1160
+ {
1161
+ ...input[0],
1162
+ userId: requireUserId(input[0].userId)
1163
+ },
1164
+ options
1165
+ );
1166
+ }
1167
+ return postGeneric(
1168
+ "/admin/revoke-user-sessions",
1169
+ requireSinglePluralUserId(input),
1170
+ options
1171
+ );
1172
+ }
1173
+ const parsed = input;
1174
+ const sessions = parsed.sessions;
1175
+ if (sessions && sessions.length === 0) {
1176
+ throw new Error("admin.user.session.revoke requires at least one payload item");
1177
+ }
1178
+ if (sessions && sessions.length === 1) {
1179
+ return postGeneric(
1180
+ "/admin/revoke-user-session",
1181
+ {
1182
+ ...sessions[0],
1183
+ userId: requireUserId(sessions[0].userId),
1184
+ fetchOptions: parsed.fetchOptions
1185
+ },
1186
+ options
1187
+ );
1188
+ }
1189
+ if (sessions && sessions.length > 1) {
1190
+ return postGeneric(
1191
+ "/admin/revoke-user-sessions",
1192
+ {
1193
+ ...requireSinglePluralUserId(sessions),
1194
+ fetchOptions: parsed.fetchOptions
1195
+ },
1196
+ options
1197
+ );
1198
+ }
1199
+ const normalizedUserId = requireUserId(parsed.userId);
1200
+ if (!parsed.sessionToken) {
1201
+ return postGeneric(
1202
+ "/admin/revoke-user-sessions",
1203
+ {
1204
+ userId: normalizedUserId,
1205
+ fetchOptions: parsed.fetchOptions
1206
+ },
1207
+ options
1208
+ );
1209
+ }
1210
+ return postGeneric(
1211
+ "/admin/revoke-user-session",
1212
+ {
1213
+ ...parsed,
1214
+ userId: normalizedUserId
1215
+ },
1216
+ options
1217
+ );
1218
+ };
1219
+ const auth = {
1220
+ getSession: (input, options) => getGeneric("/get-session", input, options),
1221
+ signOut,
1222
+ forgetPassword: (input, options) => postGeneric("/forget-password", input, options),
1223
+ resetPassword: authResetPassword,
1224
+ setPassword: (input, options) => postGeneric("/set-password", input, options),
1225
+ verifyEmail: (input, options) => {
1226
+ const queryInput = {
1227
+ query: {
1228
+ token: input.token,
1229
+ callbackURL: input.callbackURL
1230
+ },
1231
+ fetchOptions: input.fetchOptions
1232
+ };
1233
+ return getWithQuery(
1234
+ "/verify-email",
1235
+ queryInput,
1236
+ options
1237
+ );
759
1238
  },
760
- limit(count) {
761
- state.limit = count;
762
- return self;
1239
+ sendVerificationEmail: (input, options) => postGeneric("/send-verification-email", input, options),
1240
+ changeEmail: (input, options) => postGeneric("/change-email", input, options),
1241
+ changeEmailVerify: (input, options) => getWithQuery("/change-email/verify", input, options),
1242
+ deleteUserVerify: (input, options) => getWithQuery("/delete-user/verify", input, options),
1243
+ changePassword: (input, options) => postGeneric("/change-password", input, options),
1244
+ user: {
1245
+ update: (input, options) => postGeneric("/update-user", input, options),
1246
+ delete: (input, options) => postGeneric("/delete-user", input, options),
1247
+ email: {
1248
+ list: listUserEmailsWithFallback
1249
+ }
763
1250
  },
764
- offset(count) {
765
- state.offset = count;
766
- return self;
1251
+ session: {
1252
+ list: (input, options) => getGeneric("/list-sessions", input, options),
1253
+ revoke: sessionRevokeBinding,
1254
+ revokeOther: revokeOtherSessions
767
1255
  },
768
- currentPage(value) {
769
- state.currentPage = value;
770
- return self;
1256
+ social: {
1257
+ link: (input, options) => postGeneric("/link-social", input, options)
771
1258
  },
772
- pageSize(value) {
773
- state.pageSize = value;
774
- return self;
1259
+ account: {
1260
+ list: (input, options) => getGeneric("/list-accounts", input, options),
1261
+ unlink: (input, options) => postGeneric("/unlink-account", input, options)
775
1262
  },
776
- totalPages(value) {
777
- state.totalPages = value;
778
- return self;
1263
+ deleteUser: {
1264
+ callback: deleteUserCallback
779
1265
  },
780
- order(column, options) {
781
- state.order = {
782
- field: String(column),
783
- direction: options?.ascending === false ? "descending" : "ascending"
784
- };
785
- return self;
1266
+ refreshToken: (input, options) => postGeneric("/refresh-token", input, options),
1267
+ getAccessToken: (input, options) => postGeneric("/get-access-token", input, options),
1268
+ health: healthWithFallback,
1269
+ ok: (input, options) => getGeneric("/ok", input, options),
1270
+ error: (input, options) => getGeneric("/error", input, options),
1271
+ twoFactor: {
1272
+ getTotpUri: (input, options) => postGeneric("/two-factor/get-totp-uri", input, options),
1273
+ verifyTotp: (input, options) => postGeneric("/two-factor/verify-totp", input, options),
1274
+ sendOtp: (input, options) => postGeneric("/two-factor/send-otp", input, options),
1275
+ verifyOtp: (input, options) => postGeneric("/two-factor/verify-otp", input, options),
1276
+ verifyBackupCode: (input, options) => postGeneric("/two-factor/verify-backup-code", input, options),
1277
+ generateBackupCodes: (input, options) => executePostWithCompatibleInput(
1278
+ resolvedConfig,
1279
+ { endpoint: "/two-factor/generate-backup-codes", method: "POST" },
1280
+ input,
1281
+ options
1282
+ ),
1283
+ enable: (input, options) => postGeneric("/two-factor/enable", input, options),
1284
+ disable: (input, options) => postGeneric("/two-factor/disable", input, options)
786
1285
  },
787
- gt(column, value) {
788
- addCondition("gt", String(column), value);
789
- return self;
1286
+ passkey: {
1287
+ generateRegisterOptions: (input, options) => getGeneric("/passkey/generate-register-options", input, options),
1288
+ generateAuthenticateOptions: (input, options) => postGeneric("/passkey/generate-authenticate-options", input, options),
1289
+ verifyRegistration: (input, options) => postGeneric("/passkey/verify-registration", input, options),
1290
+ verifyAuthentication: (input, options) => postGeneric("/passkey/verify-authentication", input, options),
1291
+ listUserPasskeys: (input, options) => getGeneric("/passkey/list-user-passkeys", input, options),
1292
+ deletePasskey: (input, options) => postGeneric("/passkey/delete-passkey", input, options),
1293
+ updatePasskey: (input, options) => postGeneric("/passkey/update-passkey", input, options),
1294
+ getRelatedOrigins: (input, options) => getGeneric("/.well-known/webauthn", input, options)
790
1295
  },
791
- gte(column, value) {
792
- addCondition("gte", String(column), value);
793
- return self;
1296
+ admin: {
1297
+ role: {
1298
+ set: (input, options) => postGeneric("/admin/set-role", input, options)
1299
+ },
1300
+ user: {
1301
+ list: (input, options) => getWithQuery("/admin/list-users", input, options),
1302
+ create: (input, options) => postGeneric("/admin/create-user", input, options),
1303
+ unban: (input, options) => postGeneric("/admin/unban-user", input, options),
1304
+ ban: (input, options) => postGeneric("/admin/ban-user", input, options),
1305
+ impersonate: (input, options) => postGeneric("/admin/impersonate-user", input, options),
1306
+ stopImpersonating: (input, options) => postGeneric("/admin/stop-impersonating", input, options),
1307
+ remove: (input, options) => postGeneric("/admin/remove-user", input, options),
1308
+ setPassword: (input, options) => postGeneric("/admin/set-user-password", input, options),
1309
+ session: {
1310
+ list: (input, options) => postGeneric("/admin/list-user-sessions", input, options),
1311
+ revoke: adminUserSessionRevokeBinding
1312
+ }
1313
+ },
1314
+ hasPermission: (input, options) => postGeneric("/admin/has-permission", input, options),
1315
+ apiKey: {
1316
+ create: (input, options) => postGeneric("/admin/api-key/create", input, options)
1317
+ },
1318
+ athenaClient: {
1319
+ create: (input, options) => postGeneric("/admin/athena-client/create", input, options),
1320
+ list: (input, options) => getWithQuery("/admin/athena-client/list", input, options)
1321
+ },
1322
+ auditLog: {
1323
+ list: (input, options) => getWithQuery("/admin/audit-log/list", input, options)
1324
+ },
1325
+ email: {
1326
+ list: (input, options) => getWithQuery("/admin/email/list", input, options),
1327
+ get: (input, options) => getWithQuery("/admin/email/get", input, options),
1328
+ create: (input, options) => postGeneric("/admin/email/create", input, options),
1329
+ update: (input, options) => postGeneric("/admin/email/update", input, options),
1330
+ delete: (input, options) => postGeneric("/admin/email/delete", input, options),
1331
+ failure: {
1332
+ list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
1333
+ get: (input, options) => getWithQuery("/admin/email-failure/get", input, options),
1334
+ create: (input, options) => postGeneric("/admin/email-failure/create", input, options),
1335
+ update: (input, options) => postGeneric("/admin/email-failure/update", input, options),
1336
+ delete: (input, options) => postGeneric("/admin/email-failure/delete", input, options)
1337
+ },
1338
+ template: {
1339
+ list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
1340
+ get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
1341
+ create: (input, options) => postGeneric("/admin/email-template/create", input, options),
1342
+ update: (input, options) => postGeneric("/admin/email-template/update", input, options),
1343
+ delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
1344
+ }
1345
+ },
1346
+ emailTemplate: {
1347
+ get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
1348
+ create: (input, options) => postGeneric("/admin/email-template/create", input, options),
1349
+ delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
1350
+ list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
1351
+ update: (input, options) => postGeneric("/admin/email-template/update", input, options)
1352
+ }
794
1353
  },
795
- lt(column, value) {
796
- addCondition("lt", String(column), value);
797
- return self;
798
- },
799
- lte(column, value) {
800
- addCondition("lte", String(column), value);
801
- return self;
802
- },
803
- neq(column, value) {
804
- addCondition("neq", String(column), value);
805
- return self;
806
- },
807
- like(column, value) {
808
- addCondition("like", String(column), value);
809
- return self;
810
- },
811
- ilike(column, value) {
812
- addCondition("ilike", String(column), value);
813
- return self;
814
- },
815
- is(column, value) {
816
- addCondition("is", String(column), value);
817
- return self;
818
- },
819
- in(column, values) {
820
- addCondition("in", String(column), values);
821
- return self;
1354
+ apiKey: {
1355
+ create: (input, options) => postGeneric("/api-key/create", input, options),
1356
+ get: (input, options) => getWithQuery("/api-key/get", input, options),
1357
+ update: (input, options) => postGeneric("/api-key/update", input, options),
1358
+ delete: (input, options) => postGeneric("/api-key/delete", input, options),
1359
+ list: (input, options) => getWithQuery("/api-key/list", input, options),
1360
+ verify: (input, options) => postGeneric("/api-key/verify", input, options),
1361
+ deleteAllExpired: (input, options) => executePostWithOptionalInput(
1362
+ resolvedConfig,
1363
+ { endpoint: "/api-key/delete-all-expired-api-keys", method: "POST" },
1364
+ input,
1365
+ options
1366
+ )
822
1367
  },
823
- contains(column, values) {
824
- addCondition("contains", String(column), values);
825
- return self;
1368
+ signIn: {
1369
+ email: (input, options) => postGeneric("/sign-in/email", input, options),
1370
+ username: (input, options) => postGeneric("/sign-in/username", input, options),
1371
+ social: (input, options) => postGeneric("/sign-in/social", input, options)
826
1372
  },
827
- containedBy(column, values) {
828
- addCondition("containedBy", String(column), values);
829
- return self;
1373
+ signUp: {
1374
+ email: (input, options) => postGeneric("/sign-up/email", input, options)
830
1375
  },
831
- not(columnOrExpression, operator, value) {
832
- const expression = String(columnOrExpression);
833
- if (operator != null && value !== void 0) {
834
- addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
835
- } else {
836
- addCondition("not", void 0, expression);
1376
+ organization,
1377
+ callback: {
1378
+ provider: (input, options) => {
1379
+ const { payload, fetchOptions } = extractFetchOptions(input);
1380
+ const parsed = payload;
1381
+ const provider = String(parsed?.provider ?? "").trim();
1382
+ if (!provider) {
1383
+ throw new Error("callback.provider requires a non-empty provider value");
1384
+ }
1385
+ const code = String(parsed?.code ?? "").trim();
1386
+ const state = String(parsed?.state ?? "").trim();
1387
+ if (!code || !state) {
1388
+ throw new Error("callback.provider requires non-empty code and state values");
1389
+ }
1390
+ const endpoint = `/callback/${encodeURIComponent(provider)}`;
1391
+ return request({
1392
+ endpoint,
1393
+ method: "GET",
1394
+ query: {
1395
+ code,
1396
+ state
1397
+ },
1398
+ fetchOptions
1399
+ }, options);
837
1400
  }
838
- return self;
839
- },
840
- or(expression) {
841
- addCondition("or", void 0, expression);
842
- return self;
843
1401
  }
844
1402
  };
845
- }
846
- function toRpcSelect(columns) {
847
- if (!columns) return void 0;
848
- return Array.isArray(columns) ? columns.join(",") : columns;
849
- }
850
- function createRpcFilterMethods(filters, self) {
851
- const addFilter = (operator, column, value) => {
852
- filters.push({ column, operator, value });
853
- };
854
1403
  return {
855
- eq(column, value) {
856
- addFilter("eq", column, value);
857
- return self;
858
- },
859
- neq(column, value) {
860
- addFilter("neq", column, value);
861
- return self;
862
- },
863
- gt(column, value) {
864
- addFilter("gt", column, value);
865
- return self;
866
- },
867
- gte(column, value) {
868
- addFilter("gte", column, value);
869
- return self;
870
- },
871
- lt(column, value) {
872
- addFilter("lt", column, value);
873
- return self;
874
- },
875
- lte(column, value) {
876
- addFilter("lte", column, value);
877
- return self;
878
- },
879
- like(column, value) {
880
- addFilter("like", column, value);
881
- return self;
1404
+ baseUrl: normalizedBaseUrl,
1405
+ request,
1406
+ signIn: {
1407
+ email: (input, options) => executePostWithCompatibleInput(
1408
+ resolvedConfig,
1409
+ { endpoint: "/sign-in/email", method: "POST" },
1410
+ input,
1411
+ options
1412
+ ),
1413
+ username: (input, options) => executePostWithCompatibleInput(
1414
+ resolvedConfig,
1415
+ { endpoint: "/sign-in/username", method: "POST" },
1416
+ input,
1417
+ options
1418
+ ),
1419
+ social: (input, options) => executePostWithCompatibleInput(
1420
+ resolvedConfig,
1421
+ { endpoint: "/sign-in/social", method: "POST" },
1422
+ input,
1423
+ options
1424
+ )
882
1425
  },
883
- ilike(column, value) {
884
- addFilter("ilike", column, value);
885
- return self;
1426
+ signUp: {
1427
+ email: (input, options) => executePostWithCompatibleInput(
1428
+ resolvedConfig,
1429
+ { endpoint: "/sign-up/email", method: "POST" },
1430
+ input,
1431
+ options
1432
+ )
886
1433
  },
887
- is(column, value) {
888
- addFilter("is", column, value);
889
- return self;
1434
+ signOut,
1435
+ logout: signOut,
1436
+ getSession: (input, options) => executeGetWithCompatibleInput(
1437
+ resolvedConfig,
1438
+ { endpoint: "/get-session", method: "GET" },
1439
+ input,
1440
+ options
1441
+ ),
1442
+ listSessions: (input, options) => executeGetWithCompatibleInput(
1443
+ resolvedConfig,
1444
+ { endpoint: "/list-sessions", method: "GET" },
1445
+ input,
1446
+ options
1447
+ ),
1448
+ revokeSession,
1449
+ clearSession: revokeSession,
1450
+ revokeSessions,
1451
+ clearSessions: revokeSessions,
1452
+ revokeOtherSessions,
1453
+ clearOtherSessions: revokeOtherSessions,
1454
+ forgetPassword: (input, options) => executePostWithCompatibleInput(
1455
+ resolvedConfig,
1456
+ { endpoint: "/forget-password", method: "POST" },
1457
+ input,
1458
+ options
1459
+ ),
1460
+ resetPassword: (input, options) => executePostWithCompatibleInput(
1461
+ resolvedConfig,
1462
+ { endpoint: "/reset-password", method: "POST" },
1463
+ input,
1464
+ options
1465
+ ),
1466
+ resolveResetPasswordToken,
1467
+ verifyEmail: (input, options) => {
1468
+ const { payload, fetchOptions } = extractFetchOptions(input);
1469
+ const mergedOptions = mergeCallOptions(fetchOptions, options);
1470
+ const query = payload;
1471
+ return callAuthEndpoint(
1472
+ resolvedConfig,
1473
+ { endpoint: "/verify-email", method: "GET" },
1474
+ void 0,
1475
+ query ? {
1476
+ token: query.token,
1477
+ callbackURL: query.callbackURL
1478
+ } : void 0,
1479
+ mergedOptions
1480
+ );
890
1481
  },
891
- in(column, values) {
892
- addFilter("in", column, values);
893
- return self;
894
- }
1482
+ sendVerificationEmail: (input, options) => executePostWithCompatibleInput(
1483
+ resolvedConfig,
1484
+ { endpoint: "/send-verification-email", method: "POST" },
1485
+ input,
1486
+ options
1487
+ ),
1488
+ changeEmail: (input, options) => executePostWithCompatibleInput(
1489
+ resolvedConfig,
1490
+ { endpoint: "/change-email", method: "POST" },
1491
+ input,
1492
+ options
1493
+ ),
1494
+ changePassword: (input, options) => executePostWithCompatibleInput(
1495
+ resolvedConfig,
1496
+ { endpoint: "/change-password", method: "POST" },
1497
+ input,
1498
+ options
1499
+ ),
1500
+ updateUser: (input, options) => executePostWithCompatibleInput(
1501
+ resolvedConfig,
1502
+ { endpoint: "/update-user", method: "POST" },
1503
+ input,
1504
+ options
1505
+ ),
1506
+ deleteUser,
1507
+ deleteUserCallback,
1508
+ linkSocial: (input, options) => executePostWithCompatibleInput(
1509
+ resolvedConfig,
1510
+ { endpoint: "/link-social", method: "POST" },
1511
+ input,
1512
+ options
1513
+ ),
1514
+ listAccounts: (input, options) => executeGetWithCompatibleInput(
1515
+ resolvedConfig,
1516
+ { endpoint: "/list-accounts", method: "GET" },
1517
+ input,
1518
+ options
1519
+ ),
1520
+ unlinkAccount: (input, options) => executePostWithCompatibleInput(
1521
+ resolvedConfig,
1522
+ { endpoint: "/unlink-account", method: "POST" },
1523
+ input,
1524
+ options
1525
+ ),
1526
+ refreshToken: (input, options) => executePostWithCompatibleInput(
1527
+ resolvedConfig,
1528
+ { endpoint: "/refresh-token", method: "POST" },
1529
+ input,
1530
+ options
1531
+ ),
1532
+ getAccessToken: (input, options) => executePostWithCompatibleInput(
1533
+ resolvedConfig,
1534
+ { endpoint: "/get-access-token", method: "POST" },
1535
+ input,
1536
+ options
1537
+ ),
1538
+ organization,
1539
+ auth
895
1540
  };
896
1541
  }
897
- function createRpcBuilder(functionName, args, baseOptions, client) {
898
- const state = {
899
- filters: []
900
- };
901
- let selectedColumns;
902
- let selectedOptions;
903
- let promise = null;
904
- const executeRpc = async (columns, options) => {
905
- const mergedOptions = mergeOptions(baseOptions, options);
906
- const payload = {
907
- function: functionName,
908
- args,
909
- schema: mergedOptions?.schema,
910
- select: toRpcSelect(columns),
911
- filters: state.filters.length ? [...state.filters] : void 0,
912
- count: mergedOptions?.count,
913
- head: mergedOptions?.head,
914
- limit: state.limit,
915
- offset: state.offset,
916
- order: state.order
917
- };
918
- const response = await client.rpcGateway(payload, mergedOptions);
919
- return formatResult(response);
920
- };
921
- const run = (columns, options) => {
922
- const payloadColumns = columns ?? selectedColumns;
923
- const payloadOptions = options ?? selectedOptions;
924
- if (!promise) {
925
- promise = executeRpc(payloadColumns, payloadOptions);
926
- }
927
- return promise;
928
- };
929
- const builder = {};
930
- const filterMethods = createRpcFilterMethods(state.filters, builder);
931
- Object.assign(builder, filterMethods, {
932
- select(columns = selectedColumns, options) {
933
- selectedColumns = columns;
934
- selectedOptions = options ?? selectedOptions;
935
- return run(columns, options);
936
- },
937
- async single(columns, options) {
938
- const result = await run(columns, options);
939
- return toSingleResult(result);
940
- },
941
- maybeSingle(columns, options) {
942
- return builder.single(columns, options);
943
- },
944
- order(column, options) {
945
- state.order = { column, ascending: options?.ascending ?? true };
946
- return builder;
947
- },
948
- limit(count) {
949
- state.limit = count;
950
- return builder;
951
- },
952
- offset(count) {
953
- state.offset = count;
954
- return builder;
955
- },
956
- range(from, to) {
957
- state.offset = from;
958
- state.limit = to - from + 1;
959
- return builder;
960
- },
961
- then(onfulfilled, onrejected) {
962
- return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
963
- },
964
- catch(onrejected) {
965
- return run(selectedColumns, selectedOptions).catch(onrejected);
966
- },
967
- finally(onfinally) {
968
- return run(selectedColumns, selectedOptions).finally(onfinally);
969
- }
970
- });
971
- return builder;
1542
+
1543
+ // src/auxiliaries.ts
1544
+ var AthenaErrorKind = {
1545
+ UniqueViolation: "unique_violation",
1546
+ NotFound: "not_found",
1547
+ Validation: "validation",
1548
+ Auth: "auth",
1549
+ RateLimit: "rate_limit",
1550
+ Transient: "transient",
1551
+ Unknown: "unknown"
1552
+ };
1553
+ var AthenaErrorCode = {
1554
+ UniqueViolation: "UNIQUE_VIOLATION",
1555
+ NotFound: "NOT_FOUND",
1556
+ ValidationFailed: "VALIDATION_FAILED",
1557
+ AuthUnauthorized: "AUTH_UNAUTHORIZED",
1558
+ AuthForbidden: "AUTH_FORBIDDEN",
1559
+ RateLimited: "RATE_LIMITED",
1560
+ NetworkUnavailable: "NETWORK_UNAVAILABLE",
1561
+ TransientFailure: "TRANSIENT_FAILURE",
1562
+ HttpFailure: "HTTP_FAILURE",
1563
+ Unknown: "UNKNOWN"
1564
+ };
1565
+ var AthenaErrorCategory = {
1566
+ Transport: "transport",
1567
+ Client: "client",
1568
+ Server: "server",
1569
+ Database: "database",
1570
+ Unknown: "unknown"
1571
+ };
1572
+ function parseBooleanFlag(rawValue, fallback) {
1573
+ if (!rawValue) return fallback;
1574
+ const normalized = rawValue.trim().toLowerCase();
1575
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
1576
+ return true;
1577
+ }
1578
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
1579
+ return false;
1580
+ }
1581
+ return fallback;
972
1582
  }
973
- function createTableBuilder(tableName, client) {
974
- const state = {
975
- conditions: []
1583
+ var AthenaError = class extends Error {
1584
+ code;
1585
+ kind;
1586
+ category;
1587
+ status;
1588
+ retryable;
1589
+ requestId;
1590
+ context;
1591
+ raw;
1592
+ constructor(input) {
1593
+ super(input.message);
1594
+ this.name = "AthenaError";
1595
+ this.code = input.code;
1596
+ this.kind = input.kind;
1597
+ this.category = input.category;
1598
+ this.status = input.status;
1599
+ this.retryable = input.retryable ?? false;
1600
+ this.requestId = input.requestId;
1601
+ this.context = input.context;
1602
+ this.raw = input.raw;
1603
+ }
1604
+ };
1605
+ function isRecord3(value) {
1606
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1607
+ }
1608
+ function isAthenaErrorKind(value) {
1609
+ return value === "unique_violation" || value === "not_found" || value === "validation" || value === "auth" || value === "rate_limit" || value === "transient" || value === "unknown";
1610
+ }
1611
+ function isAthenaErrorCode(value) {
1612
+ return value === "UNIQUE_VIOLATION" || value === "NOT_FOUND" || value === "VALIDATION_FAILED" || value === "AUTH_UNAUTHORIZED" || value === "AUTH_FORBIDDEN" || value === "RATE_LIMITED" || value === "NETWORK_UNAVAILABLE" || value === "TRANSIENT_FAILURE" || value === "HTTP_FAILURE" || value === "UNKNOWN";
1613
+ }
1614
+ function isAthenaErrorCategory(value) {
1615
+ return value === "transport" || value === "client" || value === "server" || value === "database" || value === "unknown";
1616
+ }
1617
+ function isNormalizedAthenaError(value) {
1618
+ return isRecord3(value) && isAthenaErrorKind(value.kind) && isAthenaErrorCode(value.code) && isAthenaErrorCategory(value.category) && typeof value.retryable === "boolean" && typeof value.message === "string" && "raw" in value;
1619
+ }
1620
+ function withContextOverrides(normalized, context) {
1621
+ if (!context?.table && !context?.operation) {
1622
+ return normalized;
1623
+ }
1624
+ return {
1625
+ ...normalized,
1626
+ table: context.table ?? normalized.table,
1627
+ operation: context.operation ?? normalized.operation
976
1628
  };
977
- const addCondition = (operator, column, value, hints) => {
978
- const condition = { operator };
979
- if (column) {
980
- condition.column = column;
981
- if (operator === "eq") {
982
- condition.eq_column = column;
983
- }
984
- }
985
- if (value !== void 0) {
986
- condition.value = value;
987
- if (operator === "eq") {
988
- condition.eq_value = value;
989
- }
990
- }
991
- if (hints?.valueCast) {
992
- condition.value_cast = hints.valueCast;
993
- if (operator === "eq") {
994
- condition.eq_value_cast = hints.valueCast;
995
- }
996
- }
997
- if (hints?.columnCast) {
998
- condition.column_cast = hints.columnCast;
999
- if (operator === "eq") {
1000
- condition.eq_column_cast = hints.columnCast;
1629
+ }
1630
+ function resolveAttachedNormalizedError(resultOrError) {
1631
+ if (!isRecord3(resultOrError)) return void 0;
1632
+ if (!("__athenaNormalizedError" in resultOrError)) return void 0;
1633
+ const candidate = resultOrError.__athenaNormalizedError;
1634
+ return isNormalizedAthenaError(candidate) ? candidate : void 0;
1635
+ }
1636
+ function safeStringify(value) {
1637
+ try {
1638
+ const serialized = JSON.stringify(value);
1639
+ return serialized ?? String(value);
1640
+ } catch {
1641
+ return "[unserializable]";
1642
+ }
1643
+ }
1644
+ function contextHint(context) {
1645
+ if (!context?.identity) return void 0;
1646
+ const identity = typeof context.identity === "string" ? context.identity : safeStringify(context.identity);
1647
+ return `Identity: ${identity}`;
1648
+ }
1649
+ function isAthenaResultLike(value) {
1650
+ return isRecord3(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
1651
+ }
1652
+ function operationFromDetails(details) {
1653
+ if (!details?.endpoint) return void 0;
1654
+ if (details.endpoint === "/gateway/fetch" || details.endpoint === "/gateway/query") return "select";
1655
+ if (details.endpoint === "/gateway/insert") return "insert";
1656
+ if (details.endpoint === "/gateway/update") return "update";
1657
+ if (details.endpoint === "/gateway/delete") return "delete";
1658
+ if (details.endpoint === "/gateway/rpc" || details.endpoint.startsWith("/rpc/")) return "rpc";
1659
+ return void 0;
1660
+ }
1661
+ function matchRegex(input, patterns) {
1662
+ for (const pattern of patterns) {
1663
+ const match = pattern.exec(input);
1664
+ if (match?.[1]) return match[1];
1665
+ }
1666
+ return void 0;
1667
+ }
1668
+ function extractConstraint(message) {
1669
+ return matchRegex(message, [
1670
+ /unique constraint\s+["'`]([^"'`]+)["'`]/i,
1671
+ /constraint\s+["'`]([^"'`]+)["'`]/i
1672
+ ]);
1673
+ }
1674
+ function extractTable(message) {
1675
+ return matchRegex(message, [
1676
+ /(?:table|relation)\s+["'`]([^"'`]+)["'`]/i,
1677
+ /on\s+table\s+([a-zA-Z0-9_.]+)/i
1678
+ ]);
1679
+ }
1680
+ function classifyKind(status, code, message) {
1681
+ const lower = message.toLowerCase();
1682
+ const hasUniquePattern = lower.includes("unique constraint") || lower.includes("duplicate key") || lower.includes("already exists") || lower.includes("duplicate");
1683
+ const hasNotFoundPattern = lower.includes("not found") || lower.includes("no rows");
1684
+ const hasValidationPattern = lower.includes("validation") || lower.includes("invalid") || lower.includes("malformed");
1685
+ const hasAuthPattern = lower.includes("unauthorized") || lower.includes("forbidden") || lower.includes("auth");
1686
+ const hasRateLimitPattern = lower.includes("rate limit") || lower.includes("too many requests");
1687
+ const hasTransientPattern = lower.includes("timeout") || lower.includes("temporar") || lower.includes("connection reset") || lower.includes("socket") || lower.includes("deadlock");
1688
+ if (status === 409 || hasUniquePattern) return "unique_violation";
1689
+ if (status === 404 || hasNotFoundPattern) return "not_found";
1690
+ if (status === 401 || status === 403 || hasAuthPattern) return "auth";
1691
+ if (status === 429 || hasRateLimitPattern) return "rate_limit";
1692
+ if (status === 400 || status === 422 || hasValidationPattern) return "validation";
1693
+ if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
1694
+ return "transient";
1695
+ }
1696
+ return "unknown";
1697
+ }
1698
+ function toAthenaErrorCode(kind, status, gatewayCode) {
1699
+ if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
1700
+ return AthenaErrorCode.NetworkUnavailable;
1701
+ }
1702
+ switch (kind) {
1703
+ case "unique_violation":
1704
+ return AthenaErrorCode.UniqueViolation;
1705
+ case "not_found":
1706
+ return AthenaErrorCode.NotFound;
1707
+ case "validation":
1708
+ return AthenaErrorCode.ValidationFailed;
1709
+ case "rate_limit":
1710
+ return AthenaErrorCode.RateLimited;
1711
+ case "auth":
1712
+ if (status === 403) {
1713
+ return AthenaErrorCode.AuthForbidden;
1001
1714
  }
1002
- }
1003
- state.conditions.push(condition);
1715
+ return AthenaErrorCode.AuthUnauthorized;
1716
+ case "transient":
1717
+ return status !== void 0 && status >= 500 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.TransientFailure;
1718
+ case "unknown":
1719
+ default:
1720
+ return status !== void 0 && status >= 400 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.Unknown;
1721
+ }
1722
+ }
1723
+ function toAthenaErrorCategory(kind, status) {
1724
+ if (kind === "transient" && (status === 0 || status === void 0)) {
1725
+ return AthenaErrorCategory.Transport;
1726
+ }
1727
+ if (kind === "unique_violation") return AthenaErrorCategory.Database;
1728
+ if (kind === "validation" || kind === "auth" || kind === "not_found") return AthenaErrorCategory.Client;
1729
+ if (kind === "rate_limit" || kind === "transient") return AthenaErrorCategory.Server;
1730
+ return AthenaErrorCategory.Unknown;
1731
+ }
1732
+ function isRetryable(kind, status) {
1733
+ if (kind === "rate_limit" || kind === "transient") return true;
1734
+ return status !== void 0 && status >= 500;
1735
+ }
1736
+ function toGatewayCode(kind, status) {
1737
+ if (kind === "transient" && (status === 0 || status === void 0)) return "NETWORK_ERROR";
1738
+ if (kind === "validation") return "INVALID_JSON";
1739
+ if (status !== void 0 && status >= 400) return "HTTP_ERROR";
1740
+ return "UNKNOWN_ERROR";
1741
+ }
1742
+ function toAthenaGatewayError(source, fallbackMessage, context) {
1743
+ if (isAthenaGatewayError(source)) {
1744
+ return source;
1745
+ }
1746
+ if (isAthenaResultLike(source) && source.errorDetails) {
1747
+ return new AthenaGatewayError({
1748
+ code: source.errorDetails.code,
1749
+ message: source.error ?? source.errorDetails.message,
1750
+ status: source.status,
1751
+ endpoint: source.errorDetails.endpoint,
1752
+ method: source.errorDetails.method,
1753
+ requestId: source.errorDetails.requestId,
1754
+ hint: source.errorDetails.hint,
1755
+ cause: source.errorDetails.cause
1756
+ });
1757
+ }
1758
+ const normalized = normalizeAthenaError(source, context);
1759
+ const message = isAthenaResultLike(source) && source.error == null && source.errorDetails == null ? fallbackMessage : normalized.message || fallbackMessage;
1760
+ return new AthenaGatewayError({
1761
+ code: toGatewayCode(normalized.kind, normalized.status),
1762
+ message,
1763
+ status: normalized.status ?? 0,
1764
+ hint: normalized.constraint != null ? `Constraint: ${normalized.constraint}` : contextHint(context),
1765
+ cause: typeof normalized.raw === "string" ? normalized.raw : safeStringify(normalized.raw)
1766
+ });
1767
+ }
1768
+ function isOk(result) {
1769
+ return result.error == null && result.status >= 200 && result.status < 300;
1770
+ }
1771
+ function normalizeAthenaError(resultOrError, context) {
1772
+ const attached = resolveAttachedNormalizedError(resultOrError);
1773
+ if (attached) {
1774
+ return withContextOverrides(attached, context);
1775
+ }
1776
+ if (isAthenaResultLike(resultOrError)) {
1777
+ const details = resultOrError.errorDetails;
1778
+ const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
1779
+ const operation = context?.operation ?? operationFromDetails(details);
1780
+ const table = context?.table ?? extractTable(message2);
1781
+ const constraint = extractConstraint(message2);
1782
+ const kind2 = classifyKind(resultOrError.status, details?.code, message2);
1783
+ const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
1784
+ const category = toAthenaErrorCategory(kind2, resultOrError.status);
1785
+ return {
1786
+ kind: kind2,
1787
+ code,
1788
+ category,
1789
+ retryable: isRetryable(kind2, resultOrError.status),
1790
+ status: resultOrError.status,
1791
+ constraint,
1792
+ table,
1793
+ operation,
1794
+ message: message2,
1795
+ raw: resultOrError.raw
1796
+ };
1797
+ }
1798
+ if (isAthenaGatewayError(resultOrError)) {
1799
+ const details = resultOrError.toDetails();
1800
+ const operation = context?.operation ?? operationFromDetails(details);
1801
+ const table = context?.table ?? extractTable(resultOrError.message);
1802
+ const constraint = extractConstraint(resultOrError.message);
1803
+ const kind2 = classifyKind(resultOrError.status, resultOrError.code, resultOrError.message);
1804
+ const code = toAthenaErrorCode(kind2, resultOrError.status, resultOrError.code);
1805
+ const category = toAthenaErrorCategory(kind2, resultOrError.status);
1806
+ return {
1807
+ kind: kind2,
1808
+ code,
1809
+ category,
1810
+ retryable: isRetryable(kind2, resultOrError.status),
1811
+ status: resultOrError.status,
1812
+ constraint,
1813
+ table,
1814
+ operation,
1815
+ message: resultOrError.message,
1816
+ raw: resultOrError
1817
+ };
1818
+ }
1819
+ if (resultOrError instanceof Error) {
1820
+ const maybeStatus = isRecord3(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
1821
+ const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
1822
+ return {
1823
+ kind: kind2,
1824
+ code: toAthenaErrorCode(kind2, maybeStatus),
1825
+ category: toAthenaErrorCategory(kind2, maybeStatus),
1826
+ retryable: isRetryable(kind2, maybeStatus),
1827
+ status: maybeStatus,
1828
+ constraint: extractConstraint(resultOrError.message),
1829
+ table: context?.table ?? extractTable(resultOrError.message),
1830
+ operation: context?.operation,
1831
+ message: resultOrError.message,
1832
+ raw: resultOrError
1833
+ };
1834
+ }
1835
+ const message = typeof resultOrError === "string" ? resultOrError : "Unknown Athena error";
1836
+ const kind = classifyKind(void 0, void 0, message);
1837
+ return {
1838
+ kind,
1839
+ code: toAthenaErrorCode(kind, void 0),
1840
+ category: toAthenaErrorCategory(kind, void 0),
1841
+ retryable: isRetryable(kind, void 0),
1842
+ status: void 0,
1843
+ constraint: extractConstraint(message),
1844
+ table: context?.table ?? extractTable(message),
1845
+ operation: context?.operation,
1846
+ message,
1847
+ raw: resultOrError
1004
1848
  };
1005
- const builder = {};
1006
- const filterMethods = createFilterMethods(
1007
- state,
1008
- addCondition,
1009
- builder
1010
- );
1011
- const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
1012
- const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
1013
- const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
1014
- const hasTypedEqualityComparison = conditions?.some(
1015
- (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
1016
- ) ?? false;
1017
- if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
1018
- const query = buildTypedSelectQuery({
1019
- tableName: resolvedTableName,
1020
- columns,
1021
- conditions,
1022
- limit: state.limit,
1023
- offset: state.offset,
1024
- currentPage: state.currentPage,
1025
- pageSize: state.pageSize,
1026
- order: state.order
1027
- });
1028
- if (query) {
1029
- const queryResponse = await client.queryGateway({ query }, options);
1030
- return formatResult(queryResponse);
1849
+ }
1850
+ function unwrapRows(result, options) {
1851
+ if (!isOk(result)) {
1852
+ throw toAthenaGatewayError(result, "Athena request failed", options?.context);
1853
+ }
1854
+ if (result.data == null) return [];
1855
+ return Array.isArray(result.data) ? result.data : [result.data];
1856
+ }
1857
+ function unwrap(result, options) {
1858
+ if (!isOk(result)) {
1859
+ throw toAthenaGatewayError(result, "Athena request failed", options?.context);
1860
+ }
1861
+ if (result.data == null && !options?.allowNull) {
1862
+ throw toAthenaGatewayError(result, "Expected data but received null", options?.context);
1863
+ }
1864
+ return result.data;
1865
+ }
1866
+ function unwrapOne(result, options) {
1867
+ const rows = unwrapRows(result, options);
1868
+ if (!rows.length) {
1869
+ if (options?.allowNull) return null;
1870
+ throw toAthenaGatewayError(result, "Expected one row but received none", options?.context);
1871
+ }
1872
+ if (options?.requireExactlyOne && rows.length !== 1) {
1873
+ throw toAthenaGatewayError(
1874
+ result,
1875
+ `Expected exactly one row but received ${rows.length}`,
1876
+ options.context
1877
+ );
1878
+ }
1879
+ return rows[0];
1880
+ }
1881
+ function requireSuccess(result, context) {
1882
+ if (!isOk(result)) {
1883
+ throw toAthenaGatewayError(
1884
+ result,
1885
+ `Athena ${context?.operation ?? "request"} failed`,
1886
+ context
1887
+ );
1888
+ }
1889
+ return result;
1890
+ }
1891
+ function requireAffected(result, options, context) {
1892
+ requireSuccess(result, context);
1893
+ const minimum = options?.min ?? 1;
1894
+ const count = result.count;
1895
+ if (count == null) {
1896
+ throw new AthenaGatewayError({
1897
+ code: "UNKNOWN_ERROR",
1898
+ status: result.status,
1899
+ message: "Expected affected row count but response.count is missing",
1900
+ hint: 'Set call option { count: "exact" } for mutation postcondition checks.',
1901
+ cause: safeStringify(result.raw)
1902
+ });
1903
+ }
1904
+ if (count < minimum) {
1905
+ throw new AthenaGatewayError({
1906
+ code: "UNKNOWN_ERROR",
1907
+ status: result.status,
1908
+ message: `Expected at least ${minimum} affected rows but received ${count}`,
1909
+ hint: contextHint(context),
1910
+ cause: safeStringify(result.raw)
1911
+ });
1912
+ }
1913
+ return count;
1914
+ }
1915
+ function applyBounds(value, options) {
1916
+ if (options?.min !== void 0 && value < options.min) return null;
1917
+ if (options?.max !== void 0 && value > options.max) return null;
1918
+ return value;
1919
+ }
1920
+ function parseIntegerString(value) {
1921
+ const normalized = value.trim();
1922
+ if (!/^[-+]?\d+$/.test(normalized)) return null;
1923
+ const parsed = Number(normalized);
1924
+ if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;
1925
+ return parsed;
1926
+ }
1927
+ function coerceInt(value, options) {
1928
+ if (value == null) return null;
1929
+ if (typeof value === "number") {
1930
+ if (!Number.isFinite(value) || !Number.isInteger(value)) return null;
1931
+ return applyBounds(value, options);
1932
+ }
1933
+ if (typeof value === "string") {
1934
+ const parsed = parseIntegerString(value);
1935
+ if (parsed == null) return null;
1936
+ return applyBounds(parsed, options);
1937
+ }
1938
+ if (typeof value === "bigint") {
1939
+ if (options?.strictBigInt) {
1940
+ if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER)) {
1941
+ return null;
1031
1942
  }
1032
1943
  }
1033
- const payload = {
1034
- table_name: resolvedTableName,
1035
- columns,
1036
- conditions,
1037
- limit: state.limit,
1038
- offset: state.offset,
1039
- current_page: state.currentPage,
1040
- page_size: state.pageSize,
1041
- total_pages: state.totalPages,
1042
- sort_by: state.order,
1043
- strip_nulls: options?.stripNulls ?? true,
1044
- count: options?.count,
1045
- head: options?.head
1046
- };
1047
- const response = await client.fetchGateway(payload, options);
1048
- return formatResult(response);
1944
+ const parsed = Number(value);
1945
+ if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;
1946
+ return applyBounds(parsed, options);
1947
+ }
1948
+ return null;
1949
+ }
1950
+ function assertInt(value, label = "value", options) {
1951
+ const parsed = coerceInt(value, options);
1952
+ if (parsed == null) {
1953
+ throw new TypeError(`${label} must be a finite integer`);
1954
+ }
1955
+ return parsed;
1956
+ }
1957
+ function defaultShouldRetry(error) {
1958
+ const normalized = normalizeAthenaError(error);
1959
+ return normalized.kind === "transient" || normalized.kind === "rate_limit";
1960
+ }
1961
+ function computeDelayMs(attempt, error, config) {
1962
+ const baseDelay = config.baseDelayMs;
1963
+ const rawDelay = typeof config.backoff === "function" ? config.backoff(attempt, error) : config.backoff === "linear" ? baseDelay * attempt : baseDelay * Math.pow(2, attempt - 1);
1964
+ const safeDelay = Number.isFinite(rawDelay) ? Math.max(0, rawDelay) : 0;
1965
+ const clamped = Math.min(config.maxDelayMs, safeDelay);
1966
+ const jitterFactor = typeof config.jitter === "number" ? Math.max(0, Math.min(1, config.jitter)) : config.jitter ? 0.2 : 0;
1967
+ if (!jitterFactor) return clamped;
1968
+ const deviation = clamped * jitterFactor;
1969
+ const offset = (Math.random() * 2 - 1) * deviation;
1970
+ return Math.max(0, clamped + offset);
1971
+ }
1972
+ function sleep(ms) {
1973
+ if (ms <= 0) return Promise.resolve();
1974
+ return new Promise((resolve3) => {
1975
+ setTimeout(resolve3, ms);
1976
+ });
1977
+ }
1978
+ async function withRetry(config, fn) {
1979
+ const retries = Math.max(0, Math.trunc(config.retries));
1980
+ const shouldRetry = config.shouldRetry ?? defaultShouldRetry;
1981
+ const resolvedConfig = {
1982
+ baseDelayMs: config.baseDelayMs ?? 100,
1983
+ maxDelayMs: config.maxDelayMs ?? 1e4,
1984
+ backoff: config.backoff ?? "exponential",
1985
+ jitter: config.jitter ?? false
1049
1986
  };
1050
- const createSelectChain = (columns, options) => {
1051
- const chain = {};
1052
- const filterMethods2 = createFilterMethods(state, addCondition, chain);
1053
- Object.assign(chain, filterMethods2, {
1054
- async single(cols, opts) {
1055
- const r = await runSelect(cols ?? columns, opts ?? options);
1056
- return toSingleResult(r);
1057
- },
1058
- maybeSingle(cols, opts) {
1059
- return chain.single(cols, opts);
1060
- },
1061
- then(onfulfilled, onrejected) {
1062
- return runSelect(columns, options).then(onfulfilled, onrejected);
1063
- },
1064
- catch(onrejected) {
1065
- return runSelect(columns, options).catch(onrejected);
1066
- },
1067
- finally(onfinally) {
1068
- return runSelect(columns, options).finally(onfinally);
1987
+ for (let attempts = 0; attempts <= retries; attempts += 1) {
1988
+ try {
1989
+ return await fn();
1990
+ } catch (error) {
1991
+ if (attempts >= retries) {
1992
+ throw error;
1069
1993
  }
1070
- });
1071
- return chain;
1072
- };
1073
- Object.assign(builder, filterMethods, {
1074
- reset() {
1075
- state.conditions = [];
1076
- state.limit = void 0;
1077
- state.offset = void 0;
1078
- state.order = void 0;
1079
- state.currentPage = void 0;
1080
- state.pageSize = void 0;
1081
- state.totalPages = void 0;
1082
- return builder;
1994
+ const currentAttempt = attempts + 1;
1995
+ const retry = await shouldRetry(error, currentAttempt);
1996
+ if (!retry) {
1997
+ throw error;
1998
+ }
1999
+ const delay = computeDelayMs(currentAttempt, error, resolvedConfig);
2000
+ await sleep(delay);
2001
+ }
2002
+ }
2003
+ throw new Error("withRetry reached an unexpected state");
2004
+ }
2005
+
2006
+ // src/db/module.ts
2007
+ function createDbModule(input) {
2008
+ const db = {
2009
+ from(table) {
2010
+ return input.from(table);
1083
2011
  },
1084
- select(columns = DEFAULT_COLUMNS, options) {
1085
- return createSelectChain(columns, options);
2012
+ select(table, columns, options) {
2013
+ return input.from(table).select(columns, options);
1086
2014
  },
1087
- insert(values, options) {
1088
- if (Array.isArray(values)) {
1089
- const executeInsertMany = async (columns, selectOptions) => {
1090
- const mergedOptions = mergeOptions(options, selectOptions);
1091
- const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1092
- const payload = {
1093
- table_name: resolvedTableName,
1094
- insert_body: asAthenaJsonObjectArray(values)
1095
- };
1096
- if (columns) payload.columns = columns;
1097
- if (mergedOptions?.count) payload.count = mergedOptions.count;
1098
- if (mergedOptions?.head) payload.head = mergedOptions.head;
1099
- if (mergedOptions?.defaultToNull !== void 0) {
1100
- payload.default_to_null = mergedOptions.defaultToNull;
1101
- }
1102
- const response = await client.insertGateway(payload, mergedOptions);
1103
- return formatResult(response);
1104
- };
1105
- return createMutationQuery(executeInsertMany);
1106
- }
1107
- const executeInsertOne = async (columns, selectOptions) => {
1108
- const mergedOptions = mergeOptions(options, selectOptions);
1109
- const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1110
- const payload = {
1111
- table_name: resolvedTableName,
1112
- insert_body: asAthenaJsonObject(values)
1113
- };
1114
- if (columns) payload.columns = columns;
1115
- if (mergedOptions?.count) payload.count = mergedOptions.count;
1116
- if (mergedOptions?.head) payload.head = mergedOptions.head;
1117
- if (mergedOptions?.defaultToNull !== void 0) {
1118
- payload.default_to_null = mergedOptions.defaultToNull;
1119
- }
1120
- const response = await client.insertGateway(payload, mergedOptions);
1121
- return formatResult(response);
1122
- };
1123
- return createMutationQuery(executeInsertOne);
2015
+ insert(table, values, options) {
2016
+ return Array.isArray(values) ? input.from(table).insert(values, options) : input.from(table).insert(values, options);
1124
2017
  },
1125
- upsert(values, options) {
1126
- if (Array.isArray(values)) {
1127
- const executeUpsertMany = async (columns, selectOptions) => {
1128
- const mergedOptions = mergeOptions(options, selectOptions);
1129
- const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1130
- const payload = {
1131
- table_name: resolvedTableName,
1132
- insert_body: asAthenaJsonObjectArray(values),
1133
- update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
1134
- };
1135
- if (columns) payload.columns = columns;
1136
- if (options?.onConflict) payload.on_conflict = options.onConflict;
1137
- if (mergedOptions?.count) payload.count = mergedOptions.count;
1138
- if (mergedOptions?.head) payload.head = mergedOptions.head;
1139
- if (mergedOptions?.defaultToNull !== void 0) {
1140
- payload.default_to_null = mergedOptions.defaultToNull;
1141
- }
1142
- const response = await client.insertGateway(payload, mergedOptions);
1143
- return formatResult(response);
1144
- };
1145
- return createMutationQuery(executeUpsertMany);
1146
- }
1147
- const executeUpsertOne = async (columns, selectOptions) => {
1148
- const mergedOptions = mergeOptions(options, selectOptions);
1149
- const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1150
- const payload = {
1151
- table_name: resolvedTableName,
1152
- insert_body: asAthenaJsonObject(values),
1153
- update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
1154
- };
1155
- if (columns) payload.columns = columns;
1156
- if (options?.onConflict) payload.on_conflict = options.onConflict;
1157
- if (mergedOptions?.count) payload.count = mergedOptions.count;
1158
- if (mergedOptions?.head) payload.head = mergedOptions.head;
1159
- if (mergedOptions?.defaultToNull !== void 0) {
1160
- payload.default_to_null = mergedOptions.defaultToNull;
1161
- }
1162
- const response = await client.insertGateway(payload, mergedOptions);
1163
- return formatResult(response);
1164
- };
1165
- return createMutationQuery(executeUpsertOne);
2018
+ upsert(table, values, options) {
2019
+ return Array.isArray(values) ? input.from(table).upsert(values, options) : input.from(table).upsert(values, options);
1166
2020
  },
1167
- update(values, options) {
1168
- const executeUpdate = async (columns, selectOptions) => {
1169
- const filters = state.conditions.length ? [...state.conditions] : void 0;
1170
- const mergedOptions = mergeOptions(options, selectOptions);
1171
- const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1172
- const payload = {
1173
- table_name: resolvedTableName,
1174
- set: asAthenaJsonObject(values),
1175
- conditions: filters,
1176
- strip_nulls: mergedOptions?.stripNulls ?? true
1177
- };
1178
- if (state.order) payload.sort_by = state.order;
1179
- if (state.currentPage !== void 0) payload.current_page = state.currentPage;
1180
- if (state.pageSize !== void 0) payload.page_size = state.pageSize;
1181
- if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
1182
- if (columns) payload.columns = columns;
1183
- const response = await client.updateGateway(payload, mergedOptions);
1184
- return formatResult(response);
1185
- };
1186
- const mutation = createMutationQuery(executeUpdate, null);
1187
- const updateChain = {};
1188
- const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
1189
- Object.assign(updateChain, filterMethods2, mutation);
1190
- return updateChain;
2021
+ update(table, values, options) {
2022
+ return input.from(table).update(values, options);
1191
2023
  },
1192
- delete(options) {
1193
- const filters = state.conditions.length ? [...state.conditions] : void 0;
1194
- const resourceId = options?.resourceId ?? getResourceId(state);
1195
- if (!resourceId && !filters?.length) {
1196
- throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
1197
- }
1198
- const executeDelete = async (columns, selectOptions) => {
1199
- const mergedOptions = mergeOptions(options, selectOptions);
1200
- const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1201
- const payload = {
1202
- table_name: resolvedTableName,
1203
- resource_id: resourceId,
1204
- conditions: filters
1205
- };
1206
- if (state.order) payload.sort_by = state.order;
1207
- if (state.currentPage !== void 0) payload.current_page = state.currentPage;
1208
- if (state.pageSize !== void 0) payload.page_size = state.pageSize;
1209
- if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
1210
- if (columns) payload.columns = columns;
1211
- const response = await client.deleteGateway(payload, mergedOptions);
1212
- return formatResult(response);
1213
- };
1214
- return createMutationQuery(executeDelete, null);
2024
+ delete(table, options) {
2025
+ return input.from(table).delete(options);
1215
2026
  },
1216
- async single(columns, options) {
1217
- const response = await builder.select(columns, options);
1218
- return toSingleResult(response);
2027
+ rpc(fn, args, options) {
2028
+ return input.rpc(fn, args, options);
1219
2029
  },
1220
- async maybeSingle(columns, options) {
1221
- return builder.single(columns, options);
2030
+ query(query, options) {
2031
+ return input.query(query, options);
1222
2032
  }
2033
+ };
2034
+ return db;
2035
+ }
2036
+
2037
+ // src/client.ts
2038
+ var DEFAULT_COLUMNS = "*";
2039
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
2040
+ var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
2041
+ var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
2042
+ function formatResult(response) {
2043
+ const result = {
2044
+ data: response.data ?? null,
2045
+ error: response.error ?? null,
2046
+ errorDetails: response.errorDetails ?? null,
2047
+ status: response.status,
2048
+ raw: response.raw
2049
+ };
2050
+ if (response.count !== void 0) {
2051
+ result.count = response.count;
2052
+ }
2053
+ return result;
2054
+ }
2055
+ function attachNormalizedError(result, normalizedError) {
2056
+ Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
2057
+ value: normalizedError,
2058
+ enumerable: false,
2059
+ configurable: true,
2060
+ writable: false
1223
2061
  });
1224
- return builder;
1225
2062
  }
1226
- function createQueryBuilder(client) {
1227
- return async function query(query, options) {
1228
- const normalizedQuery = query.trim();
1229
- if (!normalizedQuery) {
1230
- throw new Error("query requires a non-empty string");
2063
+ function createResultFormatter(experimental) {
2064
+ if (!experimental?.enableErrorNormalization) {
2065
+ return formatResult;
2066
+ }
2067
+ return (response, context) => {
2068
+ const result = formatResult(response);
2069
+ if (result.error == null) {
2070
+ return result;
1231
2071
  }
1232
- const response = await client.queryGateway({ query: normalizedQuery }, options);
1233
- return formatResult(response);
2072
+ const normalizedError = normalizeAthenaError(result, context);
2073
+ attachNormalizedError(result, normalizedError);
2074
+ return result;
1234
2075
  };
1235
2076
  }
1236
- function createClientFromConfig(config) {
1237
- const gateway = createAthenaGatewayClient({
1238
- baseUrl: config.baseUrl,
1239
- apiKey: config.apiKey,
1240
- client: config.client,
1241
- backend: config.backend,
1242
- headers: config.headers
1243
- });
2077
+ function toSingleResult(response) {
2078
+ const payload = response.data;
2079
+ const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
1244
2080
  return {
1245
- from(table) {
1246
- return createTableBuilder(table, gateway);
1247
- },
1248
- rpc(fn, args, options) {
1249
- const normalizedFn = fn.trim();
1250
- if (!normalizedFn) {
1251
- throw new Error("rpc requires a function name");
1252
- }
1253
- return createRpcBuilder(
1254
- normalizedFn,
1255
- args,
1256
- options,
1257
- gateway
1258
- );
1259
- },
1260
- query: createQueryBuilder(gateway)
2081
+ ...response,
2082
+ data: singleData
1261
2083
  };
1262
2084
  }
1263
- var DEFAULT_BACKEND = { type: "athena" };
1264
- function toBackendConfig(b) {
1265
- if (!b) return DEFAULT_BACKEND;
1266
- return typeof b === "string" ? { type: b } : b;
2085
+ function mergeOptions(...options) {
2086
+ return options.reduce((acc, next) => {
2087
+ if (!next) return acc;
2088
+ return { ...acc, ...next };
2089
+ }, void 0);
1267
2090
  }
1268
- var AthenaClientBuilderImpl = class {
1269
- baseUrl;
1270
- apiKey;
1271
- backendConfig = DEFAULT_BACKEND;
1272
- clientName;
1273
- defaultHeaders;
1274
- isHealthTrackingEnabled = false;
1275
- url(url) {
1276
- this.baseUrl = url;
1277
- return this;
1278
- }
1279
- key(apiKey) {
1280
- this.apiKey = apiKey;
1281
- return this;
1282
- }
1283
- backend(backend) {
1284
- this.backendConfig = toBackendConfig(backend);
1285
- return this;
1286
- }
1287
- client(clientName) {
1288
- this.clientName = clientName;
1289
- return this;
1290
- }
1291
- headers(headers) {
1292
- this.defaultHeaders = headers;
1293
- return this;
1294
- }
1295
- healthTracking(enabled) {
1296
- this.isHealthTrackingEnabled = enabled;
1297
- return this;
1298
- }
1299
- build() {
1300
- if (!this.baseUrl || !this.apiKey) {
1301
- throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
2091
+ function asAthenaJsonObject(value) {
2092
+ return value;
2093
+ }
2094
+ function asAthenaJsonObjectArray(values) {
2095
+ return values;
2096
+ }
2097
+ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
2098
+ let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
2099
+ let selectedOptions;
2100
+ let promise = null;
2101
+ const run = (columns, options) => {
2102
+ const payloadColumns = columns ?? selectedColumns;
2103
+ const payloadOptions = options ?? selectedOptions;
2104
+ if (!promise) {
2105
+ promise = executor(payloadColumns, payloadOptions);
1302
2106
  }
1303
- return createClientFromConfig({
1304
- baseUrl: this.baseUrl,
1305
- apiKey: this.apiKey,
1306
- client: this.clientName,
1307
- backend: this.backendConfig,
1308
- headers: this.defaultHeaders,
1309
- healthTracking: this.isHealthTrackingEnabled
1310
- });
1311
- }
1312
- };
1313
- var AthenaClient = class _AthenaClient {
1314
- /** Create a fluent builder for a strongly-typed Athena SDK client. */
1315
- static builder() {
1316
- return new AthenaClientBuilderImpl();
1317
- }
1318
- /** Build a client from process environment variables. */
1319
- static fromEnvironment() {
1320
- const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
1321
- const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
1322
- if (!url || !key) {
1323
- throw new Error(
1324
- "ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
1325
- );
2107
+ return promise;
2108
+ };
2109
+ const mutationQuery = {
2110
+ select(columns = selectedColumns, options) {
2111
+ selectedColumns = columns;
2112
+ selectedOptions = options ?? selectedOptions;
2113
+ return run(columns, options);
2114
+ },
2115
+ returning(columns = selectedColumns, options) {
2116
+ return mutationQuery.select(columns, options);
2117
+ },
2118
+ single(columns = selectedColumns, options) {
2119
+ selectedColumns = columns;
2120
+ selectedOptions = options ?? selectedOptions;
2121
+ return run(columns, options).then(toSingleResult);
2122
+ },
2123
+ maybeSingle(columns = selectedColumns, options) {
2124
+ return mutationQuery.single(columns, options);
2125
+ },
2126
+ then(onfulfilled, onrejected) {
2127
+ return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
2128
+ },
2129
+ catch(onrejected) {
2130
+ return run(selectedColumns, selectedOptions).catch(onrejected);
2131
+ },
2132
+ finally(onfinally) {
2133
+ return run(selectedColumns, selectedOptions).finally(onfinally);
1326
2134
  }
1327
- return _AthenaClient.builder().url(url).key(key).build();
1328
- }
1329
- };
1330
- function createClient(url, apiKey, options) {
1331
- const b = AthenaClient.builder().url(url).key(apiKey).backend(toBackendConfig(options?.backend));
1332
- if (options?.client) b.client(options.client);
1333
- if (options?.headers && Object.keys(options.headers).length > 0) b.headers(options.headers);
1334
- return b.build();
2135
+ };
2136
+ return mutationQuery;
1335
2137
  }
1336
-
1337
- // src/gateway/types.ts
1338
- var Backend = {
1339
- Athena: { type: "athena" },
1340
- Postgrest: { type: "postgrest" },
1341
- PostgreSQL: { type: "postgresql" },
1342
- ScyllaDB: { type: "scylladb" }
1343
- };
1344
-
1345
- // src/auxiliaries.ts
1346
- var AthenaErrorKind = {
1347
- UniqueViolation: "unique_violation",
1348
- NotFound: "not_found",
1349
- Validation: "validation",
1350
- Auth: "auth",
1351
- RateLimit: "rate_limit",
1352
- Transient: "transient",
1353
- Unknown: "unknown"
1354
- };
1355
- var AthenaErrorCode = {
1356
- UniqueViolation: "UNIQUE_VIOLATION",
1357
- NotFound: "NOT_FOUND",
1358
- ValidationFailed: "VALIDATION_FAILED",
1359
- AuthUnauthorized: "AUTH_UNAUTHORIZED",
1360
- AuthForbidden: "AUTH_FORBIDDEN",
1361
- RateLimited: "RATE_LIMITED",
1362
- NetworkUnavailable: "NETWORK_UNAVAILABLE",
1363
- TransientFailure: "TRANSIENT_FAILURE",
1364
- HttpFailure: "HTTP_FAILURE",
1365
- Unknown: "UNKNOWN"
1366
- };
1367
- var AthenaErrorCategory = {
1368
- Transport: "transport",
1369
- Client: "client",
1370
- Server: "server",
1371
- Database: "database",
1372
- Unknown: "unknown"
1373
- };
1374
- var AthenaError = class extends Error {
1375
- code;
1376
- kind;
1377
- category;
1378
- status;
1379
- retryable;
1380
- requestId;
1381
- context;
1382
- raw;
1383
- constructor(input) {
1384
- super(input.message);
1385
- this.name = "AthenaError";
1386
- this.code = input.code;
1387
- this.kind = input.kind;
1388
- this.category = input.category;
1389
- this.status = input.status;
1390
- this.retryable = input.retryable ?? false;
1391
- this.requestId = input.requestId;
1392
- this.context = input.context;
1393
- this.raw = input.raw;
2138
+ function getResourceId(state) {
2139
+ const candidate = state.conditions.find(
2140
+ (condition) => condition.operator === "eq" && (condition.column === "resource_id" || condition.column === "id")
2141
+ );
2142
+ return candidate?.value?.toString();
2143
+ }
2144
+ function stringifyFilterValue(value) {
2145
+ if (Array.isArray(value)) {
2146
+ return value.join(",");
1394
2147
  }
1395
- };
1396
- function isRecord2(value) {
1397
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2148
+ return String(value);
1398
2149
  }
1399
- function safeStringify(value) {
1400
- try {
1401
- const serialized = JSON.stringify(value);
1402
- return serialized ?? String(value);
1403
- } catch {
1404
- return "[unserializable]";
2150
+ function isUuidString(value) {
2151
+ return UUID_PATTERN.test(value.trim());
2152
+ }
2153
+ function isUuidIdentifierColumn(column) {
2154
+ return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
2155
+ }
2156
+ function shouldUseUuidTextComparison(column, value) {
2157
+ return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
2158
+ }
2159
+ function normalizeCast(cast) {
2160
+ const normalized = cast.trim().toLowerCase();
2161
+ if (!SAFE_CAST_PATTERN.test(normalized)) {
2162
+ throw new Error(`Invalid cast type "${cast}"`);
1405
2163
  }
2164
+ return normalized;
1406
2165
  }
1407
- function contextHint(context) {
1408
- if (!context?.identity) return void 0;
1409
- const identity = typeof context.identity === "string" ? context.identity : safeStringify(context.identity);
1410
- return `Identity: ${identity}`;
2166
+ function escapeSqlStringLiteral(value) {
2167
+ return value.replace(/'/g, "''");
1411
2168
  }
1412
- function isAthenaResultLike(value) {
1413
- return isRecord2(value) && "status" in value && "error" in value && "data" in value && typeof value.status === "number";
2169
+ function toSqlLiteral(value) {
2170
+ if (value === null) return "NULL";
2171
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : "NULL";
2172
+ if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
2173
+ return `'${escapeSqlStringLiteral(value)}'`;
1414
2174
  }
1415
- function operationFromDetails(details) {
1416
- if (!details?.endpoint) return void 0;
1417
- if (details.endpoint === "/gateway/fetch" || details.endpoint === "/gateway/query") return "select";
1418
- if (details.endpoint === "/gateway/insert") return "insert";
1419
- if (details.endpoint === "/gateway/update") return "update";
1420
- if (details.endpoint === "/gateway/delete") return "delete";
1421
- if (details.endpoint === "/gateway/rpc" || details.endpoint.startsWith("/rpc/")) return "rpc";
1422
- return void 0;
2175
+ function withCast(expression, cast) {
2176
+ if (!cast) return expression;
2177
+ return `${expression}::${normalizeCast(cast)}`;
1423
2178
  }
1424
- function matchRegex(input, patterns) {
1425
- for (const pattern of patterns) {
1426
- const match = pattern.exec(input);
1427
- if (match?.[1]) return match[1];
2179
+ function buildSelectColumnsClause(columns) {
2180
+ if (Array.isArray(columns)) {
2181
+ return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
1428
2182
  }
1429
- return void 0;
1430
- }
1431
- function extractConstraint(message) {
1432
- return matchRegex(message, [
1433
- /unique constraint\s+["'`]([^"'`]+)["'`]/i,
1434
- /constraint\s+["'`]([^"'`]+)["'`]/i
1435
- ]);
2183
+ return quoteSelectColumnsExpression(columns);
1436
2184
  }
1437
- function extractTable(message) {
1438
- return matchRegex(message, [
1439
- /(?:table|relation)\s+["'`]([^"'`]+)["'`]/i,
1440
- /on\s+table\s+([a-zA-Z0-9_.]+)/i
1441
- ]);
2185
+ function resolveTableNameForCall(tableName, schema) {
2186
+ if (!schema) return tableName;
2187
+ const normalizedSchema = schema.trim();
2188
+ if (!normalizedSchema) {
2189
+ throw new Error("schema option must be a non-empty string");
2190
+ }
2191
+ if (tableName.includes(".")) {
2192
+ if (tableName.startsWith(`${normalizedSchema}.`)) {
2193
+ return tableName;
2194
+ }
2195
+ throw new Error(
2196
+ `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
2197
+ );
2198
+ }
2199
+ return `${normalizedSchema}.${tableName}`;
1442
2200
  }
1443
- function classifyKind(status, code, message) {
1444
- const lower = message.toLowerCase();
1445
- const hasUniquePattern = lower.includes("unique constraint") || lower.includes("duplicate key") || lower.includes("already exists") || lower.includes("duplicate");
1446
- const hasNotFoundPattern = lower.includes("not found") || lower.includes("no rows");
1447
- const hasValidationPattern = lower.includes("validation") || lower.includes("invalid") || lower.includes("malformed");
1448
- const hasAuthPattern = lower.includes("unauthorized") || lower.includes("forbidden") || lower.includes("auth");
1449
- const hasRateLimitPattern = lower.includes("rate limit") || lower.includes("too many requests");
1450
- const hasTransientPattern = lower.includes("timeout") || lower.includes("temporar") || lower.includes("connection reset") || lower.includes("socket") || lower.includes("deadlock");
1451
- if (status === 409 || hasUniquePattern) return "unique_violation";
1452
- if (status === 404 || hasNotFoundPattern) return "not_found";
1453
- if (status === 401 || status === 403 || hasAuthPattern) return "auth";
1454
- if (status === 429 || hasRateLimitPattern) return "rate_limit";
1455
- if (status === 400 || status === 422 || hasValidationPattern) return "validation";
1456
- if (code === "NETWORK_ERROR" || status === 0 || status !== void 0 && status >= 500 || hasTransientPattern) {
1457
- return "transient";
2201
+ function conditionToSqlClause(condition) {
2202
+ if (!condition.column) return null;
2203
+ const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
2204
+ const value = condition.value;
2205
+ const sqlOperator = {
2206
+ eq: "=",
2207
+ neq: "!=",
2208
+ gt: ">",
2209
+ gte: ">=",
2210
+ lt: "<",
2211
+ lte: "<=",
2212
+ like: "LIKE",
2213
+ ilike: "ILIKE"
2214
+ };
2215
+ switch (condition.operator) {
2216
+ case "eq":
2217
+ case "neq":
2218
+ case "gt":
2219
+ case "gte":
2220
+ case "lt":
2221
+ case "lte":
2222
+ case "like":
2223
+ case "ilike": {
2224
+ if (Array.isArray(value) || value === void 0) return null;
2225
+ const rhs = withCast(toSqlLiteral(value), condition.value_cast);
2226
+ return `${column} ${sqlOperator[condition.operator]} ${rhs}`;
2227
+ }
2228
+ case "is": {
2229
+ if (value === null) return `${column} IS NULL`;
2230
+ if (value === true) return `${column} IS TRUE`;
2231
+ if (value === false) return `${column} IS FALSE`;
2232
+ return null;
2233
+ }
2234
+ case "in": {
2235
+ if (!Array.isArray(value)) return null;
2236
+ if (value.length === 0) return "FALSE";
2237
+ const values = value.map((item) => withCast(toSqlLiteral(item), condition.value_cast));
2238
+ return `${column} IN (${values.join(", ")})`;
2239
+ }
2240
+ default:
2241
+ return null;
1458
2242
  }
1459
- return "unknown";
1460
2243
  }
1461
- function toAthenaErrorCode(kind, status, gatewayCode) {
1462
- if (gatewayCode === "NETWORK_ERROR" || kind === "transient" && status === 0) {
1463
- return AthenaErrorCode.NetworkUnavailable;
2244
+ function buildTypedSelectQuery(input) {
2245
+ const whereClauses = [];
2246
+ for (const condition of input.conditions) {
2247
+ const clause = conditionToSqlClause(condition);
2248
+ if (!clause) return null;
2249
+ whereClauses.push(clause);
1464
2250
  }
1465
- switch (kind) {
1466
- case "unique_violation":
1467
- return AthenaErrorCode.UniqueViolation;
1468
- case "not_found":
1469
- return AthenaErrorCode.NotFound;
1470
- case "validation":
1471
- return AthenaErrorCode.ValidationFailed;
1472
- case "rate_limit":
1473
- return AthenaErrorCode.RateLimited;
1474
- case "auth":
1475
- if (status === 403) {
1476
- return AthenaErrorCode.AuthForbidden;
1477
- }
1478
- return AthenaErrorCode.AuthUnauthorized;
1479
- case "transient":
1480
- return status !== void 0 && status >= 500 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.TransientFailure;
1481
- case "unknown":
1482
- default:
1483
- return status !== void 0 && status >= 400 ? AthenaErrorCode.HttpFailure : AthenaErrorCode.Unknown;
2251
+ let limit = input.limit;
2252
+ let offset = input.offset;
2253
+ if (limit === void 0 && input.pageSize !== void 0) {
2254
+ limit = input.pageSize;
2255
+ }
2256
+ if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
2257
+ offset = (input.currentPage - 1) * input.pageSize;
2258
+ }
2259
+ const sqlParts = [
2260
+ `SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
2261
+ ];
2262
+ if (whereClauses.length > 0) {
2263
+ sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
2264
+ }
2265
+ if (input.order?.field) {
2266
+ const direction = input.order.direction === "descending" ? "DESC" : "ASC";
2267
+ sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(input.order.field)} ${direction}`);
2268
+ }
2269
+ if (limit !== void 0) {
2270
+ sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
1484
2271
  }
2272
+ if (offset !== void 0) {
2273
+ sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
2274
+ }
2275
+ return `${sqlParts.join(" ")};`;
2276
+ }
2277
+ function createFilterMethods(state, addCondition, self) {
2278
+ return {
2279
+ eq(column, value) {
2280
+ const columnName = String(column);
2281
+ if (shouldUseUuidTextComparison(columnName, value)) {
2282
+ addCondition("eq", columnName, value, { columnCast: "text" });
2283
+ } else {
2284
+ addCondition("eq", columnName, value);
2285
+ }
2286
+ return self;
2287
+ },
2288
+ eqCast(column, value, cast) {
2289
+ addCondition("eq", String(column), value, { valueCast: cast });
2290
+ return self;
2291
+ },
2292
+ eqUuid(column, value) {
2293
+ addCondition("eq", String(column), value, { valueCast: "uuid" });
2294
+ return self;
2295
+ },
2296
+ match(filters) {
2297
+ Object.entries(filters).forEach(([column, value]) => {
2298
+ if (value === void 0) {
2299
+ return;
2300
+ }
2301
+ if (shouldUseUuidTextComparison(column, value)) {
2302
+ addCondition("eq", column, value, { columnCast: "text" });
2303
+ } else {
2304
+ addCondition("eq", column, value);
2305
+ }
2306
+ });
2307
+ return self;
2308
+ },
2309
+ range(from, to) {
2310
+ state.offset = from;
2311
+ state.limit = to - from + 1;
2312
+ return self;
2313
+ },
2314
+ limit(count) {
2315
+ state.limit = count;
2316
+ return self;
2317
+ },
2318
+ offset(count) {
2319
+ state.offset = count;
2320
+ return self;
2321
+ },
2322
+ currentPage(value) {
2323
+ state.currentPage = value;
2324
+ return self;
2325
+ },
2326
+ pageSize(value) {
2327
+ state.pageSize = value;
2328
+ return self;
2329
+ },
2330
+ totalPages(value) {
2331
+ state.totalPages = value;
2332
+ return self;
2333
+ },
2334
+ order(column, options) {
2335
+ state.order = {
2336
+ field: String(column),
2337
+ direction: options?.ascending === false ? "descending" : "ascending"
2338
+ };
2339
+ return self;
2340
+ },
2341
+ gt(column, value) {
2342
+ addCondition("gt", String(column), value);
2343
+ return self;
2344
+ },
2345
+ gte(column, value) {
2346
+ addCondition("gte", String(column), value);
2347
+ return self;
2348
+ },
2349
+ lt(column, value) {
2350
+ addCondition("lt", String(column), value);
2351
+ return self;
2352
+ },
2353
+ lte(column, value) {
2354
+ addCondition("lte", String(column), value);
2355
+ return self;
2356
+ },
2357
+ neq(column, value) {
2358
+ addCondition("neq", String(column), value);
2359
+ return self;
2360
+ },
2361
+ like(column, value) {
2362
+ addCondition("like", String(column), value);
2363
+ return self;
2364
+ },
2365
+ ilike(column, value) {
2366
+ addCondition("ilike", String(column), value);
2367
+ return self;
2368
+ },
2369
+ is(column, value) {
2370
+ addCondition("is", String(column), value);
2371
+ return self;
2372
+ },
2373
+ in(column, values) {
2374
+ addCondition("in", String(column), values);
2375
+ return self;
2376
+ },
2377
+ contains(column, values) {
2378
+ addCondition("contains", String(column), values);
2379
+ return self;
2380
+ },
2381
+ containedBy(column, values) {
2382
+ addCondition("containedBy", String(column), values);
2383
+ return self;
2384
+ },
2385
+ not(columnOrExpression, operator, value) {
2386
+ const expression = String(columnOrExpression);
2387
+ if (operator != null && value !== void 0) {
2388
+ addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
2389
+ } else {
2390
+ addCondition("not", void 0, expression);
2391
+ }
2392
+ return self;
2393
+ },
2394
+ or(expression) {
2395
+ addCondition("or", void 0, expression);
2396
+ return self;
2397
+ }
2398
+ };
1485
2399
  }
1486
- function toAthenaErrorCategory(kind, status) {
1487
- if (kind === "transient" && (status === 0 || status === void 0)) {
1488
- return AthenaErrorCategory.Transport;
1489
- }
1490
- if (kind === "unique_violation") return AthenaErrorCategory.Database;
1491
- if (kind === "validation" || kind === "auth" || kind === "not_found") return AthenaErrorCategory.Client;
1492
- if (kind === "rate_limit" || kind === "transient") return AthenaErrorCategory.Server;
1493
- return AthenaErrorCategory.Unknown;
2400
+ function toRpcSelect(columns) {
2401
+ if (!columns) return void 0;
2402
+ return Array.isArray(columns) ? columns.join(",") : columns;
1494
2403
  }
1495
- function isRetryable(kind, status) {
1496
- if (kind === "rate_limit" || kind === "transient") return true;
1497
- return status !== void 0 && status >= 500;
2404
+ function createRpcFilterMethods(filters, self) {
2405
+ const addFilter = (operator, column, value) => {
2406
+ filters.push({ column, operator, value });
2407
+ };
2408
+ return {
2409
+ eq(column, value) {
2410
+ addFilter("eq", column, value);
2411
+ return self;
2412
+ },
2413
+ neq(column, value) {
2414
+ addFilter("neq", column, value);
2415
+ return self;
2416
+ },
2417
+ gt(column, value) {
2418
+ addFilter("gt", column, value);
2419
+ return self;
2420
+ },
2421
+ gte(column, value) {
2422
+ addFilter("gte", column, value);
2423
+ return self;
2424
+ },
2425
+ lt(column, value) {
2426
+ addFilter("lt", column, value);
2427
+ return self;
2428
+ },
2429
+ lte(column, value) {
2430
+ addFilter("lte", column, value);
2431
+ return self;
2432
+ },
2433
+ like(column, value) {
2434
+ addFilter("like", column, value);
2435
+ return self;
2436
+ },
2437
+ ilike(column, value) {
2438
+ addFilter("ilike", column, value);
2439
+ return self;
2440
+ },
2441
+ is(column, value) {
2442
+ addFilter("is", column, value);
2443
+ return self;
2444
+ },
2445
+ in(column, values) {
2446
+ addFilter("in", column, values);
2447
+ return self;
2448
+ }
2449
+ };
1498
2450
  }
1499
- function toGatewayCode(kind, status) {
1500
- if (kind === "transient" && (status === 0 || status === void 0)) return "NETWORK_ERROR";
1501
- if (kind === "validation") return "INVALID_JSON";
1502
- if (status !== void 0 && status >= 400) return "HTTP_ERROR";
1503
- return "UNKNOWN_ERROR";
2451
+ function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult) {
2452
+ const state = {
2453
+ filters: []
2454
+ };
2455
+ let selectedColumns;
2456
+ let selectedOptions;
2457
+ let promise = null;
2458
+ const executeRpc = async (columns, options) => {
2459
+ const mergedOptions = mergeOptions(baseOptions, options);
2460
+ const payload = {
2461
+ function: functionName,
2462
+ args,
2463
+ schema: mergedOptions?.schema,
2464
+ select: toRpcSelect(columns),
2465
+ filters: state.filters.length ? [...state.filters] : void 0,
2466
+ count: mergedOptions?.count,
2467
+ head: mergedOptions?.head,
2468
+ limit: state.limit,
2469
+ offset: state.offset,
2470
+ order: state.order
2471
+ };
2472
+ const response = await client.rpcGateway(payload, mergedOptions);
2473
+ return formatGatewayResult(response, { operation: "rpc" });
2474
+ };
2475
+ const run = (columns, options) => {
2476
+ const payloadColumns = columns ?? selectedColumns;
2477
+ const payloadOptions = options ?? selectedOptions;
2478
+ if (!promise) {
2479
+ promise = executeRpc(payloadColumns, payloadOptions);
2480
+ }
2481
+ return promise;
2482
+ };
2483
+ const builder = {};
2484
+ const filterMethods = createRpcFilterMethods(state.filters, builder);
2485
+ Object.assign(builder, filterMethods, {
2486
+ select(columns = selectedColumns, options) {
2487
+ selectedColumns = columns;
2488
+ selectedOptions = options ?? selectedOptions;
2489
+ return run(columns, options);
2490
+ },
2491
+ async single(columns, options) {
2492
+ const result = await run(columns, options);
2493
+ return toSingleResult(result);
2494
+ },
2495
+ maybeSingle(columns, options) {
2496
+ return builder.single(columns, options);
2497
+ },
2498
+ order(column, options) {
2499
+ state.order = { column, ascending: options?.ascending ?? true };
2500
+ return builder;
2501
+ },
2502
+ limit(count) {
2503
+ state.limit = count;
2504
+ return builder;
2505
+ },
2506
+ offset(count) {
2507
+ state.offset = count;
2508
+ return builder;
2509
+ },
2510
+ range(from, to) {
2511
+ state.offset = from;
2512
+ state.limit = to - from + 1;
2513
+ return builder;
2514
+ },
2515
+ then(onfulfilled, onrejected) {
2516
+ return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
2517
+ },
2518
+ catch(onrejected) {
2519
+ return run(selectedColumns, selectedOptions).catch(onrejected);
2520
+ },
2521
+ finally(onfinally) {
2522
+ return run(selectedColumns, selectedOptions).finally(onfinally);
2523
+ }
2524
+ });
2525
+ return builder;
1504
2526
  }
1505
- function toAthenaGatewayError(source, fallbackMessage, context) {
1506
- if (isAthenaGatewayError(source)) {
1507
- return source;
1508
- }
1509
- if (isAthenaResultLike(source) && source.errorDetails) {
1510
- return new AthenaGatewayError({
1511
- code: source.errorDetails.code,
1512
- message: source.error ?? source.errorDetails.message,
1513
- status: source.status,
1514
- endpoint: source.errorDetails.endpoint,
1515
- method: source.errorDetails.method,
1516
- requestId: source.errorDetails.requestId,
1517
- hint: source.errorDetails.hint,
1518
- cause: source.errorDetails.cause
2527
+ function createTableBuilder(tableName, client, formatGatewayResult) {
2528
+ const state = {
2529
+ conditions: []
2530
+ };
2531
+ const addCondition = (operator, column, value, hints) => {
2532
+ const condition = { operator };
2533
+ if (column) {
2534
+ condition.column = column;
2535
+ if (operator === "eq") {
2536
+ condition.eq_column = column;
2537
+ }
2538
+ }
2539
+ if (value !== void 0) {
2540
+ condition.value = value;
2541
+ if (operator === "eq") {
2542
+ condition.eq_value = value;
2543
+ }
2544
+ }
2545
+ if (hints?.valueCast) {
2546
+ condition.value_cast = hints.valueCast;
2547
+ if (operator === "eq") {
2548
+ condition.eq_value_cast = hints.valueCast;
2549
+ }
2550
+ }
2551
+ if (hints?.columnCast) {
2552
+ condition.column_cast = hints.columnCast;
2553
+ if (operator === "eq") {
2554
+ condition.eq_column_cast = hints.columnCast;
2555
+ }
2556
+ }
2557
+ state.conditions.push(condition);
2558
+ };
2559
+ const builder = {};
2560
+ const filterMethods = createFilterMethods(
2561
+ state,
2562
+ addCondition,
2563
+ builder
2564
+ );
2565
+ const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
2566
+ const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
2567
+ const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
2568
+ const hasTypedEqualityComparison = conditions?.some(
2569
+ (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
2570
+ ) ?? false;
2571
+ if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
2572
+ const query = buildTypedSelectQuery({
2573
+ tableName: resolvedTableName,
2574
+ columns,
2575
+ conditions,
2576
+ limit: state.limit,
2577
+ offset: state.offset,
2578
+ currentPage: state.currentPage,
2579
+ pageSize: state.pageSize,
2580
+ order: state.order
2581
+ });
2582
+ if (query) {
2583
+ const queryResponse = await client.queryGateway({ query }, options);
2584
+ return formatGatewayResult(queryResponse, { table: resolvedTableName, operation: "select" });
2585
+ }
2586
+ }
2587
+ const payload = {
2588
+ table_name: resolvedTableName,
2589
+ columns,
2590
+ conditions,
2591
+ limit: state.limit,
2592
+ offset: state.offset,
2593
+ current_page: state.currentPage,
2594
+ page_size: state.pageSize,
2595
+ total_pages: state.totalPages,
2596
+ sort_by: state.order,
2597
+ strip_nulls: options?.stripNulls ?? true,
2598
+ count: options?.count,
2599
+ head: options?.head
2600
+ };
2601
+ const response = await client.fetchGateway(payload, options);
2602
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "select" });
2603
+ };
2604
+ const createSelectChain = (columns, options) => {
2605
+ const chain = {};
2606
+ const filterMethods2 = createFilterMethods(state, addCondition, chain);
2607
+ Object.assign(chain, filterMethods2, {
2608
+ async single(cols, opts) {
2609
+ const r = await runSelect(cols ?? columns, opts ?? options);
2610
+ return toSingleResult(r);
2611
+ },
2612
+ maybeSingle(cols, opts) {
2613
+ return chain.single(cols, opts);
2614
+ },
2615
+ then(onfulfilled, onrejected) {
2616
+ return runSelect(columns, options).then(onfulfilled, onrejected);
2617
+ },
2618
+ catch(onrejected) {
2619
+ return runSelect(columns, options).catch(onrejected);
2620
+ },
2621
+ finally(onfinally) {
2622
+ return runSelect(columns, options).finally(onfinally);
2623
+ }
1519
2624
  });
1520
- }
1521
- const normalized = normalizeAthenaError(source, context);
1522
- const message = isAthenaResultLike(source) && source.error == null && source.errorDetails == null ? fallbackMessage : normalized.message || fallbackMessage;
1523
- return new AthenaGatewayError({
1524
- code: toGatewayCode(normalized.kind, normalized.status),
1525
- message,
1526
- status: normalized.status ?? 0,
1527
- hint: normalized.constraint != null ? `Constraint: ${normalized.constraint}` : contextHint(context),
1528
- cause: typeof normalized.raw === "string" ? normalized.raw : safeStringify(normalized.raw)
2625
+ return chain;
2626
+ };
2627
+ Object.assign(builder, filterMethods, {
2628
+ reset() {
2629
+ state.conditions = [];
2630
+ state.limit = void 0;
2631
+ state.offset = void 0;
2632
+ state.order = void 0;
2633
+ state.currentPage = void 0;
2634
+ state.pageSize = void 0;
2635
+ state.totalPages = void 0;
2636
+ return builder;
2637
+ },
2638
+ select(columns = DEFAULT_COLUMNS, options) {
2639
+ return createSelectChain(columns, options);
2640
+ },
2641
+ insert(values, options) {
2642
+ if (Array.isArray(values)) {
2643
+ const executeInsertMany = async (columns, selectOptions) => {
2644
+ const mergedOptions = mergeOptions(options, selectOptions);
2645
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2646
+ const payload = {
2647
+ table_name: resolvedTableName,
2648
+ insert_body: asAthenaJsonObjectArray(values)
2649
+ };
2650
+ if (columns) payload.columns = columns;
2651
+ if (mergedOptions?.count) payload.count = mergedOptions.count;
2652
+ if (mergedOptions?.head) payload.head = mergedOptions.head;
2653
+ if (mergedOptions?.defaultToNull !== void 0) {
2654
+ payload.default_to_null = mergedOptions.defaultToNull;
2655
+ }
2656
+ const response = await client.insertGateway(payload, mergedOptions);
2657
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
2658
+ };
2659
+ return createMutationQuery(executeInsertMany);
2660
+ }
2661
+ const executeInsertOne = async (columns, selectOptions) => {
2662
+ const mergedOptions = mergeOptions(options, selectOptions);
2663
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2664
+ const payload = {
2665
+ table_name: resolvedTableName,
2666
+ insert_body: asAthenaJsonObject(values)
2667
+ };
2668
+ if (columns) payload.columns = columns;
2669
+ if (mergedOptions?.count) payload.count = mergedOptions.count;
2670
+ if (mergedOptions?.head) payload.head = mergedOptions.head;
2671
+ if (mergedOptions?.defaultToNull !== void 0) {
2672
+ payload.default_to_null = mergedOptions.defaultToNull;
2673
+ }
2674
+ const response = await client.insertGateway(payload, mergedOptions);
2675
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
2676
+ };
2677
+ return createMutationQuery(executeInsertOne);
2678
+ },
2679
+ upsert(values, options) {
2680
+ if (Array.isArray(values)) {
2681
+ const executeUpsertMany = async (columns, selectOptions) => {
2682
+ const mergedOptions = mergeOptions(options, selectOptions);
2683
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2684
+ const payload = {
2685
+ table_name: resolvedTableName,
2686
+ insert_body: asAthenaJsonObjectArray(values),
2687
+ update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
2688
+ };
2689
+ if (columns) payload.columns = columns;
2690
+ if (options?.onConflict) payload.on_conflict = options.onConflict;
2691
+ if (mergedOptions?.count) payload.count = mergedOptions.count;
2692
+ if (mergedOptions?.head) payload.head = mergedOptions.head;
2693
+ if (mergedOptions?.defaultToNull !== void 0) {
2694
+ payload.default_to_null = mergedOptions.defaultToNull;
2695
+ }
2696
+ const response = await client.insertGateway(payload, mergedOptions);
2697
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
2698
+ };
2699
+ return createMutationQuery(executeUpsertMany);
2700
+ }
2701
+ const executeUpsertOne = async (columns, selectOptions) => {
2702
+ const mergedOptions = mergeOptions(options, selectOptions);
2703
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2704
+ const payload = {
2705
+ table_name: resolvedTableName,
2706
+ insert_body: asAthenaJsonObject(values),
2707
+ update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
2708
+ };
2709
+ if (columns) payload.columns = columns;
2710
+ if (options?.onConflict) payload.on_conflict = options.onConflict;
2711
+ if (mergedOptions?.count) payload.count = mergedOptions.count;
2712
+ if (mergedOptions?.head) payload.head = mergedOptions.head;
2713
+ if (mergedOptions?.defaultToNull !== void 0) {
2714
+ payload.default_to_null = mergedOptions.defaultToNull;
2715
+ }
2716
+ const response = await client.insertGateway(payload, mergedOptions);
2717
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "insert" });
2718
+ };
2719
+ return createMutationQuery(executeUpsertOne);
2720
+ },
2721
+ update(values, options) {
2722
+ const executeUpdate = async (columns, selectOptions) => {
2723
+ const filters = state.conditions.length ? [...state.conditions] : void 0;
2724
+ const mergedOptions = mergeOptions(options, selectOptions);
2725
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2726
+ const payload = {
2727
+ table_name: resolvedTableName,
2728
+ set: asAthenaJsonObject(values),
2729
+ conditions: filters,
2730
+ strip_nulls: mergedOptions?.stripNulls ?? true
2731
+ };
2732
+ if (state.order) payload.sort_by = state.order;
2733
+ if (state.currentPage !== void 0) payload.current_page = state.currentPage;
2734
+ if (state.pageSize !== void 0) payload.page_size = state.pageSize;
2735
+ if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
2736
+ if (columns) payload.columns = columns;
2737
+ const response = await client.updateGateway(payload, mergedOptions);
2738
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "update" });
2739
+ };
2740
+ const mutation = createMutationQuery(executeUpdate, null);
2741
+ const updateChain = {};
2742
+ const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
2743
+ Object.assign(updateChain, filterMethods2, mutation);
2744
+ return updateChain;
2745
+ },
2746
+ delete(options) {
2747
+ const filters = state.conditions.length ? [...state.conditions] : void 0;
2748
+ const resourceId = options?.resourceId ?? getResourceId(state);
2749
+ if (!resourceId && !filters?.length) {
2750
+ throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
2751
+ }
2752
+ const executeDelete = async (columns, selectOptions) => {
2753
+ const mergedOptions = mergeOptions(options, selectOptions);
2754
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
2755
+ const payload = {
2756
+ table_name: resolvedTableName,
2757
+ resource_id: resourceId,
2758
+ conditions: filters
2759
+ };
2760
+ if (state.order) payload.sort_by = state.order;
2761
+ if (state.currentPage !== void 0) payload.current_page = state.currentPage;
2762
+ if (state.pageSize !== void 0) payload.page_size = state.pageSize;
2763
+ if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
2764
+ if (columns) payload.columns = columns;
2765
+ const response = await client.deleteGateway(payload, mergedOptions);
2766
+ return formatGatewayResult(response, { table: resolvedTableName, operation: "delete" });
2767
+ };
2768
+ return createMutationQuery(executeDelete, null);
2769
+ },
2770
+ async single(columns, options) {
2771
+ const response = await builder.select(columns, options);
2772
+ return toSingleResult(response);
2773
+ },
2774
+ async maybeSingle(columns, options) {
2775
+ return builder.single(columns, options);
2776
+ }
1529
2777
  });
2778
+ return builder;
1530
2779
  }
1531
- function isOk(result) {
1532
- return result.error == null && result.status >= 200 && result.status < 300;
2780
+ function createQueryBuilder(client, formatGatewayResult) {
2781
+ return async function query(query, options) {
2782
+ const normalizedQuery = query.trim();
2783
+ if (!normalizedQuery) {
2784
+ throw new Error("query requires a non-empty string");
2785
+ }
2786
+ const response = await client.queryGateway({ query: normalizedQuery }, options);
2787
+ return formatGatewayResult(response, { operation: "query" });
2788
+ };
1533
2789
  }
1534
- function normalizeAthenaError(resultOrError, context) {
1535
- if (isAthenaResultLike(resultOrError)) {
1536
- const details = resultOrError.errorDetails;
1537
- const message2 = resultOrError.error ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
1538
- const operation = context?.operation ?? operationFromDetails(details);
1539
- const table = context?.table ?? extractTable(message2);
1540
- const constraint = extractConstraint(message2);
1541
- const kind2 = classifyKind(resultOrError.status, details?.code, message2);
1542
- const code = toAthenaErrorCode(kind2, resultOrError.status, details?.code);
1543
- const category = toAthenaErrorCategory(kind2, resultOrError.status);
1544
- return {
1545
- kind: kind2,
1546
- code,
1547
- category,
1548
- retryable: isRetryable(kind2, resultOrError.status),
1549
- status: resultOrError.status,
1550
- constraint,
1551
- table,
1552
- operation,
1553
- message: message2,
1554
- raw: resultOrError.raw
1555
- };
1556
- }
1557
- if (isAthenaGatewayError(resultOrError)) {
1558
- const details = resultOrError.toDetails();
1559
- const operation = context?.operation ?? operationFromDetails(details);
1560
- const table = context?.table ?? extractTable(resultOrError.message);
1561
- const constraint = extractConstraint(resultOrError.message);
1562
- const kind2 = classifyKind(resultOrError.status, resultOrError.code, resultOrError.message);
1563
- const code = toAthenaErrorCode(kind2, resultOrError.status, resultOrError.code);
1564
- const category = toAthenaErrorCategory(kind2, resultOrError.status);
1565
- return {
1566
- kind: kind2,
1567
- code,
1568
- category,
1569
- retryable: isRetryable(kind2, resultOrError.status),
1570
- status: resultOrError.status,
1571
- constraint,
1572
- table,
1573
- operation,
1574
- message: resultOrError.message,
1575
- raw: resultOrError
1576
- };
1577
- }
1578
- if (resultOrError instanceof Error) {
1579
- const maybeStatus = isRecord2(resultOrError) && typeof resultOrError.status === "number" ? resultOrError.status : void 0;
1580
- const kind2 = classifyKind(maybeStatus, void 0, resultOrError.message);
1581
- return {
1582
- kind: kind2,
1583
- code: toAthenaErrorCode(kind2, maybeStatus),
1584
- category: toAthenaErrorCategory(kind2, maybeStatus),
1585
- retryable: isRetryable(kind2, maybeStatus),
1586
- status: maybeStatus,
1587
- constraint: extractConstraint(resultOrError.message),
1588
- table: context?.table ?? extractTable(resultOrError.message),
1589
- operation: context?.operation,
1590
- message: resultOrError.message,
1591
- raw: resultOrError
1592
- };
1593
- }
1594
- const message = typeof resultOrError === "string" ? resultOrError : "Unknown Athena error";
1595
- const kind = classifyKind(void 0, void 0, message);
2790
+ function createClientFromConfig(config) {
2791
+ const gateway = createAthenaGatewayClient({
2792
+ baseUrl: config.baseUrl,
2793
+ apiKey: config.apiKey,
2794
+ client: config.client,
2795
+ backend: config.backend,
2796
+ headers: config.headers
2797
+ });
2798
+ const formatGatewayResult = createResultFormatter(config.experimental);
2799
+ const auth = createAuthClient(config.auth);
2800
+ const from = (table) => createTableBuilder(table, gateway, formatGatewayResult);
2801
+ const rpc = (fn, args, options) => {
2802
+ const normalizedFn = fn.trim();
2803
+ if (!normalizedFn) {
2804
+ throw new Error("rpc requires a function name");
2805
+ }
2806
+ return createRpcBuilder(
2807
+ normalizedFn,
2808
+ args,
2809
+ options,
2810
+ gateway,
2811
+ formatGatewayResult
2812
+ );
2813
+ };
2814
+ const query = createQueryBuilder(gateway, formatGatewayResult);
2815
+ const db = createDbModule({ from, rpc, query });
1596
2816
  return {
1597
- kind,
1598
- code: toAthenaErrorCode(kind, void 0),
1599
- category: toAthenaErrorCategory(kind, void 0),
1600
- retryable: isRetryable(kind, void 0),
1601
- status: void 0,
1602
- constraint: extractConstraint(message),
1603
- table: context?.table ?? extractTable(message),
1604
- operation: context?.operation,
1605
- message,
1606
- raw: resultOrError
2817
+ from,
2818
+ db,
2819
+ rpc,
2820
+ query,
2821
+ auth: auth.auth
1607
2822
  };
1608
2823
  }
1609
- function unwrapRows(result, options) {
1610
- if (!isOk(result)) {
1611
- throw toAthenaGatewayError(result, "Athena request failed", options?.context);
1612
- }
1613
- if (result.data == null) return [];
1614
- return Array.isArray(result.data) ? result.data : [result.data];
2824
+ var DEFAULT_BACKEND = { type: "athena" };
2825
+ function toBackendConfig(b) {
2826
+ if (!b) return DEFAULT_BACKEND;
2827
+ return typeof b === "string" ? { type: b } : b;
1615
2828
  }
1616
- function unwrap(result, options) {
1617
- if (!isOk(result)) {
1618
- throw toAthenaGatewayError(result, "Athena request failed", options?.context);
2829
+ var AthenaClientBuilderImpl = class {
2830
+ baseUrl;
2831
+ apiKey;
2832
+ backendConfig = DEFAULT_BACKEND;
2833
+ clientName;
2834
+ defaultHeaders;
2835
+ isHealthTrackingEnabled = false;
2836
+ url(url) {
2837
+ this.baseUrl = url;
2838
+ return this;
1619
2839
  }
1620
- if (result.data == null && !options?.allowNull) {
1621
- throw toAthenaGatewayError(result, "Expected data but received null", options?.context);
2840
+ key(apiKey) {
2841
+ this.apiKey = apiKey;
2842
+ return this;
1622
2843
  }
1623
- return result.data;
1624
- }
1625
- function unwrapOne(result, options) {
1626
- const rows = unwrapRows(result, options);
1627
- if (!rows.length) {
1628
- if (options?.allowNull) return null;
1629
- throw toAthenaGatewayError(result, "Expected one row but received none", options?.context);
2844
+ backend(backend) {
2845
+ this.backendConfig = toBackendConfig(backend);
2846
+ return this;
1630
2847
  }
1631
- if (options?.requireExactlyOne && rows.length !== 1) {
1632
- throw toAthenaGatewayError(
1633
- result,
1634
- `Expected exactly one row but received ${rows.length}`,
1635
- options.context
1636
- );
2848
+ client(clientName) {
2849
+ this.clientName = clientName;
2850
+ return this;
1637
2851
  }
1638
- return rows[0];
1639
- }
1640
- function requireSuccess(result, context) {
1641
- if (!isOk(result)) {
1642
- throw toAthenaGatewayError(
1643
- result,
1644
- `Athena ${context?.operation ?? "request"} failed`,
1645
- context
1646
- );
2852
+ headers(headers) {
2853
+ this.defaultHeaders = headers;
2854
+ return this;
1647
2855
  }
1648
- return result;
1649
- }
1650
- function requireAffected(result, options, context) {
1651
- requireSuccess(result, context);
1652
- const minimum = options?.min ?? 1;
1653
- const count = result.count;
1654
- if (count == null) {
1655
- throw new AthenaGatewayError({
1656
- code: "UNKNOWN_ERROR",
1657
- status: result.status,
1658
- message: "Expected affected row count but response.count is missing",
1659
- hint: 'Set call option { count: "exact" } for mutation postcondition checks.',
1660
- cause: safeStringify(result.raw)
1661
- });
2856
+ healthTracking(enabled) {
2857
+ this.isHealthTrackingEnabled = enabled;
2858
+ return this;
1662
2859
  }
1663
- if (count < minimum) {
1664
- throw new AthenaGatewayError({
1665
- code: "UNKNOWN_ERROR",
1666
- status: result.status,
1667
- message: `Expected at least ${minimum} affected rows but received ${count}`,
1668
- hint: contextHint(context),
1669
- cause: safeStringify(result.raw)
2860
+ build() {
2861
+ if (!this.baseUrl || !this.apiKey) {
2862
+ throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
2863
+ }
2864
+ return createClientFromConfig({
2865
+ baseUrl: this.baseUrl,
2866
+ apiKey: this.apiKey,
2867
+ client: this.clientName,
2868
+ backend: this.backendConfig,
2869
+ headers: this.defaultHeaders,
2870
+ healthTracking: this.isHealthTrackingEnabled
1670
2871
  });
1671
2872
  }
1672
- return count;
1673
- }
1674
- function applyBounds(value, options) {
1675
- if (options?.min !== void 0 && value < options.min) return null;
1676
- if (options?.max !== void 0 && value > options.max) return null;
1677
- return value;
1678
- }
1679
- function parseIntegerString(value) {
1680
- const normalized = value.trim();
1681
- if (!/^[-+]?\d+$/.test(normalized)) return null;
1682
- const parsed = Number(normalized);
1683
- if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;
1684
- return parsed;
1685
- }
1686
- function coerceInt(value, options) {
1687
- if (value == null) return null;
1688
- if (typeof value === "number") {
1689
- if (!Number.isFinite(value) || !Number.isInteger(value)) return null;
1690
- return applyBounds(value, options);
1691
- }
1692
- if (typeof value === "string") {
1693
- const parsed = parseIntegerString(value);
1694
- if (parsed == null) return null;
1695
- return applyBounds(parsed, options);
2873
+ };
2874
+ var AthenaClient = class _AthenaClient {
2875
+ /** Create a fluent builder for a strongly-typed Athena SDK client. */
2876
+ static builder() {
2877
+ return new AthenaClientBuilderImpl();
1696
2878
  }
1697
- if (typeof value === "bigint") {
1698
- if (options?.strictBigInt) {
1699
- if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER)) {
1700
- return null;
1701
- }
2879
+ /** Build a client from process environment variables. */
2880
+ static fromEnvironment() {
2881
+ const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
2882
+ const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
2883
+ if (!url || !key) {
2884
+ throw new Error(
2885
+ "ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
2886
+ );
1702
2887
  }
1703
- const parsed = Number(value);
1704
- if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;
1705
- return applyBounds(parsed, options);
1706
- }
1707
- return null;
1708
- }
1709
- function assertInt(value, label = "value", options) {
1710
- const parsed = coerceInt(value, options);
1711
- if (parsed == null) {
1712
- throw new TypeError(`${label} must be a finite integer`);
2888
+ return _AthenaClient.builder().url(url).key(key).build();
1713
2889
  }
1714
- return parsed;
1715
- }
1716
- function defaultShouldRetry(error) {
1717
- const normalized = normalizeAthenaError(error);
1718
- return normalized.kind === "transient" || normalized.kind === "rate_limit";
1719
- }
1720
- function computeDelayMs(attempt, error, config) {
1721
- const baseDelay = config.baseDelayMs;
1722
- const rawDelay = typeof config.backoff === "function" ? config.backoff(attempt, error) : config.backoff === "linear" ? baseDelay * attempt : baseDelay * Math.pow(2, attempt - 1);
1723
- const safeDelay = Number.isFinite(rawDelay) ? Math.max(0, rawDelay) : 0;
1724
- const clamped = Math.min(config.maxDelayMs, safeDelay);
1725
- const jitterFactor = typeof config.jitter === "number" ? Math.max(0, Math.min(1, config.jitter)) : config.jitter ? 0.2 : 0;
1726
- if (!jitterFactor) return clamped;
1727
- const deviation = clamped * jitterFactor;
1728
- const offset = (Math.random() * 2 - 1) * deviation;
1729
- return Math.max(0, clamped + offset);
1730
- }
1731
- function sleep(ms) {
1732
- if (ms <= 0) return Promise.resolve();
1733
- return new Promise((resolve3) => {
1734
- setTimeout(resolve3, ms);
2890
+ };
2891
+ function createClient(url, apiKey, options) {
2892
+ return createClientFromConfig({
2893
+ baseUrl: url,
2894
+ apiKey,
2895
+ client: options?.client,
2896
+ backend: toBackendConfig(options?.backend),
2897
+ headers: options?.headers,
2898
+ auth: options?.auth,
2899
+ experimental: options?.experimental
1735
2900
  });
1736
2901
  }
1737
- async function withRetry(config, fn) {
1738
- const retries = Math.max(0, Math.trunc(config.retries));
1739
- const shouldRetry = config.shouldRetry ?? defaultShouldRetry;
1740
- const resolvedConfig = {
1741
- baseDelayMs: config.baseDelayMs ?? 100,
1742
- maxDelayMs: config.maxDelayMs ?? 1e4,
1743
- backoff: config.backoff ?? "exponential",
1744
- jitter: config.jitter ?? false
1745
- };
1746
- for (let attempts = 0; attempts <= retries; attempts += 1) {
1747
- try {
1748
- return await fn();
1749
- } catch (error) {
1750
- if (attempts >= retries) {
1751
- throw error;
1752
- }
1753
- const currentAttempt = attempts + 1;
1754
- const retry = await shouldRetry(error, currentAttempt);
1755
- if (!retry) {
1756
- throw error;
1757
- }
1758
- const delay = computeDelayMs(currentAttempt, error, resolvedConfig);
1759
- await sleep(delay);
1760
- }
1761
- }
1762
- throw new Error("withRetry reached an unexpected state");
1763
- }
2902
+
2903
+ // src/gateway/types.ts
2904
+ var Backend = {
2905
+ Athena: { type: "athena" },
2906
+ Postgrest: { type: "postgrest" },
2907
+ PostgreSQL: { type: "postgresql" },
2908
+ ScyllaDB: { type: "scylladb" }
2909
+ };
1764
2910
 
1765
2911
  // src/schema/definitions.ts
1766
2912
  function defineModel(input) {
@@ -1827,6 +2973,7 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
1827
2973
  registry;
1828
2974
  tenantKeyMap;
1829
2975
  tenantContext;
2976
+ db;
1830
2977
  baseClient;
1831
2978
  registryNavigator;
1832
2979
  tenantHeaderMapper;
@@ -1853,6 +3000,7 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
1853
3000
  client: this.clientOptions.client,
1854
3001
  headers: this.tenantHeaderMapper.apply(this.clientOptions.headers, tenantContext)
1855
3002
  });
3003
+ this.db = this.baseClient.db;
1856
3004
  }
1857
3005
  from(table) {
1858
3006
  return this.baseClient.from(table);
@@ -2242,6 +3390,21 @@ var PostgresCatalogSnapshotAssembler = class {
2242
3390
  };
2243
3391
 
2244
3392
  // src/schema/postgres-provider.ts
3393
+ var pgPoolConstructorPromise;
3394
+ async function loadPgPoolConstructor() {
3395
+ if (!pgPoolConstructorPromise) {
3396
+ pgPoolConstructorPromise = import('pg').then((module) => {
3397
+ const poolConstructor = module.Pool ?? module.default?.Pool;
3398
+ if (!poolConstructor) {
3399
+ throw new Error(
3400
+ '@xylex-group/athena: Unable to load the PostgreSQL driver. Ensure "pg" is installed and this API runs in a Node.js server runtime.'
3401
+ );
3402
+ }
3403
+ return poolConstructor;
3404
+ });
3405
+ }
3406
+ return pgPoolConstructorPromise;
3407
+ }
2245
3408
  var PgCatalogClient = class {
2246
3409
  constructor(pool) {
2247
3410
  this.pool = pool;
@@ -2281,7 +3444,8 @@ var PostgresIntrospectionProvider = class {
2281
3444
  }
2282
3445
  async inspect(options) {
2283
3446
  const schemas = options?.schemas && options.schemas.length > 0 ? normalizePostgresCatalogSchemas(options.schemas) : this.schemas;
2284
- const pool = new pg.Pool({
3447
+ const PoolConstructor = await loadPgPoolConstructor();
3448
+ const pool = new PoolConstructor({
2285
3449
  connectionString: this.connectionString
2286
3450
  });
2287
3451
  const catalogClient = new PgCatalogClient(pool);
@@ -2318,7 +3482,7 @@ function resolveNullishValue(mode) {
2318
3482
  if (mode === "null") return null;
2319
3483
  return "";
2320
3484
  }
2321
- function isRecord3(value) {
3485
+ function isRecord4(value) {
2322
3486
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2323
3487
  }
2324
3488
  function isNullableColumn(model, key) {
@@ -2327,7 +3491,7 @@ function isNullableColumn(model, key) {
2327
3491
  }
2328
3492
  function toModelFormDefaults(model, values, options) {
2329
3493
  const source = values;
2330
- if (!isRecord3(source)) {
3494
+ if (!isRecord4(source)) {
2331
3495
  return {};
2332
3496
  }
2333
3497
  const mode = options?.nullishMode ?? "empty-string";
@@ -2403,6 +3567,7 @@ function resolveProviderSchemas(providerConfig) {
2403
3567
  }
2404
3568
 
2405
3569
  // src/generator/config.ts
3570
+ var POSTGRES_PROTOCOLS = /* @__PURE__ */ new Set(["postgres:", "postgresql:"]);
2406
3571
  var DEFAULT_CONFIG_CANDIDATES = [
2407
3572
  "athena.config.ts",
2408
3573
  "athena.config.js",
@@ -2432,6 +3597,184 @@ var DEFAULT_EXPERIMENTAL_FLAGS = {
2432
3597
  postgresGatewayIntrospection: false,
2433
3598
  scyllaProviderContracts: true
2434
3599
  };
3600
+ var PROJECT_ENV_FILENAMES = [".env", ".env.local"];
3601
+ var DIRECT_CONNECTION_STRING_ENV_KEYS = [
3602
+ "ATHENA_GENERATOR_PG_URL",
3603
+ "DATABASE_URL",
3604
+ "PG_URL",
3605
+ "POSTGRES_URL",
3606
+ "POSTGRESQL_URL"
3607
+ ];
3608
+ var POSTGRES_DATABASE_ENV_KEYS = ["ATHENA_GENERATOR_DB", "ATHENA_DATABASE", "PGDATABASE"];
3609
+ var POSTGRES_PASSWORD_ENV_KEYS = ["ATHENA_GENERATOR_PG_PASSWORD", "PGPASSWORD"];
3610
+ var GATEWAY_URL_ENV_KEYS = ["ATHENA_URL", "ATHENA_GATEWAY_URL", "ATHENA_GENERATOR_URL"];
3611
+ var GATEWAY_API_KEY_ENV_KEYS = [
3612
+ "ATHENA_API_KEY",
3613
+ "ATHENA_GATEWAY_API_KEY",
3614
+ "ATHENA_GENERATOR_API_KEY"
3615
+ ];
3616
+ function normalizeRawEnvValue(rawValue) {
3617
+ if (rawValue.startsWith('"') && rawValue.endsWith('"') && rawValue.length >= 2) {
3618
+ const inner = rawValue.slice(1, -1);
3619
+ return inner.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
3620
+ }
3621
+ if (rawValue.startsWith("'") && rawValue.endsWith("'") && rawValue.length >= 2) {
3622
+ return rawValue.slice(1, -1);
3623
+ }
3624
+ const commentIndex = rawValue.search(/\s+#/);
3625
+ const withoutComment = commentIndex >= 0 ? rawValue.slice(0, commentIndex) : rawValue;
3626
+ return withoutComment.trim();
3627
+ }
3628
+ function parseEnvLine(line) {
3629
+ const trimmed = line.trim();
3630
+ if (!trimmed || trimmed.startsWith("#")) {
3631
+ return void 0;
3632
+ }
3633
+ const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
3634
+ if (!match) {
3635
+ return void 0;
3636
+ }
3637
+ const [, key, rawValue] = match;
3638
+ return [key, normalizeRawEnvValue(rawValue.trim())];
3639
+ }
3640
+ function readProjectEnvEntries(cwd) {
3641
+ const nodeEnv = process.env.NODE_ENV?.trim();
3642
+ const filenames = [
3643
+ ...PROJECT_ENV_FILENAMES,
3644
+ ...nodeEnv ? [`.env.${nodeEnv}`, `.env.${nodeEnv}.local`] : []
3645
+ ];
3646
+ const entries = /* @__PURE__ */ new Map();
3647
+ for (const filename of filenames) {
3648
+ const absolutePath = path.resolve(cwd, filename);
3649
+ if (!fs.existsSync(absolutePath)) {
3650
+ continue;
3651
+ }
3652
+ const content = fs.readFileSync(absolutePath, "utf8");
3653
+ const lines = content.split(/\r?\n/g);
3654
+ for (const line of lines) {
3655
+ const parsed = parseEnvLine(line);
3656
+ if (!parsed) {
3657
+ continue;
3658
+ }
3659
+ const [key, value] = parsed;
3660
+ entries.set(key, value);
3661
+ }
3662
+ }
3663
+ return entries;
3664
+ }
3665
+ function applyProjectEnv(cwd) {
3666
+ const envEntries = readProjectEnvEntries(cwd);
3667
+ if (envEntries.size === 0) {
3668
+ return () => {
3669
+ };
3670
+ }
3671
+ const initialKeys = new Set(
3672
+ Object.keys(process.env).filter((key) => process.env[key] !== void 0)
3673
+ );
3674
+ const staged = /* @__PURE__ */ new Map();
3675
+ for (const [key, value] of envEntries.entries()) {
3676
+ if (initialKeys.has(key)) {
3677
+ continue;
3678
+ }
3679
+ staged.set(key, value);
3680
+ }
3681
+ for (const [key, value] of staged.entries()) {
3682
+ process.env[key] = value;
3683
+ }
3684
+ return () => {
3685
+ for (const key of staged.keys()) {
3686
+ delete process.env[key];
3687
+ }
3688
+ };
3689
+ }
3690
+ function readEnvStringValue(key) {
3691
+ const value = process.env[key];
3692
+ if (typeof value !== "string") {
3693
+ return void 0;
3694
+ }
3695
+ const trimmed = value.trim();
3696
+ return trimmed.length > 0 ? trimmed : void 0;
3697
+ }
3698
+ function resolveFallbackValue(fallbackKeys) {
3699
+ for (const key of fallbackKeys) {
3700
+ const value = readEnvStringValue(key);
3701
+ if (value) {
3702
+ return value;
3703
+ }
3704
+ }
3705
+ return void 0;
3706
+ }
3707
+ function normalizeOptionalString(value, fallbackKeys) {
3708
+ if (typeof value === "string") {
3709
+ const trimmed = value.trim();
3710
+ if (trimmed.length > 0) {
3711
+ return trimmed;
3712
+ }
3713
+ }
3714
+ return resolveFallbackValue(fallbackKeys);
3715
+ }
3716
+ function normalizeRequiredString(value, fieldLabel, fallbackKeys) {
3717
+ const resolved = normalizeOptionalString(value, fallbackKeys);
3718
+ if (resolved) {
3719
+ return resolved;
3720
+ }
3721
+ throw new Error(
3722
+ `Generator config is missing ${fieldLabel}. Set ${fieldLabel} directly or provide one of: ${fallbackKeys.join(", ")}.`
3723
+ );
3724
+ }
3725
+ function applyPostgresPasswordFallback(connectionString) {
3726
+ let parsedUrl;
3727
+ try {
3728
+ parsedUrl = new URL(connectionString);
3729
+ } catch {
3730
+ return connectionString;
3731
+ }
3732
+ if (!POSTGRES_PROTOCOLS.has(parsedUrl.protocol)) {
3733
+ return connectionString;
3734
+ }
3735
+ if (!parsedUrl.username || parsedUrl.password) {
3736
+ return connectionString;
3737
+ }
3738
+ const fallbackPassword = resolveFallbackValue(POSTGRES_PASSWORD_ENV_KEYS);
3739
+ if (!fallbackPassword) {
3740
+ return connectionString;
3741
+ }
3742
+ parsedUrl.password = fallbackPassword;
3743
+ return parsedUrl.toString();
3744
+ }
3745
+ function normalizeBooleanFlag(rawValue, fallback) {
3746
+ if (typeof rawValue === "boolean") {
3747
+ return rawValue;
3748
+ }
3749
+ if (typeof rawValue === "string") {
3750
+ return parseBooleanFlag(rawValue, fallback);
3751
+ }
3752
+ return fallback;
3753
+ }
3754
+ function normalizeFeatureFlags(input) {
3755
+ return {
3756
+ emitRelations: normalizeBooleanFlag(
3757
+ input?.emitRelations,
3758
+ DEFAULT_FEATURES.emitRelations
3759
+ ),
3760
+ emitRegistry: normalizeBooleanFlag(
3761
+ input?.emitRegistry,
3762
+ DEFAULT_FEATURES.emitRegistry
3763
+ )
3764
+ };
3765
+ }
3766
+ function normalizeExperimentalFlags(input) {
3767
+ return {
3768
+ postgresGatewayIntrospection: normalizeBooleanFlag(
3769
+ input?.postgresGatewayIntrospection,
3770
+ DEFAULT_EXPERIMENTAL_FLAGS.postgresGatewayIntrospection
3771
+ ),
3772
+ scyllaProviderContracts: normalizeBooleanFlag(
3773
+ input?.scyllaProviderContracts,
3774
+ DEFAULT_EXPERIMENTAL_FLAGS.scyllaProviderContracts
3775
+ )
3776
+ };
3777
+ }
2435
3778
  function normalizeOutputConfig(output) {
2436
3779
  return {
2437
3780
  targets: {
@@ -2444,9 +3787,41 @@ function normalizeOutputConfig(output) {
2444
3787
  };
2445
3788
  }
2446
3789
  function normalizeProviderConfig(provider) {
2447
- if (provider.kind === "postgres") {
3790
+ if (provider.kind === "postgres" && provider.mode === "direct") {
3791
+ const connectionString = normalizeRequiredString(
3792
+ provider.connectionString,
3793
+ "provider.connectionString",
3794
+ DIRECT_CONNECTION_STRING_ENV_KEYS
3795
+ );
3796
+ const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS);
3797
+ return {
3798
+ ...provider,
3799
+ connectionString: applyPostgresPasswordFallback(connectionString),
3800
+ database,
3801
+ schemas: normalizeSchemaSelection(provider.schemas)
3802
+ };
3803
+ }
3804
+ if (provider.kind === "postgres" && provider.mode === "gateway") {
3805
+ const gatewayUrl = normalizeRequiredString(
3806
+ provider.gatewayUrl,
3807
+ "provider.gatewayUrl",
3808
+ GATEWAY_URL_ENV_KEYS
3809
+ );
3810
+ const apiKey = normalizeRequiredString(
3811
+ provider.apiKey,
3812
+ "provider.apiKey",
3813
+ GATEWAY_API_KEY_ENV_KEYS
3814
+ );
3815
+ const database = normalizeRequiredString(
3816
+ provider.database,
3817
+ "provider.database",
3818
+ POSTGRES_DATABASE_ENV_KEYS
3819
+ );
2448
3820
  return {
2449
3821
  ...provider,
3822
+ gatewayUrl,
3823
+ apiKey,
3824
+ database,
2450
3825
  schemas: normalizeSchemaSelection(provider.schemas)
2451
3826
  };
2452
3827
  }
@@ -2467,14 +3842,8 @@ function normalizeGeneratorConfig(input) {
2467
3842
  ...DEFAULT_NAMING,
2468
3843
  ...input.naming ?? {}
2469
3844
  },
2470
- features: {
2471
- ...DEFAULT_FEATURES,
2472
- ...input.features ?? {}
2473
- },
2474
- experimental: {
2475
- ...DEFAULT_EXPERIMENTAL_FLAGS,
2476
- ...input.experimental ?? {}
2477
- }
3845
+ features: normalizeFeatureFlags(input.features),
3846
+ experimental: normalizeExperimentalFlags(input.experimental)
2478
3847
  };
2479
3848
  }
2480
3849
  function defineGeneratorConfig(config) {
@@ -2514,6 +3883,11 @@ function extractConfigExport(module) {
2514
3883
  if (moduleExports && typeof moduleExports === "object") {
2515
3884
  queue.push(moduleExports);
2516
3885
  }
3886
+ for (const value of Object.values(record)) {
3887
+ if (value && typeof value === "object") {
3888
+ queue.push(value);
3889
+ }
3890
+ }
2517
3891
  }
2518
3892
  throw new Error(
2519
3893
  "Generator config file must export a config object as default export or `config`."
@@ -2528,19 +3902,24 @@ function importConfigModule(moduleSpecifier) {
2528
3902
  }
2529
3903
  async function loadGeneratorConfig(options = {}) {
2530
3904
  const cwd = options.cwd ?? process.cwd();
3905
+ const restoreProjectEnv = applyProjectEnv(cwd);
2531
3906
  const resolvedPath = options.configPath ? path.resolve(cwd, options.configPath) : findGeneratorConfigPath(cwd);
2532
3907
  if (!resolvedPath) {
2533
3908
  throw new Error(
2534
3909
  `No generator config found in ${cwd}. Expected one of: ${DEFAULT_CONFIG_CANDIDATES.join(", ")}`
2535
3910
  );
2536
3911
  }
2537
- const moduleUrl = url.pathToFileURL(resolvedPath);
2538
- const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
2539
- const rawConfig = extractConfigExport(module);
2540
- return {
2541
- configPath: resolvedPath,
2542
- config: normalizeGeneratorConfig(rawConfig)
2543
- };
3912
+ try {
3913
+ const moduleUrl = url.pathToFileURL(resolvedPath);
3914
+ const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
3915
+ const rawConfig = extractConfigExport(module);
3916
+ return {
3917
+ configPath: resolvedPath,
3918
+ config: normalizeGeneratorConfig(rawConfig)
3919
+ };
3920
+ } finally {
3921
+ restoreProjectEnv();
3922
+ }
2544
3923
  }
2545
3924
 
2546
3925
  // src/generator/naming.ts
@@ -2684,9 +4063,13 @@ function resolvePlaceholderMap(baseTokens, outputConfig) {
2684
4063
  const resolved = {
2685
4064
  ...baseTokens
2686
4065
  };
4066
+ const reservedTokenKeys = new Set(Object.keys(baseTokens));
2687
4067
  const entries = Object.entries(outputConfig.placeholderMap ?? {});
2688
4068
  for (let index = 0; index < entries.length; index += 1) {
2689
4069
  const [key, value] = entries[index];
4070
+ if (reservedTokenKeys.has(key)) {
4071
+ continue;
4072
+ }
2690
4073
  let current = value;
2691
4074
  for (let depth = 0; depth < 8; depth += 1) {
2692
4075
  const next = renderTemplate(current, resolved);
@@ -2966,13 +4349,65 @@ function assertNoDuplicatePaths(files) {
2966
4349
  [
2967
4350
  `Generator output collision detected for path: ${file.path}`,
2968
4351
  `Collision: ${existing.kind} and ${file.kind}.`,
2969
- "When syncing multiple schemas, include a schema placeholder such as {schema} or {schema_kebab} in model/schema output targets."
4352
+ "Use explicit placeholders such as {model}, {model_kebab}, {schema}, or {schema_kebab} in output targets so each artifact resolves to a unique path."
2970
4353
  ].join(" ")
2971
4354
  );
2972
4355
  }
2973
4356
  seen.set(file.path, file);
2974
4357
  }
2975
4358
  }
4359
+ function addSchemaSegmentToPath(pathValue, schemaName) {
4360
+ const normalizedPath = normalizePath(pathValue);
4361
+ const parsedPath = path.posix.parse(normalizedPath);
4362
+ const schemaSegment = applyNamingStyle(schemaName, "kebab");
4363
+ if (!schemaSegment) {
4364
+ return normalizedPath;
4365
+ }
4366
+ const dir = parsedPath.dir.length > 0 ? `${parsedPath.dir}/${schemaSegment}` : schemaSegment;
4367
+ return normalizePath(path.posix.join(dir, parsedPath.base));
4368
+ }
4369
+ function scopeDuplicateDescriptorPathsBySchema(descriptors) {
4370
+ const nextDescriptors = descriptors.map((descriptor) => ({ ...descriptor }));
4371
+ const duplicates = /* @__PURE__ */ new Map();
4372
+ for (let index = 0; index < nextDescriptors.length; index += 1) {
4373
+ const descriptor = nextDescriptors[index];
4374
+ const indexes = duplicates.get(descriptor.filePath) ?? [];
4375
+ indexes.push(index);
4376
+ duplicates.set(descriptor.filePath, indexes);
4377
+ }
4378
+ let appliedSchemaScoping = false;
4379
+ for (const indexes of duplicates.values()) {
4380
+ if (indexes.length <= 1) {
4381
+ continue;
4382
+ }
4383
+ const schemaNames = new Set(indexes.map((index) => nextDescriptors[index].schemaName));
4384
+ if (schemaNames.size <= 1) {
4385
+ continue;
4386
+ }
4387
+ for (const index of indexes) {
4388
+ const descriptor = nextDescriptors[index];
4389
+ descriptor.filePath = addSchemaSegmentToPath(descriptor.filePath, descriptor.schemaName);
4390
+ }
4391
+ appliedSchemaScoping = true;
4392
+ }
4393
+ if (!appliedSchemaScoping) {
4394
+ return nextDescriptors;
4395
+ }
4396
+ const normalizedPaths = /* @__PURE__ */ new Set();
4397
+ for (const descriptor of nextDescriptors) {
4398
+ if (normalizedPaths.has(descriptor.filePath)) {
4399
+ throw new Error(
4400
+ [
4401
+ `Generator output collision detected for path: ${descriptor.filePath}`,
4402
+ "Automatic schema path scoping was applied but collisions remain.",
4403
+ "Add explicit placeholders such as {model}, {model_kebab}, {schema}, or {schema_kebab} to your output targets."
4404
+ ].join(" ")
4405
+ );
4406
+ }
4407
+ normalizedPaths.add(descriptor.filePath);
4408
+ }
4409
+ return nextDescriptors;
4410
+ }
2976
4411
  var ArtifactComposer = class {
2977
4412
  constructor(snapshot, config) {
2978
4413
  this.snapshot = snapshot;
@@ -3011,7 +4446,8 @@ var ArtifactComposer = class {
3011
4446
  });
3012
4447
  }
3013
4448
  }
3014
- const schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
4449
+ const scopedModelDescriptors = scopeDuplicateDescriptorPathsBySchema(modelDescriptors);
4450
+ let schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
3015
4451
  const schemaPath = normalizePath(
3016
4452
  renderOutputPath(this.config.output.targets.schema, {
3017
4453
  provider: providerName,
@@ -3029,9 +4465,10 @@ var ArtifactComposer = class {
3029
4465
  this.config.naming.schemaConst,
3030
4466
  "schema"
3031
4467
  ),
3032
- models: modelDescriptors.filter((model) => model.schemaName === schemaName)
4468
+ models: scopedModelDescriptors.filter((model) => model.schemaName === schemaName)
3033
4469
  };
3034
4470
  });
4471
+ schemaDescriptors = scopeDuplicateDescriptorPathsBySchema(schemaDescriptors);
3035
4472
  const databasePath = normalizePath(
3036
4473
  renderOutputPath(this.config.output.targets.database, {
3037
4474
  provider: providerName,
@@ -3051,7 +4488,7 @@ var ArtifactComposer = class {
3051
4488
  schemas: schemaDescriptors
3052
4489
  };
3053
4490
  const files = [];
3054
- for (const modelDescriptor of modelDescriptors) {
4491
+ for (const modelDescriptor of scopedModelDescriptors) {
3055
4492
  files.push(renderModelArtifact(this.snapshot, modelDescriptor, this.config));
3056
4493
  }
3057
4494
  for (const schemaDescriptor of schemaDescriptors) {
@@ -3084,633 +4521,142 @@ var ArtifactComposer = class {
3084
4521
  files
3085
4522
  };
3086
4523
  }
3087
- };
3088
- function generateArtifactsFromSnapshot(snapshot, config) {
3089
- const normalizedConfig = "naming" in config && "features" in config && "experimental" in config ? config : normalizeGeneratorConfig(config);
3090
- return new ArtifactComposer(snapshot, normalizedConfig).compose();
3091
- }
3092
-
3093
- // src/generator/providers.ts
3094
- var AthenaGatewayCatalogClient = class {
3095
- constructor(client) {
3096
- this.client = client;
3097
- }
3098
- async queryRows(query) {
3099
- const result = await this.client.query(query);
3100
- if (result.error || result.status < 200 || result.status >= 300) {
3101
- throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
3102
- }
3103
- return result.data ?? [];
3104
- }
3105
- async queryColumns(query) {
3106
- return this.queryRows(query);
3107
- }
3108
- async queryEnums(query) {
3109
- const rows = await this.queryRows(query);
3110
- const enumMap = /* @__PURE__ */ new Map();
3111
- for (const row of rows) {
3112
- const existing = enumMap.get(row.type_oid) ?? [];
3113
- existing.push(row.enum_label);
3114
- enumMap.set(row.type_oid, existing);
3115
- }
3116
- return enumMap;
3117
- }
3118
- async queryPrimaryKeys(query) {
3119
- return this.queryRows(query);
3120
- }
3121
- async queryForeignKeys(query) {
3122
- return this.queryRows(query);
3123
- }
3124
- };
3125
- var AthenaGatewayPostgresIntrospectionProvider = class {
3126
- constructor(config) {
3127
- this.config = config;
3128
- this.client = createClient(this.config.gatewayUrl, this.config.apiKey, {
3129
- backend: {
3130
- type: this.config.backend ?? "postgresql"
3131
- }
3132
- });
3133
- this.schemas = normalizeSchemaSelection(this.config.schemas);
3134
- }
3135
- backend = "postgresql";
3136
- client;
3137
- schemas;
3138
- async inspect(options) {
3139
- const schemas = options?.schemas && options.schemas.length > 0 ? normalizeSchemaSelection(options.schemas) : this.schemas;
3140
- const catalogClient = new AthenaGatewayCatalogClient(this.client);
3141
- const queries = buildGatewayCatalogQueries(schemas);
3142
- const [columnRows, enumMap, primaryKeyRows, foreignKeyRows] = await Promise.all([
3143
- catalogClient.queryColumns(queries.columns),
3144
- catalogClient.queryEnums(queries.enums),
3145
- catalogClient.queryPrimaryKeys(queries.primaryKeys),
3146
- catalogClient.queryForeignKeys(queries.foreignKeys)
3147
- ]);
3148
- const assembler = new PostgresCatalogSnapshotAssembler();
3149
- assembler.addColumnRows(columnRows, enumMap);
3150
- assembler.addPrimaryKeyRows(primaryKeyRows);
3151
- assembler.addForeignKeyRows(foreignKeyRows);
3152
- assembler.addManyToManyRows(foreignKeyRows);
3153
- return {
3154
- backend: "postgresql",
3155
- database: this.config.database,
3156
- generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3157
- schemas: assembler.toSchemas()
3158
- };
3159
- }
3160
- };
3161
- var ScyllaIntrospectionProvider = class {
3162
- constructor(config) {
3163
- this.config = config;
3164
- }
3165
- backend = "scylladb";
3166
- async inspect() {
3167
- throw new Error(
3168
- `Scylla introspection provider is not implemented yet for keyspace ${this.config.keyspace}.`
3169
- );
3170
- }
3171
- };
3172
- function createPostgresProvider(config) {
3173
- return createPostgresIntrospectionProvider({
3174
- connectionString: config.connectionString,
3175
- database: config.database,
3176
- schemas: normalizeSchemaSelection(config.schemas)
3177
- });
3178
- }
3179
- function resolveGeneratorProvider(providerConfig, experimentalFlags) {
3180
- if (providerConfig.kind === "postgres" && providerConfig.mode === "direct") {
3181
- return createPostgresProvider(providerConfig);
3182
- }
3183
- if (providerConfig.kind === "postgres" && providerConfig.mode === "gateway") {
3184
- return new AthenaGatewayPostgresIntrospectionProvider(providerConfig);
3185
- }
3186
- if (providerConfig.kind === "scylla") {
3187
- if (!experimentalFlags.scyllaProviderContracts) {
3188
- throw new Error(
3189
- "Scylla provider contracts are disabled. Set experimental.scyllaProviderContracts=true to enable placeholders."
3190
- );
3191
- }
3192
- return new ScyllaIntrospectionProvider(providerConfig);
3193
- }
3194
- throw new Error(`Unsupported generator provider kind: ${providerConfig.kind ?? "unknown"}`);
3195
- }
3196
- async function writeArtifacts(files, cwd) {
3197
- const writtenFiles = [];
3198
- for (const file of files) {
3199
- const absolutePath = path.resolve(cwd, file.path);
3200
- await promises.mkdir(path.dirname(absolutePath), { recursive: true });
3201
- await promises.writeFile(absolutePath, file.content, "utf8");
3202
- writtenFiles.push(file.path);
3203
- }
3204
- return writtenFiles;
3205
- }
3206
- async function runSchemaGenerator(options = {}) {
3207
- const cwd = options.cwd ?? process.cwd();
3208
- const configOptions = {
3209
- cwd,
3210
- configPath: options.configPath
3211
- };
3212
- const { configPath, config } = await loadGeneratorConfig(configOptions);
3213
- const provider = options.provider ?? resolveGeneratorProvider(config.provider, config.experimental);
3214
- const snapshot = await provider.inspect({
3215
- schemas: resolveProviderSchemas(config.provider)
3216
- });
3217
- const generated = generateArtifactsFromSnapshot(snapshot, config);
3218
- const writtenFiles = options.dryRun ? [] : await writeArtifacts(generated.files, cwd);
3219
- return {
3220
- ...generated,
3221
- configPath,
3222
- writtenFiles
3223
- };
3224
- }
3225
-
3226
- // src/auth/client.ts
3227
- var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
3228
- var FALLBACK_SDK_VERSION2 = "1.0.0";
3229
- var SDK_NAME2 = "xylex-group/athena-auth";
3230
- var SDK_VERSION2 = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION2;
3231
- var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
3232
- function normalizeBaseUrl(baseUrl) {
3233
- return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
3234
- }
3235
- function isRecord4(value) {
3236
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3237
- }
3238
- function normalizeHeaderValue2(value) {
3239
- return value ? value : void 0;
3240
- }
3241
- function parseResponseBody2(rawText, contentType) {
3242
- if (!rawText) {
3243
- return { parsed: null, parseFailed: false };
3244
- }
3245
- const contentTypeSuggestsJson = contentType?.toLowerCase().includes("application/json") ?? false;
3246
- const looksJson = contentTypeSuggestsJson || rawText.startsWith("{") || rawText.startsWith("[");
3247
- if (!looksJson) {
3248
- return { parsed: rawText, parseFailed: false };
3249
- }
3250
- try {
3251
- return { parsed: JSON.parse(rawText), parseFailed: false };
3252
- } catch {
3253
- return { parsed: rawText, parseFailed: true };
3254
- }
3255
- }
3256
- function resolveRequestId2(headers) {
3257
- return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
3258
- }
3259
- function resolveErrorMessage2(payload, fallback) {
3260
- if (isRecord4(payload)) {
3261
- const messageCandidates = [payload.error, payload.message, payload.details];
3262
- for (const candidate of messageCandidates) {
3263
- if (typeof candidate === "string" && candidate.trim().length > 0) {
3264
- return candidate.trim();
3265
- }
3266
- }
3267
- }
3268
- if (typeof payload === "string" && payload.trim().length > 0) {
3269
- return payload.trim();
3270
- }
3271
- return fallback;
3272
- }
3273
- function toErrorDetails(input) {
3274
- return {
3275
- code: input.code,
3276
- message: input.message,
3277
- status: input.status,
3278
- endpoint: input.endpoint,
3279
- method: input.method,
3280
- requestId: input.requestId,
3281
- hint: input.hint,
3282
- cause: input.cause
3283
- };
3284
- }
3285
- function mergeCallOptions(base, override) {
3286
- if (!base && !override) return void 0;
3287
- return {
3288
- ...base,
3289
- ...override,
3290
- headers: {
3291
- ...base?.headers ?? {},
3292
- ...override?.headers ?? {}
3293
- }
3294
- };
3295
- }
3296
- function extractFetchOptions(input) {
3297
- if (!input) {
3298
- return {
3299
- payload: void 0,
3300
- fetchOptions: void 0
3301
- };
3302
- }
3303
- const { fetchOptions, ...rest } = input;
3304
- const hasPayloadKeys = Object.keys(rest).length > 0;
3305
- return {
3306
- payload: hasPayloadKeys ? rest : void 0,
3307
- fetchOptions
3308
- };
4524
+ };
4525
+ function generateArtifactsFromSnapshot(snapshot, config) {
4526
+ const normalizedConfig = "naming" in config && "features" in config && "experimental" in config ? config : normalizeGeneratorConfig(config);
4527
+ return new ArtifactComposer(snapshot, normalizedConfig).compose();
3309
4528
  }
3310
- function buildHeaders2(config, options) {
3311
- const headers = {
3312
- "Content-Type": "application/json",
3313
- "X-Athena-Sdk": SDK_HEADER_VALUE2
3314
- };
3315
- const apiKey = options?.apiKey ?? config.apiKey;
3316
- if (apiKey) {
3317
- headers.apikey = apiKey;
3318
- headers["x-api-key"] = apiKey;
3319
- }
3320
- const bearerToken = options?.bearerToken ?? config.bearerToken;
3321
- if (bearerToken) {
3322
- headers.Authorization = `Bearer ${bearerToken}`;
4529
+
4530
+ // src/generator/providers.ts
4531
+ var AthenaGatewayCatalogClient = class {
4532
+ constructor(client) {
4533
+ this.client = client;
3323
4534
  }
3324
- const mergedExtraHeaders = {
3325
- ...config.headers ?? {},
3326
- ...options?.headers ?? {}
3327
- };
3328
- Object.entries(mergedExtraHeaders).forEach(([key, value]) => {
3329
- const normalized = normalizeHeaderValue2(value);
3330
- if (normalized) {
3331
- headers[key] = normalized;
4535
+ async queryRows(query) {
4536
+ const result = await this.client.query(query);
4537
+ if (result.error || result.status < 200 || result.status >= 300) {
4538
+ throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
3332
4539
  }
3333
- });
3334
- return headers;
3335
- }
3336
- function appendQueryParam(searchParams, key, value) {
3337
- if (value === void 0 || value === null) return;
3338
- if (Array.isArray(value)) {
3339
- value.forEach((item) => {
3340
- searchParams.append(key, String(item));
3341
- });
3342
- return;
4540
+ return result.data ?? [];
3343
4541
  }
3344
- searchParams.append(key, String(value));
3345
- }
3346
- function buildRequestUrl(baseUrl, endpoint, query) {
3347
- const url = `${baseUrl}${endpoint}`;
3348
- if (!query || Object.keys(query).length === 0) return url;
3349
- const searchParams = new URLSearchParams();
3350
- Object.entries(query).forEach(([key, value]) => appendQueryParam(searchParams, key, value));
3351
- const queryText = searchParams.toString();
3352
- return queryText ? `${url}?${queryText}` : url;
3353
- }
3354
- function inferDefaultMethod(endpoint) {
3355
- if (endpoint.startsWith("/reset-password/")) {
3356
- return "GET";
4542
+ async queryColumns(query) {
4543
+ return this.queryRows(query);
3357
4544
  }
3358
- switch (endpoint) {
3359
- case "/get-session":
3360
- case "/list-sessions":
3361
- case "/verify-email":
3362
- case "/delete-user/callback":
3363
- case "/list-accounts":
3364
- case "/ok":
3365
- case "/error":
3366
- return "GET";
3367
- default:
3368
- return "POST";
4545
+ async queryEnums(query) {
4546
+ const rows = await this.queryRows(query);
4547
+ const enumMap = /* @__PURE__ */ new Map();
4548
+ for (const row of rows) {
4549
+ const existing = enumMap.get(row.type_oid) ?? [];
4550
+ existing.push(row.enum_label);
4551
+ enumMap.set(row.type_oid, existing);
4552
+ }
4553
+ return enumMap;
3369
4554
  }
3370
- }
3371
- async function callAuthEndpoint(config, context, body, query, options) {
3372
- const baseUrl = normalizeBaseUrl(options?.baseUrl ?? config.baseUrl);
3373
- const url = buildRequestUrl(baseUrl, context.endpoint, query);
3374
- const headers = buildHeaders2(config, options);
3375
- const credentials = options?.credentials ?? config.credentials ?? "include";
3376
- const requestInit = {
3377
- method: context.method,
3378
- headers,
3379
- credentials,
3380
- signal: options?.signal
3381
- };
3382
- if (context.method !== "GET") {
3383
- requestInit.body = JSON.stringify(body ?? {});
4555
+ async queryPrimaryKeys(query) {
4556
+ return this.queryRows(query);
3384
4557
  }
3385
- const fetcher = config.fetch ?? globalThis.fetch;
3386
- if (!fetcher) {
3387
- const details = toErrorDetails({
3388
- code: "UNKNOWN_ERROR",
3389
- message: "No fetch implementation available for auth client",
3390
- status: 0,
3391
- endpoint: context.endpoint,
3392
- method: context.method,
3393
- hint: "Use Node 18+ or provide `fetch` in createAuthClient({ fetch })"
4558
+ async queryForeignKeys(query) {
4559
+ return this.queryRows(query);
4560
+ }
4561
+ };
4562
+ var AthenaGatewayPostgresIntrospectionProvider = class {
4563
+ constructor(config) {
4564
+ this.config = config;
4565
+ this.client = createClient(this.config.gatewayUrl, this.config.apiKey, {
4566
+ backend: {
4567
+ type: this.config.backend ?? "postgresql"
4568
+ }
3394
4569
  });
4570
+ this.schemas = normalizeSchemaSelection(this.config.schemas);
4571
+ }
4572
+ backend = "postgresql";
4573
+ client;
4574
+ schemas;
4575
+ async inspect(options) {
4576
+ const schemas = options?.schemas && options.schemas.length > 0 ? normalizeSchemaSelection(options.schemas) : this.schemas;
4577
+ const catalogClient = new AthenaGatewayCatalogClient(this.client);
4578
+ const queries = buildGatewayCatalogQueries(schemas);
4579
+ const [columnRows, enumMap, primaryKeyRows, foreignKeyRows] = await Promise.all([
4580
+ catalogClient.queryColumns(queries.columns),
4581
+ catalogClient.queryEnums(queries.enums),
4582
+ catalogClient.queryPrimaryKeys(queries.primaryKeys),
4583
+ catalogClient.queryForeignKeys(queries.foreignKeys)
4584
+ ]);
4585
+ const assembler = new PostgresCatalogSnapshotAssembler();
4586
+ assembler.addColumnRows(columnRows, enumMap);
4587
+ assembler.addPrimaryKeyRows(primaryKeyRows);
4588
+ assembler.addForeignKeyRows(foreignKeyRows);
4589
+ assembler.addManyToManyRows(foreignKeyRows);
3395
4590
  return {
3396
- ok: false,
3397
- status: 0,
3398
- data: null,
3399
- error: details.message,
3400
- errorDetails: details,
3401
- raw: null
4591
+ backend: "postgresql",
4592
+ database: this.config.database,
4593
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4594
+ schemas: assembler.toSchemas()
3402
4595
  };
3403
4596
  }
3404
- try {
3405
- const response = await fetcher(url, requestInit);
3406
- const rawText = await response.text();
3407
- const requestId = resolveRequestId2(response.headers);
3408
- const parsedBody = parseResponseBody2(rawText ?? "", response.headers.get("content-type"));
3409
- if (parsedBody.parseFailed) {
3410
- const details = toErrorDetails({
3411
- code: "INVALID_JSON",
3412
- message: "Auth server returned malformed JSON",
3413
- status: response.status,
3414
- endpoint: context.endpoint,
3415
- method: context.method,
3416
- requestId,
3417
- hint: "Verify the auth endpoint response body is valid JSON.",
3418
- cause: rawText.slice(0, 300)
3419
- });
3420
- return {
3421
- ok: false,
3422
- status: response.status,
3423
- data: null,
3424
- error: details.message,
3425
- errorDetails: details,
3426
- raw: parsedBody.parsed
3427
- };
3428
- }
3429
- const parsed = parsedBody.parsed;
3430
- if (!response.ok) {
3431
- const details = toErrorDetails({
3432
- code: "HTTP_ERROR",
3433
- message: resolveErrorMessage2(
3434
- parsed,
3435
- `Auth endpoint ${context.method} ${context.endpoint} failed with status ${response.status}`
3436
- ),
3437
- status: response.status,
3438
- endpoint: context.endpoint,
3439
- method: context.method,
3440
- requestId
3441
- });
3442
- return {
3443
- ok: false,
3444
- status: response.status,
3445
- data: null,
3446
- error: details.message,
3447
- errorDetails: details,
3448
- raw: parsed
3449
- };
4597
+ };
4598
+ var ScyllaIntrospectionProvider = class {
4599
+ constructor(config) {
4600
+ this.config = config;
4601
+ }
4602
+ backend = "scylladb";
4603
+ async inspect() {
4604
+ throw new Error(
4605
+ `Scylla introspection provider is not implemented yet for keyspace ${this.config.keyspace}.`
4606
+ );
4607
+ }
4608
+ };
4609
+ function createPostgresProvider(config) {
4610
+ return createPostgresIntrospectionProvider({
4611
+ connectionString: config.connectionString,
4612
+ database: config.database,
4613
+ schemas: normalizeSchemaSelection(config.schemas)
4614
+ });
4615
+ }
4616
+ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
4617
+ if (providerConfig.kind === "postgres" && providerConfig.mode === "direct") {
4618
+ return createPostgresProvider(providerConfig);
4619
+ }
4620
+ if (providerConfig.kind === "postgres" && providerConfig.mode === "gateway") {
4621
+ return new AthenaGatewayPostgresIntrospectionProvider(providerConfig);
4622
+ }
4623
+ if (providerConfig.kind === "scylla") {
4624
+ if (!experimentalFlags.scyllaProviderContracts) {
4625
+ throw new Error(
4626
+ "Scylla provider contracts are disabled. Set experimental.scyllaProviderContracts=true to enable placeholders."
4627
+ );
3450
4628
  }
3451
- return {
3452
- ok: true,
3453
- status: response.status,
3454
- data: parsed ?? null,
3455
- error: null,
3456
- errorDetails: null,
3457
- raw: parsed
3458
- };
3459
- } catch (callError) {
3460
- const message = callError instanceof Error ? callError.message : String(callError);
3461
- const details = toErrorDetails({
3462
- code: "NETWORK_ERROR",
3463
- message: `Network error while calling ${context.method} ${context.endpoint}: ${message}`,
3464
- status: 0,
3465
- endpoint: context.endpoint,
3466
- method: context.method,
3467
- cause: message,
3468
- hint: "Check auth server URL, DNS, and network reachability."
3469
- });
3470
- return {
3471
- ok: false,
3472
- status: 0,
3473
- data: null,
3474
- error: details.message,
3475
- errorDetails: details,
3476
- raw: null
3477
- };
4629
+ return new ScyllaIntrospectionProvider(providerConfig);
3478
4630
  }
4631
+ throw new Error(`Unsupported generator provider kind: ${providerConfig.kind ?? "unknown"}`);
3479
4632
  }
3480
- function executePostWithCompatibleInput(config, context, input, options) {
3481
- const { payload, fetchOptions } = extractFetchOptions(input);
3482
- const mergedOptions = mergeCallOptions(fetchOptions, options);
3483
- return callAuthEndpoint(config, context, payload ?? {}, void 0, mergedOptions);
3484
- }
3485
- function executePostWithOptionalInput(config, context, input, options) {
3486
- const { fetchOptions } = extractFetchOptions(input);
3487
- const mergedOptions = mergeCallOptions(fetchOptions, options);
3488
- return callAuthEndpoint(config, context, {}, void 0, mergedOptions);
3489
- }
3490
- function executeGetWithCompatibleInput(config, context, input, options) {
3491
- const { fetchOptions } = extractFetchOptions(input);
3492
- const mergedOptions = mergeCallOptions(fetchOptions, options);
3493
- return callAuthEndpoint(config, context, void 0, void 0, mergedOptions);
4633
+ async function writeArtifacts(files, cwd) {
4634
+ const writtenFiles = [];
4635
+ for (const file of files) {
4636
+ const absolutePath = path.resolve(cwd, file.path);
4637
+ await promises.mkdir(path.dirname(absolutePath), { recursive: true });
4638
+ await promises.writeFile(absolutePath, file.content, "utf8");
4639
+ writtenFiles.push(file.path);
4640
+ }
4641
+ return writtenFiles;
3494
4642
  }
3495
- function createAuthClient(config = {}) {
3496
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
3497
- const resolvedConfig = {
3498
- ...config,
3499
- baseUrl: normalizedBaseUrl
3500
- };
3501
- const request = (input, options) => {
3502
- const method = input.method ?? (input.body !== void 0 ? "POST" : inferDefaultMethod(input.endpoint));
3503
- const mergedOptions = mergeCallOptions(input.fetchOptions, options);
3504
- return callAuthEndpoint(
3505
- resolvedConfig,
3506
- { endpoint: input.endpoint, method },
3507
- input.body,
3508
- input.query,
3509
- mergedOptions
3510
- );
3511
- };
3512
- const signOut = (input, options) => executePostWithOptionalInput(
3513
- resolvedConfig,
3514
- { endpoint: "/sign-out", method: "POST" },
3515
- input,
3516
- options
3517
- );
3518
- const revokeSessions = (input, options) => executePostWithOptionalInput(
3519
- resolvedConfig,
3520
- { endpoint: "/revoke-sessions", method: "POST" },
3521
- input,
3522
- options
3523
- );
3524
- const revokeOtherSessions = (input, options) => executePostWithOptionalInput(
3525
- resolvedConfig,
3526
- { endpoint: "/revoke-other-sessions", method: "POST" },
3527
- input,
3528
- options
3529
- );
3530
- const revokeSession = (input, options) => executePostWithCompatibleInput(
3531
- resolvedConfig,
3532
- { endpoint: "/revoke-session", method: "POST" },
3533
- input,
3534
- options
3535
- );
3536
- const deleteUser = (input, options) => {
3537
- const { payload, fetchOptions } = extractFetchOptions(input);
3538
- const mergedOptions = mergeCallOptions(fetchOptions, options);
3539
- return callAuthEndpoint(
3540
- resolvedConfig,
3541
- { endpoint: "/delete-user", method: "POST" },
3542
- payload ?? {},
3543
- void 0,
3544
- mergedOptions
3545
- );
3546
- };
3547
- const deleteUserCallback = (input, options) => {
3548
- const { payload, fetchOptions } = extractFetchOptions(input);
3549
- const mergedOptions = mergeCallOptions(fetchOptions, options);
3550
- const query = payload ?? {};
3551
- return callAuthEndpoint(
3552
- resolvedConfig,
3553
- { endpoint: "/delete-user/callback", method: "GET" },
3554
- void 0,
3555
- {
3556
- token: query.token,
3557
- callbackURL: query.callbackURL
3558
- },
3559
- mergedOptions
3560
- );
3561
- };
3562
- const resolveResetPasswordToken = (input, options) => {
3563
- const { payload, fetchOptions } = extractFetchOptions(input);
3564
- const mergedOptions = mergeCallOptions(fetchOptions, options);
3565
- const query = payload;
3566
- const token = query?.token?.trim();
3567
- if (!token) {
3568
- throw new Error("resolveResetPasswordToken requires a non-empty token");
3569
- }
3570
- const endpoint = `/reset-password/${encodeURIComponent(token)}`;
3571
- return callAuthEndpoint(
3572
- resolvedConfig,
3573
- { endpoint, method: "GET" },
3574
- void 0,
3575
- query?.callbackURL ? { callbackURL: query.callbackURL } : void 0,
3576
- mergedOptions
3577
- );
4643
+ async function runSchemaGenerator(options = {}) {
4644
+ const cwd = options.cwd ?? process.cwd();
4645
+ const configOptions = {
4646
+ cwd,
4647
+ configPath: options.configPath
3578
4648
  };
4649
+ const { configPath, config } = await loadGeneratorConfig(configOptions);
4650
+ const provider = options.provider ?? resolveGeneratorProvider(config.provider, config.experimental);
4651
+ const snapshot = await provider.inspect({
4652
+ schemas: resolveProviderSchemas(config.provider)
4653
+ });
4654
+ const generated = generateArtifactsFromSnapshot(snapshot, config);
4655
+ const writtenFiles = options.dryRun ? [] : await writeArtifacts(generated.files, cwd);
3579
4656
  return {
3580
- baseUrl: normalizedBaseUrl,
3581
- request,
3582
- signIn: {
3583
- email: (input, options) => executePostWithCompatibleInput(
3584
- resolvedConfig,
3585
- { endpoint: "/sign-in/email", method: "POST" },
3586
- input,
3587
- options
3588
- ),
3589
- username: (input, options) => executePostWithCompatibleInput(
3590
- resolvedConfig,
3591
- { endpoint: "/sign-in/username", method: "POST" },
3592
- input,
3593
- options
3594
- ),
3595
- social: (input, options) => executePostWithCompatibleInput(
3596
- resolvedConfig,
3597
- { endpoint: "/sign-in/social", method: "POST" },
3598
- input,
3599
- options
3600
- )
3601
- },
3602
- signUp: {
3603
- email: (input, options) => executePostWithCompatibleInput(
3604
- resolvedConfig,
3605
- { endpoint: "/sign-up/email", method: "POST" },
3606
- input,
3607
- options
3608
- )
3609
- },
3610
- signOut,
3611
- logout: signOut,
3612
- getSession: (input, options) => executeGetWithCompatibleInput(
3613
- resolvedConfig,
3614
- { endpoint: "/get-session", method: "GET" },
3615
- input,
3616
- options
3617
- ),
3618
- listSessions: (input, options) => executeGetWithCompatibleInput(
3619
- resolvedConfig,
3620
- { endpoint: "/list-sessions", method: "GET" },
3621
- input,
3622
- options
3623
- ),
3624
- revokeSession,
3625
- clearSession: revokeSession,
3626
- revokeSessions,
3627
- clearSessions: revokeSessions,
3628
- revokeOtherSessions,
3629
- clearOtherSessions: revokeOtherSessions,
3630
- forgetPassword: (input, options) => executePostWithCompatibleInput(
3631
- resolvedConfig,
3632
- { endpoint: "/forget-password", method: "POST" },
3633
- input,
3634
- options
3635
- ),
3636
- resetPassword: (input, options) => executePostWithCompatibleInput(
3637
- resolvedConfig,
3638
- { endpoint: "/reset-password", method: "POST" },
3639
- input,
3640
- options
3641
- ),
3642
- resolveResetPasswordToken,
3643
- verifyEmail: (input, options) => {
3644
- const { payload, fetchOptions } = extractFetchOptions(input);
3645
- const mergedOptions = mergeCallOptions(fetchOptions, options);
3646
- const query = payload;
3647
- return callAuthEndpoint(
3648
- resolvedConfig,
3649
- { endpoint: "/verify-email", method: "GET" },
3650
- void 0,
3651
- query ? {
3652
- token: query.token,
3653
- callbackURL: query.callbackURL
3654
- } : void 0,
3655
- mergedOptions
3656
- );
3657
- },
3658
- sendVerificationEmail: (input, options) => executePostWithCompatibleInput(
3659
- resolvedConfig,
3660
- { endpoint: "/send-verification-email", method: "POST" },
3661
- input,
3662
- options
3663
- ),
3664
- changeEmail: (input, options) => executePostWithCompatibleInput(
3665
- resolvedConfig,
3666
- { endpoint: "/change-email", method: "POST" },
3667
- input,
3668
- options
3669
- ),
3670
- changePassword: (input, options) => executePostWithCompatibleInput(
3671
- resolvedConfig,
3672
- { endpoint: "/change-password", method: "POST" },
3673
- input,
3674
- options
3675
- ),
3676
- updateUser: (input, options) => executePostWithCompatibleInput(
3677
- resolvedConfig,
3678
- { endpoint: "/update-user", method: "POST" },
3679
- input,
3680
- options
3681
- ),
3682
- deleteUser,
3683
- deleteUserCallback,
3684
- linkSocial: (input, options) => executePostWithCompatibleInput(
3685
- resolvedConfig,
3686
- { endpoint: "/link-social", method: "POST" },
3687
- input,
3688
- options
3689
- ),
3690
- listAccounts: (input, options) => executeGetWithCompatibleInput(
3691
- resolvedConfig,
3692
- { endpoint: "/list-accounts", method: "GET" },
3693
- input,
3694
- options
3695
- ),
3696
- unlinkAccount: (input, options) => executePostWithCompatibleInput(
3697
- resolvedConfig,
3698
- { endpoint: "/unlink-account", method: "POST" },
3699
- input,
3700
- options
3701
- ),
3702
- refreshToken: (input, options) => executePostWithCompatibleInput(
3703
- resolvedConfig,
3704
- { endpoint: "/refresh-token", method: "POST" },
3705
- input,
3706
- options
3707
- ),
3708
- getAccessToken: (input, options) => executePostWithCompatibleInput(
3709
- resolvedConfig,
3710
- { endpoint: "/get-access-token", method: "POST" },
3711
- input,
3712
- options
3713
- )
4657
+ ...generated,
4658
+ configPath,
4659
+ writtenFiles
3714
4660
  };
3715
4661
  }
3716
4662
 
@@ -3743,6 +4689,7 @@ exports.loadGeneratorConfig = loadGeneratorConfig;
3743
4689
  exports.normalizeAthenaError = normalizeAthenaError;
3744
4690
  exports.normalizeGeneratorConfig = normalizeGeneratorConfig;
3745
4691
  exports.normalizeSchemaSelection = normalizeSchemaSelection;
4692
+ exports.parseBooleanFlag = parseBooleanFlag;
3746
4693
  exports.requireAffected = requireAffected;
3747
4694
  exports.requireSuccess = requireSuccess;
3748
4695
  exports.resolveGeneratorProvider = resolveGeneratorProvider;