import { mkdir, writeFile } from 'fs/promises';
import { resolve, dirname, posix } from 'path';
import { existsSync } from 'fs';
import { pathToFileURL } from 'url';
import { Pool } from 'pg';

// src/generator/pipeline.ts

// src/generator/naming.ts
var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
var RESERVED_IDENTIFIERS = /* @__PURE__ */ new Set([
  "break",
  "case",
  "catch",
  "class",
  "const",
  "continue",
  "debugger",
  "default",
  "delete",
  "do",
  "else",
  "enum",
  "export",
  "extends",
  "false",
  "finally",
  "for",
  "function",
  "if",
  "import",
  "in",
  "instanceof",
  "new",
  "null",
  "return",
  "super",
  "switch",
  "this",
  "throw",
  "true",
  "try",
  "typeof",
  "var",
  "void",
  "while",
  "with",
  "as",
  "implements",
  "interface",
  "let",
  "package",
  "private",
  "protected",
  "public",
  "static",
  "yield",
  "any",
  "boolean",
  "constructor",
  "declare",
  "get",
  "module",
  "require",
  "number",
  "set",
  "string",
  "symbol",
  "type",
  "from",
  "of"
]);
function splitWords(input) {
  return input.trim().replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z0-9]+)/g, "$1 $2").replace(/[^A-Za-z0-9]+/g, " ").split(" ").map((word) => word.trim()).filter((word) => word.length > 0);
}
function capitalize(word) {
  return word.length > 0 ? `${word[0].toUpperCase()}${word.slice(1).toLowerCase()}` : word;
}
function ensureValidIdentifier(candidate, fallback) {
  const normalized = candidate.length > 0 ? candidate : fallback;
  const prefixed = /^[0-9]/.test(normalized) ? `_${normalized}` : normalized;
  if (RESERVED_IDENTIFIERS.has(prefixed)) {
    return `${prefixed}_value`;
  }
  return prefixed;
}
function applyNamingStyle(input, style) {
  const words = splitWords(input);
  if (words.length === 0) {
    return "";
  }
  switch (style) {
    case "preserve":
      return input;
    case "camel": {
      const [first, ...rest] = words;
      return `${first.toLowerCase()}${rest.map(capitalize).join("")}`;
    }
    case "pascal":
      return words.map(capitalize).join("");
    case "snake":
      return words.map((word) => word.toLowerCase()).join("_");
    case "kebab":
      return words.map((word) => word.toLowerCase()).join("-");
    default:
      return input;
  }
}
function toSafeIdentifier(input, style, fallback = "value") {
  const transformed = applyNamingStyle(input, style);
  const normalized = transformed.replace(/[^A-Za-z0-9_$]+/g, "_").replace(/^_+|_+$/g, "");
  const fallbackValue = splitWords(input).join("");
  return ensureValidIdentifier(
    normalized.length > 0 ? normalized : fallbackValue,
    fallback
  );
}
function escapeTypePropertyName(propertyName) {
  if (IDENTIFIER_PATTERN.test(propertyName) && !RESERVED_IDENTIFIERS.has(propertyName)) {
    return propertyName;
  }
  return `'${propertyName.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
}
function escapeStringLiteral(value) {
  return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
}

// src/generator/placeholders.ts
function createStyleTokens(prefix, value) {
  return {
    [prefix]: value,
    [`${prefix}_camel`]: applyNamingStyle(value, "camel"),
    [`${prefix}_pascal`]: applyNamingStyle(value, "pascal"),
    [`${prefix}_snake`]: applyNamingStyle(value, "snake"),
    [`${prefix}_kebab`]: applyNamingStyle(value, "kebab")
  };
}
function renderTemplate(template, tokenMap) {
  return template.replace(/\{([A-Za-z0-9_]+)\}/g, (_match, token) => {
    if (!(token in tokenMap)) {
      throw new Error(`Unknown placeholder token "${token}" in template "${template}"`);
    }
    return tokenMap[token];
  });
}
function resolvePlaceholderMap(baseTokens, outputConfig) {
  const resolved = {
    ...baseTokens
  };
  const entries = Object.entries(outputConfig.placeholderMap ?? {});
  for (let index = 0; index < entries.length; index += 1) {
    const [key, value] = entries[index];
    let current = value;
    for (let depth = 0; depth < 8; depth += 1) {
      const next = renderTemplate(current, resolved);
      if (next === current) {
        break;
      }
      current = next;
    }
    resolved[key] = current;
  }
  return resolved;
}
function renderOutputPath(template, context, outputConfig) {
  const baseTokens = {
    provider: context.provider,
    kind: context.kind,
    ...createStyleTokens("database", context.database),
    ...createStyleTokens("schema", context.schema),
    ...createStyleTokens("model", context.model)
  };
  const tokens = resolvePlaceholderMap(baseTokens, outputConfig);
  return renderTemplate(template, tokens);
}

// src/generator/postgres-type-mapping.ts
var NUMBER_TYPES = /* @__PURE__ */ new Set([
  "int2",
  "int4",
  "float4",
  "float8",
  "smallint",
  "integer",
  "real",
  "double precision"
]);
var STRING_NUMERIC_TYPES = /* @__PURE__ */ new Set([
  "int8",
  "bigint",
  "serial8",
  "bigserial",
  "numeric",
  "decimal",
  "money"
]);
var TEXT_TYPES = /* @__PURE__ */ new Set([
  "char",
  "bpchar",
  "varchar",
  "character varying",
  "text",
  "citext",
  "name",
  "uuid",
  "date",
  "time",
  "timetz",
  "timestamp",
  "timestamptz",
  "interval",
  "inet",
  "cidr",
  "macaddr",
  "macaddr8",
  "point",
  "line",
  "lseg",
  "box",
  "path",
  "polygon",
  "circle",
  "bit",
  "varbit",
  "xml",
  "tsvector",
  "tsquery",
  "jsonpath"
]);
function normalizeTypeLabel(column) {
  const preferred = (column.udtName || column.dataType).toLowerCase().trim();
  if (column.arrayDimensions > 0 && preferred.startsWith("_")) {
    return preferred.slice(1);
  }
  return preferred;
}
function wrapArrayType(baseType, depth) {
  let wrapped = baseType;
  for (let index = 0; index < depth; index += 1) {
    wrapped = `Array<${wrapped}>`;
  }
  return wrapped;
}
function resolveScalarType(column) {
  const label = normalizeTypeLabel(column);
  if (NUMBER_TYPES.has(label)) {
    return "number";
  }
  if (STRING_NUMERIC_TYPES.has(label)) {
    return "string";
  }
  if (label === "bool" || label === "boolean") {
    return "boolean";
  }
  if (label === "bytea") {
    return "Buffer";
  }
  if (label === "json" || label === "jsonb") {
    return "Record<string, unknown>";
  }
  if (TEXT_TYPES.has(label)) {
    return "string";
  }
  if (label.endsWith("range") || label.endsWith("multirange")) {
    return "string";
  }
  return "unknown";
}
function resolveKindAwareType(column) {
  if (column.typeKind === "enum") {
    const values = column.enumValues ?? [];
    if (values.length === 0) {
      return "string";
    }
    return values.map((value) => `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`).join(" | ");
  }
  if (column.typeKind === "composite") {
    return "Record<string, unknown>";
  }
  if (column.typeKind === "domain" || column.typeKind === "range" || column.typeKind === "multirange") {
    return "string";
  }
  return resolveScalarType(column);
}
function resolvePostgresColumnType(column) {
  const baseType = resolveKindAwareType(column);
  if (!column.arrayDimensions || column.arrayDimensions <= 0) {
    return baseType;
  }
  return wrapArrayType(baseType, column.arrayDimensions);
}

// src/gateway/errors.ts
var AthenaGatewayError = class _AthenaGatewayError extends Error {
  code;
  status;
  endpoint;
  method;
  requestId;
  hint;
  causeDetail;
  constructor(input) {
    super(input.message);
    this.name = "AthenaGatewayError";
    this.code = input.code;
    this.status = input.status ?? 0;
    this.endpoint = input.endpoint;
    this.method = input.method;
    this.requestId = input.requestId;
    this.hint = input.hint;
    this.causeDetail = input.cause;
  }
  toDetails() {
    return {
      code: this.code,
      message: this.message,
      status: this.status,
      endpoint: this.endpoint,
      method: this.method,
      requestId: this.requestId,
      hint: this.hint,
      cause: this.causeDetail
    };
  }
  static fromResponse(response, fallback) {
    const details = response.errorDetails;
    if (details) {
      return new _AthenaGatewayError({
        code: details.code,
        message: details.message,
        status: details.status,
        endpoint: details.endpoint ?? fallback.endpoint,
        method: details.method ?? fallback.method,
        requestId: details.requestId ?? fallback.requestId,
        hint: details.hint,
        cause: details.cause
      });
    }
    return new _AthenaGatewayError({
      code: "HTTP_ERROR",
      message: response.error ?? "Gateway request failed",
      status: response.status,
      endpoint: fallback.endpoint,
      method: fallback.method,
      requestId: fallback.requestId
    });
  }
};

// src/auxiliaries.ts
function parseBooleanFlag(rawValue, fallback) {
  if (!rawValue) return fallback;
  const normalized = rawValue.trim().toLowerCase();
  if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
    return true;
  }
  if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
    return false;
  }
  return fallback;
}

// src/generator/schema-selection.ts
var DEFAULT_POSTGRES_SCHEMAS = ["public"];
function collectSchemaNames(input) {
  if (!input) {
    return [];
  }
  const values = typeof input === "string" ? [input] : input;
  return values.flatMap((value) => String(value).split(","));
}
function normalizeSchemaSelection(input) {
  const schemas = [];
  const seen = /* @__PURE__ */ new Set();
  for (const value of collectSchemaNames(input)) {
    const schema = value.trim();
    if (!schema || seen.has(schema)) {
      continue;
    }
    seen.add(schema);
    schemas.push(schema);
  }
  return schemas.length > 0 ? schemas : [...DEFAULT_POSTGRES_SCHEMAS];
}
function resolveProviderSchemas(providerConfig) {
  if (providerConfig.kind === "postgres") {
    return normalizeSchemaSelection(providerConfig.schemas);
  }
  return [...DEFAULT_POSTGRES_SCHEMAS];
}

// src/generator/config.ts
var DEFAULT_CONFIG_CANDIDATES = [
  "athena.config.ts",
  "athena.config.js",
  "athena-js.config.ts",
  "athena-js.config.js",
  ".athena.config.ts",
  ".athena.config.js"
];
var DEFAULT_TARGETS = {
  model: "athena/models/{schema_kebab}/{model_kebab}.ts",
  schema: "athena/schemas/{schema_kebab}.ts",
  database: "athena/relations.ts",
  registry: "athena/config.ts"
};
var DEFAULT_NAMING = {
  modelType: "pascal",
  modelConst: "camel",
  schemaConst: "camel",
  databaseConst: "camel",
  registryConst: "camel"
};
var DEFAULT_FEATURES = {
  emitRelations: true,
  emitRegistry: true
};
var DEFAULT_EXPERIMENTAL_FLAGS = {
  postgresGatewayIntrospection: false,
  scyllaProviderContracts: true
};
function normalizeBooleanFlag(rawValue, fallback) {
  if (typeof rawValue === "boolean") {
    return rawValue;
  }
  if (typeof rawValue === "string") {
    return parseBooleanFlag(rawValue, fallback);
  }
  return fallback;
}
function normalizeFeatureFlags(input) {
  return {
    emitRelations: normalizeBooleanFlag(
      input?.emitRelations,
      DEFAULT_FEATURES.emitRelations
    ),
    emitRegistry: normalizeBooleanFlag(
      input?.emitRegistry,
      DEFAULT_FEATURES.emitRegistry
    )
  };
}
function normalizeExperimentalFlags(input) {
  return {
    postgresGatewayIntrospection: normalizeBooleanFlag(
      input?.postgresGatewayIntrospection,
      DEFAULT_EXPERIMENTAL_FLAGS.postgresGatewayIntrospection
    ),
    scyllaProviderContracts: normalizeBooleanFlag(
      input?.scyllaProviderContracts,
      DEFAULT_EXPERIMENTAL_FLAGS.scyllaProviderContracts
    )
  };
}
function normalizeOutputConfig(output) {
  return {
    targets: {
      ...DEFAULT_TARGETS,
      ...output.targets ?? {}
    },
    placeholderMap: {
      ...output.placeholderMap ?? {}
    }
  };
}
function normalizeProviderConfig(provider) {
  if (provider.kind === "postgres") {
    return {
      ...provider,
      schemas: normalizeSchemaSelection(provider.schemas)
    };
  }
  return provider;
}
function isAthenaGeneratorConfig(value) {
  if (!value || typeof value !== "object") {
    return false;
  }
  const record = value;
  return Boolean(record.provider && typeof record.provider === "object") && Boolean(record.output && typeof record.output === "object");
}
function normalizeGeneratorConfig(input) {
  return {
    provider: normalizeProviderConfig(input.provider),
    output: normalizeOutputConfig(input.output),
    naming: {
      ...DEFAULT_NAMING,
      ...input.naming ?? {}
    },
    features: normalizeFeatureFlags(input.features),
    experimental: normalizeExperimentalFlags(input.experimental)
  };
}
function findGeneratorConfigPath(cwd = process.cwd()) {
  for (const candidate of DEFAULT_CONFIG_CANDIDATES) {
    const absolutePath = resolve(cwd, candidate);
    if (existsSync(absolutePath)) {
      return absolutePath;
    }
  }
  return void 0;
}
function extractConfigExport(module) {
  const visited = /* @__PURE__ */ new Set();
  const queue = [module];
  while (queue.length > 0) {
    const current = queue.shift();
    if (!current || typeof current !== "object" || visited.has(current)) {
      continue;
    }
    visited.add(current);
    const record = current;
    if (isAthenaGeneratorConfig(record)) {
      return record;
    }
    const defaultExport = record.default;
    if (defaultExport && typeof defaultExport === "object") {
      queue.push(defaultExport);
    }
    const namedConfigExport = record.config;
    if (namedConfigExport && typeof namedConfigExport === "object") {
      queue.push(namedConfigExport);
    }
    const moduleExports = record["module.exports"];
    if (moduleExports && typeof moduleExports === "object") {
      queue.push(moduleExports);
    }
  }
  throw new Error(
    "Generator config file must export a config object as default export or `config`."
  );
}
function importConfigModule(moduleSpecifier) {
  const runtimeImport = new Function(
    "moduleSpecifier",
    "return import(moduleSpecifier)"
  );
  return runtimeImport(moduleSpecifier);
}
async function loadGeneratorConfig(options = {}) {
  const cwd = options.cwd ?? process.cwd();
  const resolvedPath = options.configPath ? resolve(cwd, options.configPath) : findGeneratorConfigPath(cwd);
  if (!resolvedPath) {
    throw new Error(
      `No generator config found in ${cwd}. Expected one of: ${DEFAULT_CONFIG_CANDIDATES.join(", ")}`
    );
  }
  const moduleUrl = pathToFileURL(resolvedPath);
  const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
  const rawConfig = extractConfigExport(module);
  return {
    configPath: resolvedPath,
    config: normalizeGeneratorConfig(rawConfig)
  };
}

// src/generator/renderer.ts
function normalizePath(pathValue) {
  return pathValue.replace(/\\/g, "/");
}
function withoutTypeScriptExtension(pathValue) {
  return pathValue.replace(/\.tsx?$/i, "");
}
function toModuleImportPath(fromFile, targetFile) {
  const relativePath = withoutTypeScriptExtension(
    normalizePath(posix.relative(posix.dirname(fromFile), targetFile))
  );
  return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
}
function renderObjectKey(key) {
  const escaped = escapeTypePropertyName(key);
  return escaped.startsWith("'") ? escaped : escaped;
}
function renderRelation(relation) {
  const through = relation.through ? `,
      through: {
        schema: ${escapeStringLiteral(relation.through.schema)},
        model: ${escapeStringLiteral(relation.through.model)},
        sourceColumns: [${relation.through.sourceColumns.map((value) => escapeStringLiteral(value)).join(", ")}],
        targetColumns: [${relation.through.targetColumns.map((value) => escapeStringLiteral(value)).join(", ")}],
      }` : "";
  return `{
      kind: ${escapeStringLiteral(relation.kind)},
      sourceColumns: [${relation.sourceColumns.map((value) => escapeStringLiteral(value)).join(", ")}],
      targetSchema: ${escapeStringLiteral(relation.targetSchema)},
      targetModel: ${escapeStringLiteral(relation.targetModel)},
      targetColumns: [${relation.targetColumns.map((value) => escapeStringLiteral(value)).join(", ")}]${through}
    }`;
}
function renderModelArtifact(snapshot, descriptor, config) {
  const columnLines = Object.values(descriptor.table.columns).map((column) => {
    const propertyName = escapeTypePropertyName(column.name);
    const baseType = resolvePostgresColumnType(column);
    const isOptional = column.isNullable;
    const typeWithNullability = column.isNullable ? `${baseType} | null` : baseType;
    return `  ${propertyName}${isOptional ? "?" : ""}: ${typeWithNullability}`;
  }).join("\n");
  const nullableLines = Object.values(descriptor.table.columns).map((column) => `      ${renderObjectKey(column.name)}: ${column.isNullable ? "true" : "false"}`).join(",\n");
  const relationEntries = Object.entries(descriptor.table.relations);
  const relationBlock = config.features.emitRelations && relationEntries.length > 0 ? `,
    relations: {
${relationEntries.map(([relationKey2, relationValue]) => `      ${renderObjectKey(relationKey2)}: ${renderRelation(relationValue)}`).join(",\n")}
    }` : "";
  const content = `import { defineModel } from '@xylex-group/athena'

export interface ${descriptor.rowTypeName} {
${columnLines}
}

export type ${descriptor.insertTypeName} = Partial<${descriptor.rowTypeName}>
export type ${descriptor.updateTypeName} = Partial<${descriptor.insertTypeName}>

export const ${descriptor.modelConstName} = defineModel<${descriptor.rowTypeName}, ${descriptor.insertTypeName}, ${descriptor.updateTypeName}>({
  meta: {
    database: ${escapeStringLiteral(snapshot.database)},
    schema: ${escapeStringLiteral(descriptor.schemaName)},
    model: ${escapeStringLiteral(descriptor.tableName)},
    tableName: ${escapeStringLiteral(`${descriptor.schemaName}.${descriptor.tableName}`)},
    primaryKey: [${descriptor.table.primaryKey.map((value) => escapeStringLiteral(value)).join(", ")}],
    nullable: {
${nullableLines}
    }${relationBlock}
  }
})
`;
  return {
    kind: "model",
    path: descriptor.filePath,
    content
  };
}
function renderSchemaArtifact(descriptor) {
  const importLines = descriptor.models.map((modelDescriptor) => {
    const importPath = toModuleImportPath(descriptor.filePath, modelDescriptor.filePath);
    return `import { ${modelDescriptor.modelConstName} } from '${importPath}'`;
  }).join("\n");
  const modelEntries = descriptor.models.map((modelDescriptor) => `  ${renderObjectKey(modelDescriptor.tableName)}: ${modelDescriptor.modelConstName}`).join(",\n");
  const content = `import { defineSchema } from '@xylex-group/athena'
${importLines ? `
${importLines}
` : "\n"}
export const ${descriptor.schemaConstName} = defineSchema({
${modelEntries}
})
`;
  return {
    kind: "schema",
    path: descriptor.filePath,
    content
  };
}
function renderDatabaseArtifact(descriptor) {
  const importLines = descriptor.schemas.map((schemaDescriptor) => {
    const importPath = toModuleImportPath(descriptor.filePath, schemaDescriptor.filePath);
    return `import { ${schemaDescriptor.schemaConstName} } from '${importPath}'`;
  }).join("\n");
  const schemaEntries = descriptor.schemas.map((schemaDescriptor) => `  ${renderObjectKey(schemaDescriptor.schemaName)}: ${schemaDescriptor.schemaConstName}`).join(",\n");
  const content = `import { defineDatabase } from '@xylex-group/athena'
${importLines ? `
${importLines}
` : "\n"}
export const ${descriptor.databaseConstName} = defineDatabase({
${schemaEntries}
})
`;
  return {
    kind: "database",
    path: descriptor.filePath,
    content
  };
}
function renderRegistryArtifact(registryPath, databasePath, databaseConstName, registryConstName, databaseName) {
  const databaseImportPath = toModuleImportPath(registryPath, databasePath);
  const content = `import { defineRegistry } from '@xylex-group/athena'
import { ${databaseConstName} } from '${databaseImportPath}'

export const ${registryConstName} = defineRegistry({
  ${renderObjectKey(databaseName)}: ${databaseConstName}
})
`;
  return {
    kind: "registry",
    path: registryPath,
    content
  };
}
function assertNoDuplicatePaths(files) {
  const seen = /* @__PURE__ */ new Map();
  for (const file of files) {
    const existing = seen.get(file.path);
    if (existing) {
      throw new Error(
        [
          `Generator output collision detected for path: ${file.path}`,
          `Collision: ${existing.kind} and ${file.kind}.`,
          "When syncing multiple schemas, include a schema placeholder such as {schema} or {schema_kebab} in model/schema output targets."
        ].join(" ")
      );
    }
    seen.set(file.path, file);
  }
}
var ArtifactComposer = class {
  constructor(snapshot, config) {
    this.snapshot = snapshot;
    this.config = config;
  }
  compose() {
    const providerName = this.snapshot.backend;
    const databaseName = this.snapshot.database;
    const modelDescriptors = [];
    for (const schemaName of Object.keys(this.snapshot.schemas).sort()) {
      const schema = this.snapshot.schemas[schemaName];
      for (const tableName of Object.keys(schema.tables).sort()) {
        const table = schema.tables[tableName];
        const rowTypeName = `${toSafeIdentifier(`${schemaName} ${tableName}`, this.config.naming.modelType, "Model")}Row`;
        const insertTypeName = `${toSafeIdentifier(`${schemaName} ${tableName}`, this.config.naming.modelType, "Model")}Insert`;
        const updateTypeName = `${toSafeIdentifier(`${schemaName} ${tableName}`, this.config.naming.modelType, "Model")}Update`;
        const modelConstName = `${toSafeIdentifier(`${schemaName} ${tableName} model`, this.config.naming.modelConst, "model")}`;
        const modelPath = normalizePath(
          renderOutputPath(this.config.output.targets.model, {
            provider: providerName,
            kind: "model",
            database: databaseName,
            schema: schemaName,
            model: tableName
          }, this.config.output)
        );
        modelDescriptors.push({
          schemaName,
          tableName,
          filePath: modelPath,
          rowTypeName,
          insertTypeName,
          updateTypeName,
          modelConstName,
          table
        });
      }
    }
    const schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
      const schemaPath = normalizePath(
        renderOutputPath(this.config.output.targets.schema, {
          provider: providerName,
          kind: "schema",
          database: databaseName,
          schema: schemaName,
          model: "index"
        }, this.config.output)
      );
      return {
        schemaName,
        filePath: schemaPath,
        schemaConstName: toSafeIdentifier(
          `${schemaName} schema`,
          this.config.naming.schemaConst,
          "schema"
        ),
        models: modelDescriptors.filter((model) => model.schemaName === schemaName)
      };
    });
    const databasePath = normalizePath(
      renderOutputPath(this.config.output.targets.database, {
        provider: providerName,
        kind: "database",
        database: databaseName,
        schema: "index",
        model: "index"
      }, this.config.output)
    );
    const databaseDescriptor = {
      filePath: databasePath,
      databaseConstName: toSafeIdentifier(
        `${databaseName} database`,
        this.config.naming.databaseConst,
        "database"
      ),
      schemas: schemaDescriptors
    };
    const files = [];
    for (const modelDescriptor of modelDescriptors) {
      files.push(renderModelArtifact(this.snapshot, modelDescriptor, this.config));
    }
    for (const schemaDescriptor of schemaDescriptors) {
      files.push(renderSchemaArtifact(schemaDescriptor));
    }
    files.push(renderDatabaseArtifact(databaseDescriptor));
    if (this.config.features.emitRegistry) {
      const registryPath = normalizePath(
        renderOutputPath(this.config.output.targets.registry, {
          provider: providerName,
          kind: "registry",
          database: databaseName,
          schema: "index",
          model: "index"
        }, this.config.output)
      );
      files.push(
        renderRegistryArtifact(
          registryPath,
          databaseDescriptor.filePath,
          databaseDescriptor.databaseConstName,
          toSafeIdentifier("registry", this.config.naming.registryConst, "registry"),
          databaseName
        )
      );
    }
    assertNoDuplicatePaths(files);
    return {
      snapshot: this.snapshot,
      files
    };
  }
};
function generateArtifactsFromSnapshot(snapshot, config) {
  const normalizedConfig = "naming" in config && "features" in config && "experimental" in config ? config : normalizeGeneratorConfig(config);
  return new ArtifactComposer(snapshot, normalizedConfig).compose();
}

// src/gateway/client.ts
var DEFAULT_BASE_URL = "https://athena-db.com";
var DEFAULT_CLIENT = "railway_direct";
var FALLBACK_SDK_VERSION = "1.3.0";
var SDK_NAME = "xylex-group/athena";
var SDK_VERSION = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION;
var SDK_HEADER_VALUE = `${SDK_NAME} ${SDK_VERSION}`;
function parseResponseBody(rawText, contentType) {
  if (!rawText) {
    return { parsed: null, parseFailed: false };
  }
  const contentTypeSuggestsJson = contentType?.toLowerCase().includes("application/json") ?? false;
  const looksJson = contentTypeSuggestsJson || rawText.startsWith("{") || rawText.startsWith("[");
  if (!looksJson) {
    return { parsed: rawText, parseFailed: false };
  }
  try {
    return { parsed: JSON.parse(rawText), parseFailed: false };
  } catch {
    return { parsed: rawText, parseFailed: true };
  }
}
function normalizeHeaderValue(value) {
  return value ? value : void 0;
}
function isRecord(value) {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}
function resolveRequestId(headers) {
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
}
function resolveErrorMessage(payload, fallback) {
  if (isRecord(payload)) {
    const messageCandidates = [payload.error, payload.message, payload.details];
    for (const candidate of messageCandidates) {
      if (typeof candidate === "string" && candidate.trim().length > 0) {
        return candidate.trim();
      }
    }
  }
  if (typeof payload === "string" && payload.trim().length > 0) {
    return payload.trim();
  }
  return fallback;
}
function detailsFromError(error) {
  return error.toDetails();
}
function toQueryScalar(value) {
  if (value === null || value === void 0) return "null";
  if (typeof value === "boolean") return value ? "true" : "false";
  if (typeof value === "number") return Number.isFinite(value) ? String(value) : "null";
  return String(value);
}
function toQueryArray(values) {
  return `{${values.map(toQueryScalar).join(",")}}`;
}
function toRpcArgumentQueryValue(value) {
  if (Array.isArray(value)) return toQueryArray(value);
  if (value && typeof value === "object") return JSON.stringify(value);
  return toQueryScalar(value);
}
function toRpcFilterQueryValue(filter) {
  const value = filter.value;
  switch (filter.operator) {
    case "in": {
      if (!Array.isArray(value)) {
        throw new AthenaGatewayError({
          code: "UNKNOWN_ERROR",
          message: `RPC filter "${filter.column}" with operator "in" requires an array value`,
          status: 0
        });
      }
      return `in.${toQueryArray(value)}`;
    }
    case "is":
      return `is.${toQueryScalar(value)}`;
    case "eq":
    case "neq":
    case "gt":
    case "gte":
    case "lt":
    case "lte":
    case "like":
    case "ilike":
      return `${filter.operator}.${toQueryScalar(value)}`;
  }
}
function buildRpcGetEndpoint(payload) {
  const functionName = (payload.function_name ?? payload.function).trim();
  if (!functionName) {
    throw new AthenaGatewayError({
      code: "UNKNOWN_ERROR",
      message: "rpc requires a function name",
      status: 0,
      endpoint: "/gateway/rpc",
      method: "GET"
    });
  }
  const query = new URLSearchParams();
  if (payload.schema) query.set("schema", payload.schema);
  if (payload.select) query.set("select", payload.select);
  if (payload.count) query.set("count", payload.count);
  if (payload.head) query.set("head", "true");
  if (typeof payload.limit === "number") query.set("limit", String(payload.limit));
  if (typeof payload.offset === "number") query.set("offset", String(payload.offset));
  if (payload.order?.column) {
    query.set(
      "order",
      payload.order.ascending === false ? `${payload.order.column}.desc` : payload.order.column
    );
  }
  if (payload.args) {
    for (const [key, value] of Object.entries(payload.args)) {
      query.set(key, toRpcArgumentQueryValue(value));
    }
  }
  if (payload.filters?.length) {
    for (const filter of payload.filters) {
      if (payload.args && Object.prototype.hasOwnProperty.call(payload.args, filter.column)) {
        throw new AthenaGatewayError({
          code: "UNKNOWN_ERROR",
          message: `RPC filter "${filter.column}" conflicts with RPC argument "${filter.column}" in GET mode`,
          status: 0
        });
      }
      query.set(filter.column, toRpcFilterQueryValue(filter));
    }
  }
  const endpoint = `/rpc/${encodeURIComponent(functionName)}`;
  const queryText = query.toString();
  const withQuery = queryText ? `${endpoint}?${queryText}` : endpoint;
  return withQuery;
}
function buildHeaders(config, options) {
  const mergedStripNulls = options?.stripNulls ?? true;
  const extraHeaders = {
    ...config.headers ?? {},
    ...options?.headers ?? {}
  };
  const headerClient = extraHeaders["x-athena-client"] ?? extraHeaders["X-Athena-Client"];
  const finalClient = options?.client ?? config.client ?? (typeof headerClient === "string" ? headerClient : void 0) ?? DEFAULT_CLIENT;
  const finalApiKey = options?.apiKey ?? config.apiKey;
  const finalPublishEvent = options?.publishEvent ?? config.publishEvent;
  const headers = {
    "Content-Type": "application/json",
    "X-Athena-Sdk": SDK_HEADER_VALUE
  };
  if (options?.userId ?? config.userId) {
    headers["X-User-Id"] = options?.userId ?? config.userId ?? "";
  }
  if (options?.organizationId ?? config.organizationId) {
    headers["X-Organization-Id"] = options?.organizationId ?? config.organizationId ?? "";
  }
  if (finalClient) {
    headers["X-Athena-Client"] = finalClient;
  }
  const finalBackend = options?.backend ?? config.backend;
  if (finalBackend) {
    const type = typeof finalBackend === "string" ? finalBackend : finalBackend.type;
    if (type) headers["X-Backend-Type"] = type;
  }
  if (typeof mergedStripNulls === "boolean") {
    headers["X-Strip-Nulls"] = mergedStripNulls ? "true" : "false";
  }
  if (finalPublishEvent) {
    headers["X-Publish-Event"] = finalPublishEvent;
  }
  if (finalApiKey) {
    headers["apikey"] = finalApiKey;
    headers["x-api-key"] = headers["x-api-key"] ?? finalApiKey;
  }
  const athenaClientKeys = ["x-athena-client", "X-Athena-Client"];
  Object.entries(extraHeaders).forEach(([key, value]) => {
    if (athenaClientKeys.includes(key)) return;
    const normalized = normalizeHeaderValue(value);
    if (normalized) {
      headers[key] = normalized;
    }
  });
  return headers;
}
async function callAthena(config, endpoint, method, payload, options) {
  const baseUrl = (options?.baseUrl ?? config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
  const url = `${baseUrl}${endpoint}`;
  const headers = buildHeaders(config, options);
  try {
    const requestInit = {
      method,
      headers
    };
    if (method !== "GET") {
      requestInit.body = JSON.stringify(payload);
    }
    const response = await fetch(url, requestInit);
    const rawText = await response.text();
    const requestId = resolveRequestId(response.headers);
    const parsedBody = parseResponseBody(
      rawText ?? "",
      response.headers.get("content-type")
    );
    if (parsedBody.parseFailed) {
      const invalidJsonError = new AthenaGatewayError({
        code: "INVALID_JSON",
        message: "Gateway returned malformed JSON",
        status: response.status,
        endpoint,
        method,
        requestId,
        hint: "Verify the gateway response body is valid JSON.",
        cause: rawText.slice(0, 300)
      });
      return {
        ok: false,
        status: response.status,
        data: null,
        error: invalidJsonError.message,
        errorDetails: detailsFromError(invalidJsonError),
        raw: parsedBody.parsed
      };
    }
    const parsed = parsedBody.parsed;
    const parsedPayload = isRecord(parsed) ? parsed : null;
    if (!response.ok) {
      const httpError = new AthenaGatewayError({
        code: "HTTP_ERROR",
        message: resolveErrorMessage(
          parsed,
          `Athena gateway ${method} ${endpoint} failed with status ${response.status}`
        ),
        status: response.status,
        endpoint,
        method,
        requestId
      });
      return {
        ok: false,
        status: response.status,
        data: null,
        error: httpError.message,
        errorDetails: detailsFromError(httpError),
        raw: parsed
      };
    }
    const payloadData = parsedPayload && "data" in parsedPayload ? parsedPayload.data : parsed;
    const payloadCount = parsedPayload && "count" in parsedPayload ? typeof parsedPayload.count === "number" || parsedPayload.count === null ? parsedPayload.count : void 0 : void 0;
    return {
      ok: true,
      status: response.status,
      data: payloadData ?? null,
      count: payloadCount,
      error: void 0,
      errorDetails: null,
      raw: parsed
    };
  } catch (callError) {
    const message = callError instanceof Error ? callError.message : String(callError);
    const networkError = new AthenaGatewayError({
      code: "NETWORK_ERROR",
      message: `Network error while calling ${method} ${endpoint}: ${message}`,
      endpoint,
      method,
      cause: message,
      hint: "Check gateway URL, DNS, and network reachability."
    });
    return {
      ok: false,
      status: 0,
      data: null,
      error: networkError.message,
      errorDetails: detailsFromError(networkError),
      raw: null
    };
  }
}
function createAthenaGatewayClient(config = {}) {
  return {
    baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, ""),
    buildHeaders(options) {
      return buildHeaders(config, options);
    },
    fetchGateway(payload, options) {
      return callAthena(config, "/gateway/fetch", "POST", payload, options);
    },
    insertGateway(payload, options) {
      return callAthena(config, "/gateway/insert", "PUT", payload, options);
    },
    updateGateway(payload, options) {
      return callAthena(config, "/gateway/update", "POST", payload, options);
    },
    deleteGateway(payload, options) {
      return callAthena(config, "/gateway/delete", "DELETE", payload, options);
    },
    rpcGateway(payload, options) {
      if (options?.get) {
        const endpoint = buildRpcGetEndpoint(payload);
        return callAthena(config, endpoint, "GET", null, options);
      }
      return callAthena(config, "/gateway/rpc", "POST", payload, options);
    },
    queryGateway(payload, options) {
      return callAthena(config, "/gateway/query", "POST", payload, options);
    }
  };
}

// src/sql-identifiers.ts
var SIMPLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
var COMPOSITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
var ALIAS_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
function quoteIdentifierSegment(identifier) {
  return `"${identifier.replace(/"/g, '""')}"`;
}
function quoteQualifiedIdentifier(identifier) {
  return identifier.split(".").map((segment) => quoteIdentifierSegment(segment)).join(".");
}
function quoteSelectToken(token) {
  if (token === "*") return token;
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) {
    return quoteQualifiedIdentifier(token);
  }
  const aliasMatch = ALIAS_PATTERN.exec(token);
  if (!aliasMatch) {
    return token;
  }
  const [, baseIdentifier, aliasIdentifier] = aliasMatch;
  if (!COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) || !SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier)) {
    return token;
  }
  return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteIdentifierSegment(aliasIdentifier)}`;
}
function canAutoQuoteToken(token) {
  if (token === "*") return true;
  if (COMPOSITE_IDENTIFIER_PATTERN.test(token)) return true;
  const aliasMatch = ALIAS_PATTERN.exec(token);
  if (!aliasMatch) return false;
  const [, baseIdentifier, aliasIdentifier] = aliasMatch;
  return COMPOSITE_IDENTIFIER_PATTERN.test(baseIdentifier) && SIMPLE_IDENTIFIER_PATTERN.test(aliasIdentifier);
}
function splitTopLevelCommaSeparated(input) {
  const parts = [];
  let buffer = "";
  let singleQuoted = false;
  let doubleQuoted = false;
  let depth = 0;
  for (let index = 0; index < input.length; index += 1) {
    const char = input[index];
    const next = index + 1 < input.length ? input[index + 1] : "";
    if (singleQuoted) {
      buffer += char;
      if (char === "'" && next === "'") {
        buffer += next;
        index += 1;
        continue;
      }
      if (char === "'") {
        singleQuoted = false;
      }
      continue;
    }
    if (doubleQuoted) {
      buffer += char;
      if (char === '"' && next === '"') {
        buffer += next;
        index += 1;
        continue;
      }
      if (char === '"') {
        doubleQuoted = false;
      }
      continue;
    }
    if (char === "'") {
      singleQuoted = true;
      buffer += char;
      continue;
    }
    if (char === '"') {
      doubleQuoted = true;
      buffer += char;
      continue;
    }
    if (char === "(") {
      depth += 1;
      buffer += char;
      continue;
    }
    if (char === ")") {
      depth -= 1;
      if (depth < 0) return null;
      buffer += char;
      continue;
    }
    if (char === "," && depth === 0) {
      parts.push(buffer.trim());
      buffer = "";
      continue;
    }
    buffer += char;
  }
  if (singleQuoted || doubleQuoted || depth !== 0) {
    return null;
  }
  if (buffer.trim().length > 0) {
    parts.push(buffer.trim());
  }
  return parts;
}
function quoteSelectColumnsExpression(columns) {
  const trimmed = columns.trim();
  if (!trimmed || trimmed === "*") return trimmed || "*";
  const tokens = splitTopLevelCommaSeparated(trimmed);
  if (!tokens || tokens.length === 0) {
    return trimmed;
  }
  if (!tokens.every(canAutoQuoteToken)) {
    return trimmed;
  }
  return tokens.map(quoteSelectToken).join(", ");
}

// src/auth/client.ts
var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
var FALLBACK_SDK_VERSION2 = "1.0.0";
var SDK_NAME2 = "xylex-group/athena-auth";
var SDK_VERSION2 = typeof process !== "undefined" && process?.env?.npm_package_version ? process.env.npm_package_version : FALLBACK_SDK_VERSION2;
var SDK_HEADER_VALUE2 = `${SDK_NAME2} ${SDK_VERSION2}`;
function normalizeBaseUrl(baseUrl) {
  return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
}
function isRecord2(value) {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}
function normalizeHeaderValue2(value) {
  return value ? value : void 0;
}
function parseResponseBody2(rawText, contentType) {
  if (!rawText) {
    return { parsed: null, parseFailed: false };
  }
  const contentTypeSuggestsJson = contentType?.toLowerCase().includes("application/json") ?? false;
  const looksJson = contentTypeSuggestsJson || rawText.startsWith("{") || rawText.startsWith("[");
  if (!looksJson) {
    return { parsed: rawText, parseFailed: false };
  }
  try {
    return { parsed: JSON.parse(rawText), parseFailed: false };
  } catch {
    return { parsed: rawText, parseFailed: true };
  }
}
function resolveRequestId2(headers) {
  return headers.get("x-request-id") ?? headers.get("x-correlation-id") ?? headers.get("x-athena-request-id") ?? void 0;
}
function resolveErrorMessage2(payload, fallback) {
  if (isRecord2(payload)) {
    const messageCandidates = [payload.error, payload.message, payload.details];
    for (const candidate of messageCandidates) {
      if (typeof candidate === "string" && candidate.trim().length > 0) {
        return candidate.trim();
      }
    }
  }
  if (typeof payload === "string" && payload.trim().length > 0) {
    return payload.trim();
  }
  return fallback;
}
function toErrorDetails(input) {
  return {
    code: input.code,
    message: input.message,
    status: input.status,
    endpoint: input.endpoint,
    method: input.method,
    requestId: input.requestId,
    hint: input.hint,
    cause: input.cause
  };
}
function mergeCallOptions(base, override) {
  if (!base && !override) return void 0;
  return {
    ...base,
    ...override,
    headers: {
      ...base?.headers ?? {},
      ...override?.headers ?? {}
    }
  };
}
function extractFetchOptions(input) {
  if (!input) {
    return {
      payload: void 0,
      fetchOptions: void 0
    };
  }
  const { fetchOptions, ...rest } = input;
  const hasPayloadKeys = Object.keys(rest).length > 0;
  return {
    payload: hasPayloadKeys ? rest : void 0,
    fetchOptions
  };
}
function buildHeaders2(config, options) {
  const headers = {
    "Content-Type": "application/json",
    "X-Athena-Sdk": SDK_HEADER_VALUE2
  };
  const apiKey = options?.apiKey ?? config.apiKey;
  if (apiKey) {
    headers.apikey = apiKey;
    headers["x-api-key"] = apiKey;
  }
  const bearerToken = options?.bearerToken ?? config.bearerToken;
  if (bearerToken) {
    headers.Authorization = `Bearer ${bearerToken}`;
  }
  const mergedExtraHeaders = {
    ...config.headers ?? {},
    ...options?.headers ?? {}
  };
  Object.entries(mergedExtraHeaders).forEach(([key, value]) => {
    const normalized = normalizeHeaderValue2(value);
    if (normalized) {
      headers[key] = normalized;
    }
  });
  return headers;
}
function appendQueryParam(searchParams, key, value) {
  if (value === void 0 || value === null) return;
  if (Array.isArray(value)) {
    value.forEach((item) => {
      searchParams.append(key, String(item));
    });
    return;
  }
  searchParams.append(key, String(value));
}
function buildRequestUrl(baseUrl, endpoint, query) {
  const url = `${baseUrl}${endpoint}`;
  if (!query || Object.keys(query).length === 0) return url;
  const searchParams = new URLSearchParams();
  Object.entries(query).forEach(([key, value]) => appendQueryParam(searchParams, key, value));
  const queryText = searchParams.toString();
  return queryText ? `${url}?${queryText}` : url;
}
function inferDefaultMethod(endpoint) {
  if (endpoint.startsWith("/reset-password/")) {
    return "GET";
  }
  switch (endpoint) {
    case "/get-session":
    case "/list-sessions":
    case "/verify-email":
    case "/change-email/verify":
    case "/delete-user/verify":
    case "/email-list":
    case "/email/list":
    case "/delete-user/callback":
    case "/list-accounts":
    case "/passkey/generate-register-options":
    case "/passkey/list-user-passkeys":
    case "/.well-known/webauthn":
    case "/admin/list-users":
    case "/admin/athena-client/list":
    case "/admin/audit-log/list":
    case "/admin/email/get":
    case "/admin/email-failure/list":
    case "/admin/email-failure/get":
    case "/admin/email-template/get":
    case "/admin/email-template/list":
    case "/admin/email/list":
    case "/api-key/get":
    case "/api-key/list":
    case "/organization/get-full-organization":
    case "/organization/list":
    case "/organization/get-invitation":
    case "/organization/list-invitations":
    case "/organization/list-user-invitations":
    case "/organization/list-members":
    case "/organization/get-active-member":
    case "/health":
    case "/ok":
    case "/error":
      return "GET";
    default:
      return "POST";
  }
}
async function callAuthEndpoint(config, context, body, query, options) {
  const baseUrl = normalizeBaseUrl(options?.baseUrl ?? config.baseUrl);
  const url = buildRequestUrl(baseUrl, context.endpoint, query);
  const headers = buildHeaders2(config, options);
  const credentials = options?.credentials ?? config.credentials ?? "include";
  const requestInit = {
    method: context.method,
    headers,
    credentials,
    signal: options?.signal
  };
  if (context.method !== "GET") {
    requestInit.body = JSON.stringify(body ?? {});
  }
  const fetcher = config.fetch ?? globalThis.fetch;
  if (!fetcher) {
    const details = toErrorDetails({
      code: "UNKNOWN_ERROR",
      message: "No fetch implementation available for auth client",
      status: 0,
      endpoint: context.endpoint,
      method: context.method,
      hint: "Use Node 18+ or provide `fetch` via createClient(..., { auth: { fetch } }) or createAuthClient({ fetch })"
    });
    return {
      ok: false,
      status: 0,
      data: null,
      error: details.message,
      errorDetails: details,
      raw: null
    };
  }
  try {
    const response = await fetcher(url, requestInit);
    const rawText = await response.text();
    const requestId = resolveRequestId2(response.headers);
    const parsedBody = parseResponseBody2(rawText ?? "", response.headers.get("content-type"));
    if (parsedBody.parseFailed) {
      const details = toErrorDetails({
        code: "INVALID_JSON",
        message: "Auth server returned malformed JSON",
        status: response.status,
        endpoint: context.endpoint,
        method: context.method,
        requestId,
        hint: "Verify the auth endpoint response body is valid JSON.",
        cause: rawText.slice(0, 300)
      });
      return {
        ok: false,
        status: response.status,
        data: null,
        error: details.message,
        errorDetails: details,
        raw: parsedBody.parsed
      };
    }
    const parsed = parsedBody.parsed;
    if (!response.ok) {
      const details = toErrorDetails({
        code: "HTTP_ERROR",
        message: resolveErrorMessage2(
          parsed,
          `Auth endpoint ${context.method} ${context.endpoint} failed with status ${response.status}`
        ),
        status: response.status,
        endpoint: context.endpoint,
        method: context.method,
        requestId
      });
      return {
        ok: false,
        status: response.status,
        data: null,
        error: details.message,
        errorDetails: details,
        raw: parsed
      };
    }
    return {
      ok: true,
      status: response.status,
      data: parsed ?? null,
      error: null,
      errorDetails: null,
      raw: parsed
    };
  } catch (callError) {
    const message = callError instanceof Error ? callError.message : String(callError);
    const details = toErrorDetails({
      code: "NETWORK_ERROR",
      message: `Network error while calling ${context.method} ${context.endpoint}: ${message}`,
      status: 0,
      endpoint: context.endpoint,
      method: context.method,
      cause: message,
      hint: "Check auth server URL, DNS, and network reachability."
    });
    return {
      ok: false,
      status: 0,
      data: null,
      error: details.message,
      errorDetails: details,
      raw: null
    };
  }
}
function executePostWithCompatibleInput(config, context, input, options) {
  const { payload, fetchOptions } = extractFetchOptions(input);
  const mergedOptions = mergeCallOptions(fetchOptions, options);
  return callAuthEndpoint(config, context, payload ?? {}, void 0, mergedOptions);
}
function executePostWithOptionalInput(config, context, input, options) {
  const { fetchOptions } = extractFetchOptions(input);
  const mergedOptions = mergeCallOptions(fetchOptions, options);
  return callAuthEndpoint(config, context, {}, void 0, mergedOptions);
}
function executeGetWithCompatibleInput(config, context, input, options) {
  const { fetchOptions } = extractFetchOptions(input);
  const mergedOptions = mergeCallOptions(fetchOptions, options);
  return callAuthEndpoint(config, context, void 0, void 0, mergedOptions);
}
function executeGetWithQueryCompatibleInput(config, context, input, options) {
  const { payload, fetchOptions } = extractFetchOptions(input);
  const mergedOptions = mergeCallOptions(fetchOptions, options);
  const query = payload?.query;
  return callAuthEndpoint(
    config,
    context,
    void 0,
    query,
    mergedOptions
  );
}
function createAuthClient(config = {}) {
  const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
  const resolvedConfig = {
    ...config,
    baseUrl: normalizedBaseUrl
  };
  const request = (input, options) => {
    const method = input.method ?? (input.body !== void 0 ? "POST" : inferDefaultMethod(input.endpoint));
    const mergedOptions = mergeCallOptions(input.fetchOptions, options);
    return callAuthEndpoint(
      resolvedConfig,
      { endpoint: input.endpoint, method },
      input.body,
      input.query,
      mergedOptions
    );
  };
  const postGeneric = (endpoint, input, options) => {
    const { payload, fetchOptions } = extractFetchOptions(input);
    return request(
      {
        endpoint,
        method: "POST",
        body: payload ?? {},
        fetchOptions
      },
      options
    );
  };
  const getGeneric = (endpoint, input, options) => {
    const { fetchOptions } = extractFetchOptions(input);
    return request(
      {
        endpoint,
        method: "GET",
        fetchOptions
      },
      options
    );
  };
  const getWithQuery = (endpoint, input, options) => {
    const { payload, fetchOptions } = extractFetchOptions(input);
    const query = payload?.query;
    return request(
      {
        endpoint,
        method: "GET",
        query,
        fetchOptions
      },
      options
    );
  };
  const listUserEmailsWithFallback = async (input, options) => {
    const primary = await getWithQuery(
      "/email/list",
      input,
      options
    );
    if (primary.ok || primary.status !== 404 || primary.errorDetails?.code !== "HTTP_ERROR") {
      return primary;
    }
    return getWithQuery(
      "/email-list",
      input,
      options
    );
  };
  const healthWithFallback = async (input, options) => {
    const primary = await getGeneric("/health", input, options);
    if (primary.ok || primary.status !== 404 || primary.errorDetails?.code !== "HTTP_ERROR") {
      return primary;
    }
    const fallback = await getGeneric("/ok", input, options);
    if (!fallback.ok) {
      return {
        ...fallback,
        data: null
      };
    }
    const fallbackStatus = isRecord2(fallback.data) && typeof fallback.data.ok === "boolean" ? fallback.data.ok ? "ok" : "error" : "ok";
    return {
      ...fallback,
      data: {
        status: fallbackStatus
      }
    };
  };
  const signOut = (input, options) => executePostWithOptionalInput(
    resolvedConfig,
    { endpoint: "/sign-out", method: "POST" },
    input,
    options
  );
  const revokeSessions = (input, options) => executePostWithOptionalInput(
    resolvedConfig,
    { endpoint: "/revoke-sessions", method: "POST" },
    input,
    options
  );
  const revokeOtherSessions = (input, options) => executePostWithOptionalInput(
    resolvedConfig,
    { endpoint: "/revoke-other-sessions", method: "POST" },
    input,
    options
  );
  const revokeSession = (input, options) => executePostWithCompatibleInput(
    resolvedConfig,
    { endpoint: "/revoke-session", method: "POST" },
    input,
    options
  );
  const deleteUser = (input, options) => {
    const { payload, fetchOptions } = extractFetchOptions(input);
    const mergedOptions = mergeCallOptions(fetchOptions, options);
    return callAuthEndpoint(
      resolvedConfig,
      { endpoint: "/delete-user", method: "POST" },
      payload ?? {},
      void 0,
      mergedOptions
    );
  };
  const deleteUserCallback = (input, options) => {
    const { payload, fetchOptions } = extractFetchOptions(input);
    const mergedOptions = mergeCallOptions(fetchOptions, options);
    const query = payload ?? {};
    return callAuthEndpoint(
      resolvedConfig,
      { endpoint: "/delete-user/callback", method: "GET" },
      void 0,
      {
        token: query.token,
        callbackURL: query.callbackURL
      },
      mergedOptions
    );
  };
  const resolveResetPasswordToken = (input, options) => {
    const { payload, fetchOptions } = extractFetchOptions(input);
    const mergedOptions = mergeCallOptions(fetchOptions, options);
    const query = payload;
    const token = query?.token?.trim();
    if (!token) {
      throw new Error("resolveResetPasswordToken requires a non-empty token");
    }
    const endpoint = `/reset-password/${encodeURIComponent(token)}`;
    return callAuthEndpoint(
      resolvedConfig,
      { endpoint, method: "GET" },
      void 0,
      query?.callbackURL ? { callbackURL: query.callbackURL } : void 0,
      mergedOptions
    );
  };
  const organization = {
    create: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/organization/create", method: "POST" },
      input,
      options
    ),
    update: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/organization/update", method: "POST" },
      input,
      options
    ),
    delete: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/organization/delete", method: "POST" },
      input,
      options
    ),
    setActive: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/organization/set-active", method: "POST" },
      input,
      options
    ),
    list: (input, options) => getGeneric(
      "/organization/list",
      input,
      options
    ),
    getFull: (input, options) => executeGetWithQueryCompatibleInput(
      resolvedConfig,
      { endpoint: "/organization/get-full-organization", method: "GET" },
      input,
      options
    ),
    checkSlug: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/organization/check-slug", method: "POST" },
      input,
      options
    ),
    leave: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/organization/leave", method: "POST" },
      input,
      options
    ),
    listUserInvitations: (input, options) => executeGetWithQueryCompatibleInput(
      resolvedConfig,
      { endpoint: "/organization/list-user-invitations", method: "GET" },
      input,
      options
    ),
    hasPermission: (input, options) => postGeneric(
      "/organization/has-permission",
      input,
      options
    ),
    invitation: {
      cancel: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/cancel-invitation", method: "POST" },
        input,
        options
      ),
      accept: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/accept-invitation", method: "POST" },
        input,
        options
      ),
      get: (input, options) => executeGetWithQueryCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/get-invitation", method: "GET" },
        input,
        options
      ),
      reject: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/reject-invitation", method: "POST" },
        input,
        options
      ),
      list: (input, options) => executeGetWithQueryCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/list-invitations", method: "GET" },
        input,
        options
      )
    },
    member: {
      remove: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/remove-member", method: "POST" },
        input,
        options
      ),
      updateRole: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/update-member-role", method: "POST" },
        input,
        options
      ),
      invite: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/invite-member", method: "POST" },
        input,
        options
      ),
      getActive: (input, options) => executeGetWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/get-active-member", method: "GET" },
        input,
        options
      ),
      list: (input, options) => executeGetWithQueryCompatibleInput(
        resolvedConfig,
        { endpoint: "/organization/list-members", method: "GET" },
        input,
        options
      )
    }
  };
  const authResetPassword = Object.assign(
    (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/reset-password", method: "POST" },
      input,
      options
    ),
    {
      token: resolveResetPasswordToken
    }
  );
  const sessionRevokeBinding = (input, options) => {
    if (Array.isArray(input)) {
      if (input.length === 0) {
        throw new Error("session.revoke requires at least one session token");
      }
      if (input.length === 1) {
        return revokeSession(input[0], options);
      }
      return revokeSessions(void 0, options);
    }
    const parsed = input;
    const tokens = Array.isArray(parsed.tokens) ? parsed.tokens.filter((token2) => token2.trim().length > 0) : void 0;
    if (tokens && tokens.length > 1) {
      return revokeSessions(
        parsed.fetchOptions ? { fetchOptions: parsed.fetchOptions } : void 0,
        options
      );
    }
    if (tokens && tokens.length === 1) {
      return revokeSession(
        { token: tokens[0], fetchOptions: parsed.fetchOptions },
        options
      );
    }
    const token = parsed.token?.trim();
    if (!token) {
      throw new Error("session.revoke requires a non-empty token or a non-empty token list");
    }
    return revokeSession(
      {
        token,
        fetchOptions: parsed.fetchOptions
      },
      options
    );
  };
  const adminUserSessionRevokeBinding = (input, options) => {
    const requireUserId = (userId) => {
      const trimmed = String(userId ?? "").trim();
      if (!trimmed) {
        throw new Error("admin.user.session.revoke requires a non-empty userId");
      }
      return trimmed;
    };
    const requireSinglePluralUserId = (sessions2) => {
      const uniqueUserIds = [...new Set(sessions2.map((session) => requireUserId(session.userId)))];
      if (uniqueUserIds.length !== 1) {
        throw new Error("admin.user.session.revoke requires the same userId across plural payloads");
      }
      return { userId: uniqueUserIds[0] };
    };
    if (Array.isArray(input)) {
      if (input.length === 0) {
        throw new Error("admin.user.session.revoke requires at least one payload item");
      }
      if (input.length === 1) {
        return postGeneric(
          "/admin/revoke-user-session",
          {
            ...input[0],
            userId: requireUserId(input[0].userId)
          },
          options
        );
      }
      return postGeneric(
        "/admin/revoke-user-sessions",
        requireSinglePluralUserId(input),
        options
      );
    }
    const parsed = input;
    const sessions = parsed.sessions;
    if (sessions && sessions.length === 0) {
      throw new Error("admin.user.session.revoke requires at least one payload item");
    }
    if (sessions && sessions.length === 1) {
      return postGeneric(
        "/admin/revoke-user-session",
        {
          ...sessions[0],
          userId: requireUserId(sessions[0].userId),
          fetchOptions: parsed.fetchOptions
        },
        options
      );
    }
    if (sessions && sessions.length > 1) {
      return postGeneric(
        "/admin/revoke-user-sessions",
        {
          ...requireSinglePluralUserId(sessions),
          fetchOptions: parsed.fetchOptions
        },
        options
      );
    }
    const normalizedUserId = requireUserId(parsed.userId);
    if (!parsed.sessionToken) {
      return postGeneric(
        "/admin/revoke-user-sessions",
        {
          userId: normalizedUserId,
          fetchOptions: parsed.fetchOptions
        },
        options
      );
    }
    return postGeneric(
      "/admin/revoke-user-session",
      {
        ...parsed,
        userId: normalizedUserId
      },
      options
    );
  };
  const auth = {
    getSession: (input, options) => getGeneric("/get-session", input, options),
    signOut,
    forgetPassword: (input, options) => postGeneric("/forget-password", input, options),
    resetPassword: authResetPassword,
    setPassword: (input, options) => postGeneric("/set-password", input, options),
    verifyEmail: (input, options) => {
      const queryInput = {
        query: {
          token: input.token,
          callbackURL: input.callbackURL
        },
        fetchOptions: input.fetchOptions
      };
      return getWithQuery(
        "/verify-email",
        queryInput,
        options
      );
    },
    sendVerificationEmail: (input, options) => postGeneric("/send-verification-email", input, options),
    changeEmail: (input, options) => postGeneric("/change-email", input, options),
    changeEmailVerify: (input, options) => getWithQuery("/change-email/verify", input, options),
    deleteUserVerify: (input, options) => getWithQuery("/delete-user/verify", input, options),
    changePassword: (input, options) => postGeneric("/change-password", input, options),
    user: {
      update: (input, options) => postGeneric("/update-user", input, options),
      delete: (input, options) => postGeneric("/delete-user", input, options),
      email: {
        list: listUserEmailsWithFallback
      }
    },
    session: {
      list: (input, options) => getGeneric("/list-sessions", input, options),
      revoke: sessionRevokeBinding,
      revokeOther: revokeOtherSessions
    },
    social: {
      link: (input, options) => postGeneric("/link-social", input, options)
    },
    account: {
      list: (input, options) => getGeneric("/list-accounts", input, options),
      unlink: (input, options) => postGeneric("/unlink-account", input, options)
    },
    deleteUser: {
      callback: deleteUserCallback
    },
    refreshToken: (input, options) => postGeneric("/refresh-token", input, options),
    getAccessToken: (input, options) => postGeneric("/get-access-token", input, options),
    health: healthWithFallback,
    ok: (input, options) => getGeneric("/ok", input, options),
    error: (input, options) => getGeneric("/error", input, options),
    twoFactor: {
      getTotpUri: (input, options) => postGeneric("/two-factor/get-totp-uri", input, options),
      verifyTotp: (input, options) => postGeneric("/two-factor/verify-totp", input, options),
      sendOtp: (input, options) => postGeneric("/two-factor/send-otp", input, options),
      verifyOtp: (input, options) => postGeneric("/two-factor/verify-otp", input, options),
      verifyBackupCode: (input, options) => postGeneric("/two-factor/verify-backup-code", input, options),
      generateBackupCodes: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/two-factor/generate-backup-codes", method: "POST" },
        input,
        options
      ),
      enable: (input, options) => postGeneric("/two-factor/enable", input, options),
      disable: (input, options) => postGeneric("/two-factor/disable", input, options)
    },
    passkey: {
      generateRegisterOptions: (input, options) => getGeneric("/passkey/generate-register-options", input, options),
      generateAuthenticateOptions: (input, options) => postGeneric("/passkey/generate-authenticate-options", input, options),
      verifyRegistration: (input, options) => postGeneric("/passkey/verify-registration", input, options),
      verifyAuthentication: (input, options) => postGeneric("/passkey/verify-authentication", input, options),
      listUserPasskeys: (input, options) => getGeneric("/passkey/list-user-passkeys", input, options),
      deletePasskey: (input, options) => postGeneric("/passkey/delete-passkey", input, options),
      updatePasskey: (input, options) => postGeneric("/passkey/update-passkey", input, options),
      getRelatedOrigins: (input, options) => getGeneric("/.well-known/webauthn", input, options)
    },
    admin: {
      role: {
        set: (input, options) => postGeneric("/admin/set-role", input, options)
      },
      user: {
        list: (input, options) => getWithQuery("/admin/list-users", input, options),
        create: (input, options) => postGeneric("/admin/create-user", input, options),
        unban: (input, options) => postGeneric("/admin/unban-user", input, options),
        ban: (input, options) => postGeneric("/admin/ban-user", input, options),
        impersonate: (input, options) => postGeneric("/admin/impersonate-user", input, options),
        stopImpersonating: (input, options) => postGeneric("/admin/stop-impersonating", input, options),
        remove: (input, options) => postGeneric("/admin/remove-user", input, options),
        setPassword: (input, options) => postGeneric("/admin/set-user-password", input, options),
        session: {
          list: (input, options) => postGeneric("/admin/list-user-sessions", input, options),
          revoke: adminUserSessionRevokeBinding
        }
      },
      hasPermission: (input, options) => postGeneric("/admin/has-permission", input, options),
      apiKey: {
        create: (input, options) => postGeneric("/admin/api-key/create", input, options)
      },
      athenaClient: {
        create: (input, options) => postGeneric("/admin/athena-client/create", input, options),
        list: (input, options) => getWithQuery("/admin/athena-client/list", input, options)
      },
      auditLog: {
        list: (input, options) => getWithQuery("/admin/audit-log/list", input, options)
      },
      email: {
        list: (input, options) => getWithQuery("/admin/email/list", input, options),
        get: (input, options) => getWithQuery("/admin/email/get", input, options),
        create: (input, options) => postGeneric("/admin/email/create", input, options),
        update: (input, options) => postGeneric("/admin/email/update", input, options),
        delete: (input, options) => postGeneric("/admin/email/delete", input, options),
        failure: {
          list: (input, options) => getWithQuery("/admin/email-failure/list", input, options),
          get: (input, options) => getWithQuery("/admin/email-failure/get", input, options),
          create: (input, options) => postGeneric("/admin/email-failure/create", input, options),
          update: (input, options) => postGeneric("/admin/email-failure/update", input, options),
          delete: (input, options) => postGeneric("/admin/email-failure/delete", input, options)
        },
        template: {
          list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
          get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
          create: (input, options) => postGeneric("/admin/email-template/create", input, options),
          update: (input, options) => postGeneric("/admin/email-template/update", input, options),
          delete: (input, options) => postGeneric("/admin/email-template/delete", input, options)
        }
      },
      emailTemplate: {
        get: (input, options) => getWithQuery("/admin/email-template/get", input, options),
        create: (input, options) => postGeneric("/admin/email-template/create", input, options),
        delete: (input, options) => postGeneric("/admin/email-template/delete", input, options),
        list: (input, options) => getWithQuery("/admin/email-template/list", input, options),
        update: (input, options) => postGeneric("/admin/email-template/update", input, options)
      }
    },
    apiKey: {
      create: (input, options) => postGeneric("/api-key/create", input, options),
      get: (input, options) => getWithQuery("/api-key/get", input, options),
      update: (input, options) => postGeneric("/api-key/update", input, options),
      delete: (input, options) => postGeneric("/api-key/delete", input, options),
      list: (input, options) => getWithQuery("/api-key/list", input, options),
      verify: (input, options) => postGeneric("/api-key/verify", input, options),
      deleteAllExpired: (input, options) => executePostWithOptionalInput(
        resolvedConfig,
        { endpoint: "/api-key/delete-all-expired-api-keys", method: "POST" },
        input,
        options
      )
    },
    signIn: {
      email: (input, options) => postGeneric("/sign-in/email", input, options),
      username: (input, options) => postGeneric("/sign-in/username", input, options),
      social: (input, options) => postGeneric("/sign-in/social", input, options)
    },
    signUp: {
      email: (input, options) => postGeneric("/sign-up/email", input, options)
    },
    organization,
    callback: {
      provider: (input, options) => {
        const { payload, fetchOptions } = extractFetchOptions(input);
        const parsed = payload;
        const provider = String(parsed?.provider ?? "").trim();
        if (!provider) {
          throw new Error("callback.provider requires a non-empty provider value");
        }
        const code = String(parsed?.code ?? "").trim();
        const state = String(parsed?.state ?? "").trim();
        if (!code || !state) {
          throw new Error("callback.provider requires non-empty code and state values");
        }
        const endpoint = `/callback/${encodeURIComponent(provider)}`;
        return request({
          endpoint,
          method: "GET",
          query: {
            code,
            state
          },
          fetchOptions
        }, options);
      }
    }
  };
  return {
    baseUrl: normalizedBaseUrl,
    request,
    signIn: {
      email: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/sign-in/email", method: "POST" },
        input,
        options
      ),
      username: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/sign-in/username", method: "POST" },
        input,
        options
      ),
      social: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/sign-in/social", method: "POST" },
        input,
        options
      )
    },
    signUp: {
      email: (input, options) => executePostWithCompatibleInput(
        resolvedConfig,
        { endpoint: "/sign-up/email", method: "POST" },
        input,
        options
      )
    },
    signOut,
    logout: signOut,
    getSession: (input, options) => executeGetWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/get-session", method: "GET" },
      input,
      options
    ),
    listSessions: (input, options) => executeGetWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/list-sessions", method: "GET" },
      input,
      options
    ),
    revokeSession,
    clearSession: revokeSession,
    revokeSessions,
    clearSessions: revokeSessions,
    revokeOtherSessions,
    clearOtherSessions: revokeOtherSessions,
    forgetPassword: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/forget-password", method: "POST" },
      input,
      options
    ),
    resetPassword: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/reset-password", method: "POST" },
      input,
      options
    ),
    resolveResetPasswordToken,
    verifyEmail: (input, options) => {
      const { payload, fetchOptions } = extractFetchOptions(input);
      const mergedOptions = mergeCallOptions(fetchOptions, options);
      const query = payload;
      return callAuthEndpoint(
        resolvedConfig,
        { endpoint: "/verify-email", method: "GET" },
        void 0,
        query ? {
          token: query.token,
          callbackURL: query.callbackURL
        } : void 0,
        mergedOptions
      );
    },
    sendVerificationEmail: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/send-verification-email", method: "POST" },
      input,
      options
    ),
    changeEmail: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/change-email", method: "POST" },
      input,
      options
    ),
    changePassword: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/change-password", method: "POST" },
      input,
      options
    ),
    updateUser: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/update-user", method: "POST" },
      input,
      options
    ),
    deleteUser,
    deleteUserCallback,
    linkSocial: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/link-social", method: "POST" },
      input,
      options
    ),
    listAccounts: (input, options) => executeGetWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/list-accounts", method: "GET" },
      input,
      options
    ),
    unlinkAccount: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/unlink-account", method: "POST" },
      input,
      options
    ),
    refreshToken: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/refresh-token", method: "POST" },
      input,
      options
    ),
    getAccessToken: (input, options) => executePostWithCompatibleInput(
      resolvedConfig,
      { endpoint: "/get-access-token", method: "POST" },
      input,
      options
    ),
    organization,
    auth
  };
}

// src/client.ts
var DEFAULT_COLUMNS = "*";
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;
var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
function formatResult(response) {
  const result = {
    data: response.data ?? null,
    error: response.error ?? null,
    errorDetails: response.errorDetails ?? null,
    status: response.status,
    raw: response.raw
  };
  if (response.count !== void 0) {
    result.count = response.count;
  }
  return result;
}
function toSingleResult(response) {
  const payload = response.data;
  const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
  return {
    ...response,
    data: singleData
  };
}
function mergeOptions(...options) {
  return options.reduce((acc, next) => {
    if (!next) return acc;
    return { ...acc, ...next };
  }, void 0);
}
function asAthenaJsonObject(value) {
  return value;
}
function asAthenaJsonObjectArray(values) {
  return values;
}
function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
  let selectedOptions;
  let promise = null;
  const run = (columns, options) => {
    const payloadColumns = columns ?? selectedColumns;
    const payloadOptions = options ?? selectedOptions;
    if (!promise) {
      promise = executor(payloadColumns, payloadOptions);
    }
    return promise;
  };
  const mutationQuery = {
    select(columns = selectedColumns, options) {
      selectedColumns = columns;
      selectedOptions = options ?? selectedOptions;
      return run(columns, options);
    },
    returning(columns = selectedColumns, options) {
      return mutationQuery.select(columns, options);
    },
    single(columns = selectedColumns, options) {
      selectedColumns = columns;
      selectedOptions = options ?? selectedOptions;
      return run(columns, options).then(toSingleResult);
    },
    maybeSingle(columns = selectedColumns, options) {
      return mutationQuery.single(columns, options);
    },
    then(onfulfilled, onrejected) {
      return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
    },
    catch(onrejected) {
      return run(selectedColumns, selectedOptions).catch(onrejected);
    },
    finally(onfinally) {
      return run(selectedColumns, selectedOptions).finally(onfinally);
    }
  };
  return mutationQuery;
}
function getResourceId(state) {
  const candidate = state.conditions.find(
    (condition) => condition.operator === "eq" && (condition.column === "resource_id" || condition.column === "id")
  );
  return candidate?.value?.toString();
}
function stringifyFilterValue(value) {
  if (Array.isArray(value)) {
    return value.join(",");
  }
  return String(value);
}
function isUuidString(value) {
  return UUID_PATTERN.test(value.trim());
}
function isUuidIdentifierColumn(column) {
  return column === "id" || /(?:^|_)uuid(?:_|$)/i.test(column) || /_id$/i.test(column);
}
function shouldUseUuidTextComparison(column, value) {
  return typeof value === "string" && isUuidString(value) && isUuidIdentifierColumn(column);
}
function normalizeCast(cast) {
  const normalized = cast.trim().toLowerCase();
  if (!SAFE_CAST_PATTERN.test(normalized)) {
    throw new Error(`Invalid cast type "${cast}"`);
  }
  return normalized;
}
function escapeSqlStringLiteral(value) {
  return value.replace(/'/g, "''");
}
function toSqlLiteral(value) {
  if (value === null) return "NULL";
  if (typeof value === "number") return Number.isFinite(value) ? String(value) : "NULL";
  if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
  return `'${escapeSqlStringLiteral(value)}'`;
}
function withCast(expression, cast) {
  if (!cast) return expression;
  return `${expression}::${normalizeCast(cast)}`;
}
function buildSelectColumnsClause(columns) {
  if (Array.isArray(columns)) {
    return columns.map((column) => quoteQualifiedIdentifier(column)).join(", ");
  }
  return quoteSelectColumnsExpression(columns);
}
function resolveTableNameForCall(tableName, schema) {
  if (!schema) return tableName;
  const normalizedSchema = schema.trim();
  if (!normalizedSchema) {
    throw new Error("schema option must be a non-empty string");
  }
  if (tableName.includes(".")) {
    if (tableName.startsWith(`${normalizedSchema}.`)) {
      return tableName;
    }
    throw new Error(
      `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
    );
  }
  return `${normalizedSchema}.${tableName}`;
}
function conditionToSqlClause(condition) {
  if (!condition.column) return null;
  const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
  const value = condition.value;
  const sqlOperator = {
    eq: "=",
    neq: "!=",
    gt: ">",
    gte: ">=",
    lt: "<",
    lte: "<=",
    like: "LIKE",
    ilike: "ILIKE"
  };
  switch (condition.operator) {
    case "eq":
    case "neq":
    case "gt":
    case "gte":
    case "lt":
    case "lte":
    case "like":
    case "ilike": {
      if (Array.isArray(value) || value === void 0) return null;
      const rhs = withCast(toSqlLiteral(value), condition.value_cast);
      return `${column} ${sqlOperator[condition.operator]} ${rhs}`;
    }
    case "is": {
      if (value === null) return `${column} IS NULL`;
      if (value === true) return `${column} IS TRUE`;
      if (value === false) return `${column} IS FALSE`;
      return null;
    }
    case "in": {
      if (!Array.isArray(value)) return null;
      if (value.length === 0) return "FALSE";
      const values = value.map((item) => withCast(toSqlLiteral(item), condition.value_cast));
      return `${column} IN (${values.join(", ")})`;
    }
    default:
      return null;
  }
}
function buildTypedSelectQuery(input) {
  const whereClauses = [];
  for (const condition of input.conditions) {
    const clause = conditionToSqlClause(condition);
    if (!clause) return null;
    whereClauses.push(clause);
  }
  let limit = input.limit;
  let offset = input.offset;
  if (limit === void 0 && input.pageSize !== void 0) {
    limit = input.pageSize;
  }
  if (offset === void 0 && input.pageSize !== void 0 && input.currentPage !== void 0 && input.currentPage > 0) {
    offset = (input.currentPage - 1) * input.pageSize;
  }
  const sqlParts = [
    `SELECT ${buildSelectColumnsClause(input.columns)} FROM ${quoteQualifiedIdentifier(input.tableName)}`
  ];
  if (whereClauses.length > 0) {
    sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
  }
  if (input.order?.field) {
    const direction = input.order.direction === "descending" ? "DESC" : "ASC";
    sqlParts.push(`ORDER BY ${quoteQualifiedIdentifier(input.order.field)} ${direction}`);
  }
  if (limit !== void 0) {
    sqlParts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
  }
  if (offset !== void 0) {
    sqlParts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
  }
  return `${sqlParts.join(" ")};`;
}
function createFilterMethods(state, addCondition, self) {
  return {
    eq(column, value) {
      const columnName = String(column);
      if (shouldUseUuidTextComparison(columnName, value)) {
        addCondition("eq", columnName, value, { columnCast: "text" });
      } else {
        addCondition("eq", columnName, value);
      }
      return self;
    },
    eqCast(column, value, cast) {
      addCondition("eq", String(column), value, { valueCast: cast });
      return self;
    },
    eqUuid(column, value) {
      addCondition("eq", String(column), value, { valueCast: "uuid" });
      return self;
    },
    match(filters) {
      Object.entries(filters).forEach(([column, value]) => {
        if (value === void 0) {
          return;
        }
        if (shouldUseUuidTextComparison(column, value)) {
          addCondition("eq", column, value, { columnCast: "text" });
        } else {
          addCondition("eq", column, value);
        }
      });
      return self;
    },
    range(from, to) {
      state.offset = from;
      state.limit = to - from + 1;
      return self;
    },
    limit(count) {
      state.limit = count;
      return self;
    },
    offset(count) {
      state.offset = count;
      return self;
    },
    currentPage(value) {
      state.currentPage = value;
      return self;
    },
    pageSize(value) {
      state.pageSize = value;
      return self;
    },
    totalPages(value) {
      state.totalPages = value;
      return self;
    },
    order(column, options) {
      state.order = {
        field: String(column),
        direction: options?.ascending === false ? "descending" : "ascending"
      };
      return self;
    },
    gt(column, value) {
      addCondition("gt", String(column), value);
      return self;
    },
    gte(column, value) {
      addCondition("gte", String(column), value);
      return self;
    },
    lt(column, value) {
      addCondition("lt", String(column), value);
      return self;
    },
    lte(column, value) {
      addCondition("lte", String(column), value);
      return self;
    },
    neq(column, value) {
      addCondition("neq", String(column), value);
      return self;
    },
    like(column, value) {
      addCondition("like", String(column), value);
      return self;
    },
    ilike(column, value) {
      addCondition("ilike", String(column), value);
      return self;
    },
    is(column, value) {
      addCondition("is", String(column), value);
      return self;
    },
    in(column, values) {
      addCondition("in", String(column), values);
      return self;
    },
    contains(column, values) {
      addCondition("contains", String(column), values);
      return self;
    },
    containedBy(column, values) {
      addCondition("containedBy", String(column), values);
      return self;
    },
    not(columnOrExpression, operator, value) {
      const expression = String(columnOrExpression);
      if (operator != null && value !== void 0) {
        addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
      } else {
        addCondition("not", void 0, expression);
      }
      return self;
    },
    or(expression) {
      addCondition("or", void 0, expression);
      return self;
    }
  };
}
function toRpcSelect(columns) {
  if (!columns) return void 0;
  return Array.isArray(columns) ? columns.join(",") : columns;
}
function createRpcFilterMethods(filters, self) {
  const addFilter = (operator, column, value) => {
    filters.push({ column, operator, value });
  };
  return {
    eq(column, value) {
      addFilter("eq", column, value);
      return self;
    },
    neq(column, value) {
      addFilter("neq", column, value);
      return self;
    },
    gt(column, value) {
      addFilter("gt", column, value);
      return self;
    },
    gte(column, value) {
      addFilter("gte", column, value);
      return self;
    },
    lt(column, value) {
      addFilter("lt", column, value);
      return self;
    },
    lte(column, value) {
      addFilter("lte", column, value);
      return self;
    },
    like(column, value) {
      addFilter("like", column, value);
      return self;
    },
    ilike(column, value) {
      addFilter("ilike", column, value);
      return self;
    },
    is(column, value) {
      addFilter("is", column, value);
      return self;
    },
    in(column, values) {
      addFilter("in", column, values);
      return self;
    }
  };
}
function createRpcBuilder(functionName, args, baseOptions, client) {
  const state = {
    filters: []
  };
  let selectedColumns;
  let selectedOptions;
  let promise = null;
  const executeRpc = async (columns, options) => {
    const mergedOptions = mergeOptions(baseOptions, options);
    const payload = {
      function: functionName,
      args,
      schema: mergedOptions?.schema,
      select: toRpcSelect(columns),
      filters: state.filters.length ? [...state.filters] : void 0,
      count: mergedOptions?.count,
      head: mergedOptions?.head,
      limit: state.limit,
      offset: state.offset,
      order: state.order
    };
    const response = await client.rpcGateway(payload, mergedOptions);
    return formatResult(response);
  };
  const run = (columns, options) => {
    const payloadColumns = columns ?? selectedColumns;
    const payloadOptions = options ?? selectedOptions;
    if (!promise) {
      promise = executeRpc(payloadColumns, payloadOptions);
    }
    return promise;
  };
  const builder = {};
  const filterMethods = createRpcFilterMethods(state.filters, builder);
  Object.assign(builder, filterMethods, {
    select(columns = selectedColumns, options) {
      selectedColumns = columns;
      selectedOptions = options ?? selectedOptions;
      return run(columns, options);
    },
    async single(columns, options) {
      const result = await run(columns, options);
      return toSingleResult(result);
    },
    maybeSingle(columns, options) {
      return builder.single(columns, options);
    },
    order(column, options) {
      state.order = { column, ascending: options?.ascending ?? true };
      return builder;
    },
    limit(count) {
      state.limit = count;
      return builder;
    },
    offset(count) {
      state.offset = count;
      return builder;
    },
    range(from, to) {
      state.offset = from;
      state.limit = to - from + 1;
      return builder;
    },
    then(onfulfilled, onrejected) {
      return run(selectedColumns, selectedOptions).then(onfulfilled, onrejected);
    },
    catch(onrejected) {
      return run(selectedColumns, selectedOptions).catch(onrejected);
    },
    finally(onfinally) {
      return run(selectedColumns, selectedOptions).finally(onfinally);
    }
  });
  return builder;
}
function createTableBuilder(tableName, client) {
  const state = {
    conditions: []
  };
  const addCondition = (operator, column, value, hints) => {
    const condition = { operator };
    if (column) {
      condition.column = column;
      if (operator === "eq") {
        condition.eq_column = column;
      }
    }
    if (value !== void 0) {
      condition.value = value;
      if (operator === "eq") {
        condition.eq_value = value;
      }
    }
    if (hints?.valueCast) {
      condition.value_cast = hints.valueCast;
      if (operator === "eq") {
        condition.eq_value_cast = hints.valueCast;
      }
    }
    if (hints?.columnCast) {
      condition.column_cast = hints.columnCast;
      if (operator === "eq") {
        condition.eq_column_cast = hints.columnCast;
      }
    }
    state.conditions.push(condition);
  };
  const builder = {};
  const filterMethods = createFilterMethods(
    state,
    addCondition,
    builder
  );
  const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
    const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
    const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
    const hasTypedEqualityComparison = conditions?.some(
      (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
    ) ?? false;
    if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
      const query = buildTypedSelectQuery({
        tableName: resolvedTableName,
        columns,
        conditions,
        limit: state.limit,
        offset: state.offset,
        currentPage: state.currentPage,
        pageSize: state.pageSize,
        order: state.order
      });
      if (query) {
        const queryResponse = await client.queryGateway({ query }, options);
        return formatResult(queryResponse);
      }
    }
    const payload = {
      table_name: resolvedTableName,
      columns,
      conditions,
      limit: state.limit,
      offset: state.offset,
      current_page: state.currentPage,
      page_size: state.pageSize,
      total_pages: state.totalPages,
      sort_by: state.order,
      strip_nulls: options?.stripNulls ?? true,
      count: options?.count,
      head: options?.head
    };
    const response = await client.fetchGateway(payload, options);
    return formatResult(response);
  };
  const createSelectChain = (columns, options) => {
    const chain = {};
    const filterMethods2 = createFilterMethods(state, addCondition, chain);
    Object.assign(chain, filterMethods2, {
      async single(cols, opts) {
        const r = await runSelect(cols ?? columns, opts ?? options);
        return toSingleResult(r);
      },
      maybeSingle(cols, opts) {
        return chain.single(cols, opts);
      },
      then(onfulfilled, onrejected) {
        return runSelect(columns, options).then(onfulfilled, onrejected);
      },
      catch(onrejected) {
        return runSelect(columns, options).catch(onrejected);
      },
      finally(onfinally) {
        return runSelect(columns, options).finally(onfinally);
      }
    });
    return chain;
  };
  Object.assign(builder, filterMethods, {
    reset() {
      state.conditions = [];
      state.limit = void 0;
      state.offset = void 0;
      state.order = void 0;
      state.currentPage = void 0;
      state.pageSize = void 0;
      state.totalPages = void 0;
      return builder;
    },
    select(columns = DEFAULT_COLUMNS, options) {
      return createSelectChain(columns, options);
    },
    insert(values, options) {
      if (Array.isArray(values)) {
        const executeInsertMany = async (columns, selectOptions) => {
          const mergedOptions = mergeOptions(options, selectOptions);
          const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
          const payload = {
            table_name: resolvedTableName,
            insert_body: asAthenaJsonObjectArray(values)
          };
          if (columns) payload.columns = columns;
          if (mergedOptions?.count) payload.count = mergedOptions.count;
          if (mergedOptions?.head) payload.head = mergedOptions.head;
          if (mergedOptions?.defaultToNull !== void 0) {
            payload.default_to_null = mergedOptions.defaultToNull;
          }
          const response = await client.insertGateway(payload, mergedOptions);
          return formatResult(response);
        };
        return createMutationQuery(executeInsertMany);
      }
      const executeInsertOne = async (columns, selectOptions) => {
        const mergedOptions = mergeOptions(options, selectOptions);
        const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
        const payload = {
          table_name: resolvedTableName,
          insert_body: asAthenaJsonObject(values)
        };
        if (columns) payload.columns = columns;
        if (mergedOptions?.count) payload.count = mergedOptions.count;
        if (mergedOptions?.head) payload.head = mergedOptions.head;
        if (mergedOptions?.defaultToNull !== void 0) {
          payload.default_to_null = mergedOptions.defaultToNull;
        }
        const response = await client.insertGateway(payload, mergedOptions);
        return formatResult(response);
      };
      return createMutationQuery(executeInsertOne);
    },
    upsert(values, options) {
      if (Array.isArray(values)) {
        const executeUpsertMany = async (columns, selectOptions) => {
          const mergedOptions = mergeOptions(options, selectOptions);
          const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
          const payload = {
            table_name: resolvedTableName,
            insert_body: asAthenaJsonObjectArray(values),
            update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
          };
          if (columns) payload.columns = columns;
          if (options?.onConflict) payload.on_conflict = options.onConflict;
          if (mergedOptions?.count) payload.count = mergedOptions.count;
          if (mergedOptions?.head) payload.head = mergedOptions.head;
          if (mergedOptions?.defaultToNull !== void 0) {
            payload.default_to_null = mergedOptions.defaultToNull;
          }
          const response = await client.insertGateway(payload, mergedOptions);
          return formatResult(response);
        };
        return createMutationQuery(executeUpsertMany);
      }
      const executeUpsertOne = async (columns, selectOptions) => {
        const mergedOptions = mergeOptions(options, selectOptions);
        const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
        const payload = {
          table_name: resolvedTableName,
          insert_body: asAthenaJsonObject(values),
          update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
        };
        if (columns) payload.columns = columns;
        if (options?.onConflict) payload.on_conflict = options.onConflict;
        if (mergedOptions?.count) payload.count = mergedOptions.count;
        if (mergedOptions?.head) payload.head = mergedOptions.head;
        if (mergedOptions?.defaultToNull !== void 0) {
          payload.default_to_null = mergedOptions.defaultToNull;
        }
        const response = await client.insertGateway(payload, mergedOptions);
        return formatResult(response);
      };
      return createMutationQuery(executeUpsertOne);
    },
    update(values, options) {
      const executeUpdate = async (columns, selectOptions) => {
        const filters = state.conditions.length ? [...state.conditions] : void 0;
        const mergedOptions = mergeOptions(options, selectOptions);
        const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
        const payload = {
          table_name: resolvedTableName,
          set: asAthenaJsonObject(values),
          conditions: filters,
          strip_nulls: mergedOptions?.stripNulls ?? true
        };
        if (state.order) payload.sort_by = state.order;
        if (state.currentPage !== void 0) payload.current_page = state.currentPage;
        if (state.pageSize !== void 0) payload.page_size = state.pageSize;
        if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
        if (columns) payload.columns = columns;
        const response = await client.updateGateway(payload, mergedOptions);
        return formatResult(response);
      };
      const mutation = createMutationQuery(executeUpdate, null);
      const updateChain = {};
      const filterMethods2 = createFilterMethods(state, addCondition, updateChain);
      Object.assign(updateChain, filterMethods2, mutation);
      return updateChain;
    },
    delete(options) {
      const filters = state.conditions.length ? [...state.conditions] : void 0;
      const resourceId = options?.resourceId ?? getResourceId(state);
      if (!resourceId && !filters?.length) {
        throw new Error('delete requires a resource_id either via eq("resource_id", ...) or options.resourceId');
      }
      const executeDelete = async (columns, selectOptions) => {
        const mergedOptions = mergeOptions(options, selectOptions);
        const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
        const payload = {
          table_name: resolvedTableName,
          resource_id: resourceId,
          conditions: filters
        };
        if (state.order) payload.sort_by = state.order;
        if (state.currentPage !== void 0) payload.current_page = state.currentPage;
        if (state.pageSize !== void 0) payload.page_size = state.pageSize;
        if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
        if (columns) payload.columns = columns;
        const response = await client.deleteGateway(payload, mergedOptions);
        return formatResult(response);
      };
      return createMutationQuery(executeDelete, null);
    },
    async single(columns, options) {
      const response = await builder.select(columns, options);
      return toSingleResult(response);
    },
    async maybeSingle(columns, options) {
      return builder.single(columns, options);
    }
  });
  return builder;
}
function createQueryBuilder(client) {
  return async function query(query, options) {
    const normalizedQuery = query.trim();
    if (!normalizedQuery) {
      throw new Error("query requires a non-empty string");
    }
    const response = await client.queryGateway({ query: normalizedQuery }, options);
    return formatResult(response);
  };
}
function createClientFromConfig(config) {
  const gateway = createAthenaGatewayClient({
    baseUrl: config.baseUrl,
    apiKey: config.apiKey,
    client: config.client,
    backend: config.backend,
    headers: config.headers
  });
  const auth = createAuthClient(config.auth);
  return {
    from(table) {
      return createTableBuilder(table, gateway);
    },
    rpc(fn, args, options) {
      const normalizedFn = fn.trim();
      if (!normalizedFn) {
        throw new Error("rpc requires a function name");
      }
      return createRpcBuilder(
        normalizedFn,
        args,
        options,
        gateway
      );
    },
    query: createQueryBuilder(gateway),
    auth: auth.auth
  };
}
var DEFAULT_BACKEND = { type: "athena" };
function toBackendConfig(b) {
  if (!b) return DEFAULT_BACKEND;
  return typeof b === "string" ? { type: b } : b;
}
var AthenaClientBuilderImpl = class {
  baseUrl;
  apiKey;
  backendConfig = DEFAULT_BACKEND;
  clientName;
  defaultHeaders;
  isHealthTrackingEnabled = false;
  url(url) {
    this.baseUrl = url;
    return this;
  }
  key(apiKey) {
    this.apiKey = apiKey;
    return this;
  }
  backend(backend) {
    this.backendConfig = toBackendConfig(backend);
    return this;
  }
  client(clientName) {
    this.clientName = clientName;
    return this;
  }
  headers(headers) {
    this.defaultHeaders = headers;
    return this;
  }
  healthTracking(enabled) {
    this.isHealthTrackingEnabled = enabled;
    return this;
  }
  build() {
    if (!this.baseUrl || !this.apiKey) {
      throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
    }
    return createClientFromConfig({
      baseUrl: this.baseUrl,
      apiKey: this.apiKey,
      client: this.clientName,
      backend: this.backendConfig,
      headers: this.defaultHeaders,
      healthTracking: this.isHealthTrackingEnabled
    });
  }
};
var AthenaClient = class _AthenaClient {
  /** Create a fluent builder for a strongly-typed Athena SDK client. */
  static builder() {
    return new AthenaClientBuilderImpl();
  }
  /** Build a client from process environment variables. */
  static fromEnvironment() {
    const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
    const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
    if (!url || !key) {
      throw new Error(
        "ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
      );
    }
    return _AthenaClient.builder().url(url).key(key).build();
  }
};
function createClient(url, apiKey, options) {
  const b = AthenaClient.builder().url(url).key(apiKey).backend(toBackendConfig(options?.backend));
  if (options?.client) b.client(options.client);
  if (options?.headers && Object.keys(options.headers).length > 0) b.headers(options.headers);
  const client = b.build();
  if (options?.auth) {
    client.auth = createAuthClient(options.auth).auth;
  }
  return client;
}

