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