// src/schema/postgres-introspection-core.ts
var POSTGRES_CATALOG_SQL = {
  columns: `
    SELECT
      n.nspname AS schema_name,
      c.relname AS table_name,
      a.attname AS column_name,
      format_type(a.atttypid, a.atttypmod) AS data_type,
      t.typname AS udt_name,
      t.typtype AS type_kind_code,
      t.oid AS type_oid,
      NOT a.attnotnull AS is_nullable,
      (ad.adbin IS NOT NULL) AS has_default,
      (a.attgenerated <> '') AS is_generated,
      a.attndims AS array_dimensions
    FROM pg_attribute a
    JOIN pg_class c ON c.oid = a.attrelid
    JOIN pg_namespace n ON n.oid = c.relnamespace
    JOIN pg_type t ON t.oid = a.atttypid
    LEFT JOIN pg_attrdef ad ON ad.adrelid = a.attrelid AND ad.adnum = a.attnum
    WHERE c.relkind IN ('r', 'p')
      AND a.attnum > 0
      AND NOT a.attisdropped
      AND n.nspname = ANY($1::text[])
    ORDER BY n.nspname, c.relname, a.attnum;
  `,
  enums: `
    SELECT
      t.oid AS type_oid,
      e.enumlabel AS enum_label
    FROM pg_type t
    JOIN pg_enum e ON e.enumtypid = t.oid
    ORDER BY t.oid, e.enumsortorder;
  `,
  primaryKeys: `
    SELECT
      n.nspname AS schema_name,
      c.relname AS table_name,
      ARRAY_AGG(a.attname ORDER BY ck.ordinality) AS columns
    FROM pg_constraint con
    JOIN pg_class c ON c.oid = con.conrelid
    JOIN pg_namespace n ON n.oid = c.relnamespace
    JOIN unnest(con.conkey) WITH ORDINALITY AS ck(attnum, ordinality) ON TRUE
    JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ck.attnum
    WHERE con.contype = 'p'
      AND n.nspname = ANY($1::text[])
    GROUP BY n.nspname, c.relname
    ORDER BY n.nspname, c.relname;
  `,
  foreignKeys: `
    SELECT
      sn.nspname AS source_schema,
      sc.relname AS source_table,
      con.conname AS constraint_name,
      ARRAY_AGG(sa.attname ORDER BY cols.ordinality) AS source_columns,
      tn.nspname AS target_schema,
      tc.relname AS target_table,
      ARRAY_AGG(ta.attname ORDER BY cols.ordinality) AS target_columns,
      EXISTS (
        SELECT 1
        FROM pg_constraint uq
        WHERE uq.conrelid = con.conrelid
          AND uq.contype IN ('p', 'u')
          AND uq.conkey = con.conkey
      ) AS source_is_unique
    FROM pg_constraint con
    JOIN pg_class sc ON sc.oid = con.conrelid
    JOIN pg_namespace sn ON sn.oid = sc.relnamespace
    JOIN pg_class tc ON tc.oid = con.confrelid
    JOIN pg_namespace tn ON tn.oid = tc.relnamespace
    JOIN unnest(con.conkey, con.confkey) WITH ORDINALITY AS cols(source_attnum, target_attnum, ordinality) ON TRUE
    JOIN pg_attribute sa ON sa.attrelid = con.conrelid AND sa.attnum = cols.source_attnum
    JOIN pg_attribute ta ON ta.attrelid = con.confrelid AND ta.attnum = cols.target_attnum
    WHERE con.contype = 'f'
      AND sn.nspname = ANY($1::text[])
      AND tn.nspname = ANY($1::text[])
    GROUP BY
      sn.nspname,
      sc.relname,
      con.conname,
      tn.nspname,
      tc.relname,
      con.conkey,
      con.conrelid
    ORDER BY sn.nspname, sc.relname, con.conname;
  `
};
function tableKey(schema, table) {
  return `${schema}.${table}`;
}
function relationKey(...parts) {
  const base = parts.join("_").replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
  return base.length > 0 ? base : "relation";
}
function toTypeKind(code) {
  switch (code) {
    case "e":
      return "enum";
    case "d":
      return "domain";
    case "r":
      return "range";
    case "m":
      return "multirange";
    case "c":
      return "composite";
    default:
      return "scalar";
  }
}
function escapeSqlLiteral(value) {
  return value.replace(/'/g, "''");
}
function parsePostgresArrayLiteral(text) {
  const body = text.slice(1, -1).trim();
  if (!body) return [];
  const values = [];
  let current = "";
  let inQuotes = false;
  let escaped = false;
  for (const char of body) {
    if (escaped) {
      current += char;
      escaped = false;
      continue;
    }
    if (char === "\\") {
      escaped = true;
      continue;
    }
    if (char === '"') {
      inQuotes = !inQuotes;
      continue;
    }
    if (char === "," && !inQuotes) {
      values.push(current);
      current = "";
      continue;
    }
    current += char;
  }
  values.push(current);
  return values.map((value) => value.trim()).filter((value) => value.length > 0);
}
function coerceStringArray(value) {
  if (Array.isArray(value)) {
    return value.map((item) => typeof item === "string" ? item : String(item)).map((item) => item.trim()).filter((item) => item.length > 0);
  }
  if (typeof value === "string") {
    const trimmed = value.trim();
    if (!trimmed) return [];
    if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
      try {
        const parsed = JSON.parse(trimmed);
        return coerceStringArray(parsed);
      } catch {
      }
    }
    if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
      return parsePostgresArrayLiteral(trimmed);
    }
    return trimmed.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
  }
  return [];
}
function normalizePostgresCatalogSchemas(schemas) {
  const normalized = [];
  const seen = /* @__PURE__ */ new Set();
  for (const value of schemas ?? []) {
    const schema = value.trim();
    if (!schema || seen.has(schema)) {
      continue;
    }
    seen.add(schema);
    normalized.push(schema);
  }
  return normalized.length > 0 ? normalized : ["public"];
}
function buildSchemaArrayLiteral(schemas) {
  const normalized = normalizePostgresCatalogSchemas(schemas);
  const literals = normalized.map((schema) => `'${escapeSqlLiteral(schema)}'`).join(", ");
  return `ARRAY[${literals}]`;
}
function inlineSchemaLiteral(sql, schemas) {
  const schemaArray = `${buildSchemaArrayLiteral(schemas)}::text[]`;
  return sql.replace(/\$1::text\[\]/g, schemaArray);
}
function buildGatewayCatalogQueries(schemas) {
  return {
    columns: inlineSchemaLiteral(POSTGRES_CATALOG_SQL.columns, schemas),
    enums: POSTGRES_CATALOG_SQL.enums,
    primaryKeys: inlineSchemaLiteral(POSTGRES_CATALOG_SQL.primaryKeys, schemas),
    foreignKeys: inlineSchemaLiteral(POSTGRES_CATALOG_SQL.foreignKeys, schemas)
  };
}
var PostgresCatalogSnapshotAssembler = class {
  schemas = {};
  addColumnRows(columnRows, enumMap) {
    for (const row of columnRows) {
      const table = this.ensureTable(row.schema_name, row.table_name);
      table.columns[row.column_name] = {
        name: row.column_name,
        dataType: row.data_type,
        udtName: row.udt_name,
        typeKind: toTypeKind(row.type_kind_code),
        isNullable: row.is_nullable,
        isPrimaryKey: false,
        hasDefault: row.has_default,
        isGenerated: row.is_generated,
        arrayDimensions: row.array_dimensions ?? 0,
        enumValues: enumMap.get(row.type_oid)
      };
    }
  }
  addPrimaryKeyRows(primaryKeyRows) {
    for (const row of primaryKeyRows) {
      const table = this.ensureTable(row.schema_name, row.table_name);
      const primaryKeyColumns = coerceStringArray(row.columns);
      row.columns = primaryKeyColumns;
      table.primaryKey = primaryKeyColumns;
      for (const columnName of primaryKeyColumns) {
        const column = table.columns[columnName];
        if (column) {
          column.isPrimaryKey = true;
        }
      }
    }
  }
  addForeignKeyRows(foreignKeyRows) {
    for (const row of foreignKeyRows) {
      const sourceTable = this.ensureTable(row.source_schema, row.source_table);
      const targetTable = this.ensureTable(row.target_schema, row.target_table);
      const sourceColumns = coerceStringArray(row.source_columns);
      const targetColumns = coerceStringArray(row.target_columns);
      row.source_columns = sourceColumns;
      row.target_columns = targetColumns;
      const sourceRelationKind = row.source_is_unique ? "one-to-one" : "many-to-one";
      this.upsertRelation(sourceTable, relationKey(row.constraint_name, row.target_table), {
        name: row.constraint_name,
        kind: sourceRelationKind,
        sourceColumns,
        targetSchema: row.target_schema,
        targetModel: row.target_table,
        targetColumns
      });
      const targetRelationKind = row.source_is_unique ? "one-to-one" : "one-to-many";
      this.upsertRelation(targetTable, relationKey(row.source_table), {
        name: relationKey(row.source_table, row.constraint_name),
        kind: targetRelationKind,
        sourceColumns: targetColumns,
        targetSchema: row.source_schema,
        targetModel: row.source_table,
        targetColumns: sourceColumns
      });
    }
  }
  addManyToManyRows(foreignKeyRows) {
    const bySourceTable = /* @__PURE__ */ new Map();
    for (const fk of foreignKeyRows) {
      const key = tableKey(fk.source_schema, fk.source_table);
      const current = bySourceTable.get(key) ?? {
        schema: fk.source_schema,
        table: fk.source_table,
        foreignKeys: []
      };
      current.foreignKeys.push(fk);
      bySourceTable.set(key, current);
    }
    for (const candidate of bySourceTable.values()) {
      const bridgeTable = this.schemas[candidate.schema]?.tables[candidate.table];
      if (!bridgeTable) continue;
      const primaryKey = bridgeTable.primaryKey;
      if (candidate.foreignKeys.length !== 2 || primaryKey.length === 0) continue;
      const combinedForeignColumns = Array.from(
        new Set(candidate.foreignKeys.flatMap((fk) => fk.source_columns))
      );
      if (combinedForeignColumns.length !== primaryKey.length || !primaryKey.every((column) => combinedForeignColumns.includes(column))) {
        continue;
      }
      const [first, second] = candidate.foreignKeys;
      const firstTarget = this.schemas[first.target_schema]?.tables[first.target_table];
      const secondTarget = this.schemas[second.target_schema]?.tables[second.target_table];
      if (!firstTarget || !secondTarget) {
        continue;
      }
      this.upsertRelation(firstTarget, relationKey(second.target_table), {
        name: relationKey(candidate.table, first.constraint_name, second.constraint_name),
        kind: "many-to-many",
        sourceColumns: first.target_columns,
        targetSchema: second.target_schema,
        targetModel: second.target_table,
        targetColumns: second.target_columns,
        through: {
          schema: candidate.schema,
          model: candidate.table,
          sourceColumns: first.source_columns,
          targetColumns: second.source_columns
        }
      });
      this.upsertRelation(secondTarget, relationKey(first.target_table), {
        name: relationKey(candidate.table, second.constraint_name, first.constraint_name),
        kind: "many-to-many",
        sourceColumns: second.target_columns,
        targetSchema: first.target_schema,
        targetModel: first.target_table,
        targetColumns: first.target_columns,
        through: {
          schema: candidate.schema,
          model: candidate.table,
          sourceColumns: second.source_columns,
          targetColumns: first.source_columns
        }
      });
    }
  }
  toSchemas() {
    return this.schemas;
  }
  ensureTable(schemaName, tableName) {
    if (!this.schemas[schemaName]) {
      this.schemas[schemaName] = {
        name: schemaName,
        tables: {}
      };
    }
    const schema = this.schemas[schemaName];
    if (!schema.tables[tableName]) {
      schema.tables[tableName] = {
        schema: schemaName,
        name: tableName,
        columns: {},
        primaryKey: [],
        relations: {}
      };
    }
    return schema.tables[tableName];
  }
  upsertRelation(table, baseKey, relation) {
    let key = baseKey;
    let suffix = 2;
    while (table.relations[key]) {
      key = `${baseKey}_${suffix}`;
      suffix += 1;
    }
    table.relations[key] = relation;
  }
};
var PgCatalogClient = class {
  constructor(pool) {
    this.pool = pool;
  }
  async queryColumns(schemas) {
    const result = await this.pool.query(POSTGRES_CATALOG_SQL.columns, [schemas]);
    return result.rows;
  }
  async queryEnums() {
    const result = await this.pool.query(POSTGRES_CATALOG_SQL.enums);
    const enumMap = /* @__PURE__ */ new Map();
    for (const row of result.rows) {
      const existing = enumMap.get(row.type_oid) ?? [];
      existing.push(row.enum_label);
      enumMap.set(row.type_oid, existing);
    }
    return enumMap;
  }
  async queryPrimaryKeys(schemas) {
    const result = await this.pool.query(POSTGRES_CATALOG_SQL.primaryKeys, [schemas]);
    return result.rows;
  }
  async queryForeignKeys(schemas) {
    const result = await this.pool.query(POSTGRES_CATALOG_SQL.foreignKeys, [schemas]);
    return result.rows;
  }
};
var PostgresIntrospectionProvider = class {
  backend = "postgresql";
  connectionString;
  database;
  schemas;
  constructor(options) {
    this.connectionString = options.connectionString;
    this.database = options.database ?? "postgres";
    this.schemas = normalizePostgresCatalogSchemas(options.schemas);
  }
  async inspect(options) {
    const schemas = options?.schemas && options.schemas.length > 0 ? normalizePostgresCatalogSchemas(options.schemas) : this.schemas;
    const pool = new Pool({
      connectionString: this.connectionString
    });
    const catalogClient = new PgCatalogClient(pool);
    try {
      const [columnRows, enumMap, primaryKeyRows, foreignKeyRows] = await Promise.all([
        catalogClient.queryColumns(schemas),
        catalogClient.queryEnums(),
        catalogClient.queryPrimaryKeys(schemas),
        catalogClient.queryForeignKeys(schemas)
      ]);
      const assembler = new PostgresCatalogSnapshotAssembler();
      assembler.addColumnRows(columnRows, enumMap);
      assembler.addPrimaryKeyRows(primaryKeyRows);
      assembler.addForeignKeyRows(foreignKeyRows);
      assembler.addManyToManyRows(foreignKeyRows);
      return {
        backend: "postgresql",
        database: this.database,
        generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
        schemas: assembler.toSchemas()
      };
    } finally {
      await pool.end();
    }
  }
};
function createPostgresIntrospectionProvider(options) {
  return new PostgresIntrospectionProvider(options);
}

// src/generator/providers.ts
var AthenaGatewayCatalogClient = class {
  constructor(client) {
    this.client = client;
  }
  async queryRows(query) {
    const result = await this.client.query(query);
    if (result.error || result.status < 200 || result.status >= 300) {
      throw new Error(result.error ?? `Gateway query failed with status ${result.status}`);
    }
    return result.data ?? [];
  }
  async queryColumns(query) {
    return this.queryRows(query);
  }
  async queryEnums(query) {
    const rows = await this.queryRows(query);
    const enumMap = /* @__PURE__ */ new Map();
    for (const row of rows) {
      const existing = enumMap.get(row.type_oid) ?? [];
      existing.push(row.enum_label);
      enumMap.set(row.type_oid, existing);
    }
    return enumMap;
  }
  async queryPrimaryKeys(query) {
    return this.queryRows(query);
  }
  async queryForeignKeys(query) {
    return this.queryRows(query);
  }
};
var AthenaGatewayPostgresIntrospectionProvider = class {
  constructor(config) {
    this.config = config;
    this.client = createClient(this.config.gatewayUrl, this.config.apiKey, {
      backend: {
        type: this.config.backend ?? "postgresql"
      }
    });
    this.schemas = normalizeSchemaSelection(this.config.schemas);
  }
  backend = "postgresql";
  client;
  schemas;
  async inspect(options) {
    const schemas = options?.schemas && options.schemas.length > 0 ? normalizeSchemaSelection(options.schemas) : this.schemas;
    const catalogClient = new AthenaGatewayCatalogClient(this.client);
    const queries = buildGatewayCatalogQueries(schemas);
    const [columnRows, enumMap, primaryKeyRows, foreignKeyRows] = await Promise.all([
      catalogClient.queryColumns(queries.columns),
      catalogClient.queryEnums(queries.enums),
      catalogClient.queryPrimaryKeys(queries.primaryKeys),
      catalogClient.queryForeignKeys(queries.foreignKeys)
    ]);
    const assembler = new PostgresCatalogSnapshotAssembler();
    assembler.addColumnRows(columnRows, enumMap);
    assembler.addPrimaryKeyRows(primaryKeyRows);
    assembler.addForeignKeyRows(foreignKeyRows);
    assembler.addManyToManyRows(foreignKeyRows);
    return {
      backend: "postgresql",
      database: this.config.database,
      generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
      schemas: assembler.toSchemas()
    };
  }
};
var ScyllaIntrospectionProvider = class {
  constructor(config) {
    this.config = config;
  }
  backend = "scylladb";
  async inspect() {
    throw new Error(
      `Scylla introspection provider is not implemented yet for keyspace ${this.config.keyspace}.`
    );
  }
};
function createPostgresProvider(config) {
  return createPostgresIntrospectionProvider({
    connectionString: config.connectionString,
    database: config.database,
    schemas: normalizeSchemaSelection(config.schemas)
  });
}
function resolveGeneratorProvider(providerConfig, experimentalFlags) {
  if (providerConfig.kind === "postgres" && providerConfig.mode === "direct") {
    return createPostgresProvider(providerConfig);
  }
  if (providerConfig.kind === "postgres" && providerConfig.mode === "gateway") {
    return new AthenaGatewayPostgresIntrospectionProvider(providerConfig);
  }
  if (providerConfig.kind === "scylla") {
    if (!experimentalFlags.scyllaProviderContracts) {
      throw new Error(
        "Scylla provider contracts are disabled. Set experimental.scyllaProviderContracts=true to enable placeholders."
      );
    }
    return new ScyllaIntrospectionProvider(providerConfig);
  }
  throw new Error(`Unsupported generator provider kind: ${providerConfig.kind ?? "unknown"}`);
}

// src/generator/pipeline.ts
async function writeArtifacts(files, cwd) {
  const writtenFiles = [];
  for (const file of files) {
    const absolutePath = resolve(cwd, file.path);
    await mkdir(dirname(absolutePath), { recursive: true });
    await writeFile(absolutePath, file.content, "utf8");
    writtenFiles.push(file.path);
  }
  return writtenFiles;
}
async function runSchemaGenerator(options = {}) {
  const cwd = options.cwd ?? process.cwd();
  const configOptions = {
    cwd,
    configPath: options.configPath
  };
  const { configPath, config } = await loadGeneratorConfig(configOptions);
  const provider = options.provider ?? resolveGeneratorProvider(config.provider, config.experimental);
  const snapshot = await provider.inspect({
    schemas: resolveProviderSchemas(config.provider)
  });
  const generated = generateArtifactsFromSnapshot(snapshot, config);
  const writtenFiles = options.dryRun ? [] : await writeArtifacts(generated.files, cwd);
  return {
    ...generated,
    configPath,
    writtenFiles
  };
}

// src/cli/index.ts
function rootUsage() {
  return [
    "athena-js CLI",
    "",
    "Usage:",
    "  athena-js generate [--config <path>] [--dry-run]",
    "",
    "Examples:",
    "  athena-js generate",
    "  athena-js generate --config ./athena.config.ts --dry-run",
    "  athena-js generate --help"
  ].join("\n");
}
function generateUsage() {
  return [
    "athena-js generate",
    "",
    "Usage:",
    "  athena-js generate [--config <path>] [--dry-run]",
    "",
    "Options:",
    "  --config <path>  Explicit path to athena.config.ts or athena-js.config.ts",
    "  --dry-run        Build generated files in memory without writing them to disk",
    "  -h, --help       Show help for generate",
    "",
    "Examples:",
    "  athena-js generate",
    "  athena-js generate --config ./athena.config.ts --dry-run"
  ].join("\n");
}
function usage(topic = "root") {
  return topic === "generate" ? generateUsage() : rootUsage();
}
function parseCommand(argv) {
  if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
    return { command: "help", topic: "root" };
  }
  if (argv[0] === "help") {
    if (argv.length === 1) {
      return { command: "help", topic: "root" };
    }
    if (argv[1] === "generate") {
      return { command: "help", topic: "generate" };
    }
    throw new Error(`Unknown command "${argv[1]}".`);
  }
  const [command, ...rest] = argv;
  if (command !== "generate") {
    throw new Error(`Unknown command "${command}".`);
  }
  let configPath;
  let dryRun = false;
  for (let index = 0; index < rest.length; index += 1) {
    const token = rest[index];
    if (token === "--help" || token === "-h") {
      return { command: "help", topic: "generate" };
    }
    if (token === "--dry-run") {
      dryRun = true;
      continue;
    }
    if (token === "--config") {
      const nextValue = rest[index + 1];
      if (!nextValue || nextValue.startsWith("-")) {
        throw new Error("Missing value for --config option.");
      }
      configPath = nextValue;
      index += 1;
      continue;
    }
    throw new Error(`Unknown option "${token}".`);
  }
  return {
    command: "generate",
    configPath,
    dryRun
  };
}
function normalizeErrorMessage(error) {
  if (error instanceof Error) {
    return error.message;
  }
  if (typeof error === "string") {
    return error;
  }
  return "Unknown generator error.";
}
function extractMissingDatabaseName(message) {
  const match = message.match(/database "([^"]+)" does not exist/i);
  return match?.[1];
}
function isErrorWithCode(error) {
  return typeof error === "object" && error !== null && "code" in error;
}
function formatGeneratorError(error, configPath) {
  if (isErrorWithCode(error) && error.code === "3D000") {
    const message = normalizeErrorMessage(error);
    const databaseName = extractMissingDatabaseName(message);
    const databaseLabel = databaseName ? `PostgreSQL database "${databaseName}" does not exist` : "The target PostgreSQL database does not exist";
    const configLabel = configPath ? `config "${configPath}"` : "the resolved athena config";
    return new Error(
      [
        `${databaseLabel} (code 3D000).`,
        `Update provider.connectionString (and provider.database, if set) in ${configLabel}, or create that database before running generate.`
      ].join("\n")
    );
  }
  if (error instanceof Error) {
    return error;
  }
  return new Error(normalizeErrorMessage(error));
}
async function runCLI(argv, runtime = {}) {
  const log = runtime.log ?? console.log;
  const runGenerator = runtime.runGenerator ?? runSchemaGenerator;
  const parsed = parseCommand(argv);
  if (parsed.command === "help") {
    log(usage(parsed.topic));
    return;
  }
  let result;
  try {
    result = await runGenerator({
      configPath: parsed.configPath,
      dryRun: parsed.dryRun
    });
  } catch (error) {
    throw formatGeneratorError(error, parsed.configPath);
  }
  if (parsed.dryRun) {
    log(`[dry-run] Generated ${result.files.length} files from ${result.configPath}`);
    for (const file of result.files) {
      log(` - ${file.path}`);
    }
    return;
  }
  log(`Generated ${result.writtenFiles.length} files from ${result.configPath}`);
  for (const filePath of result.writtenFiles) {
    log(` - ${filePath}`);
  }
}

export { parseCommand, runCLI, usage };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map