ronantakizawa/codereview-bench huggingface dataset:
Repository: sunner/ChatALL
File: src/bots/index.js (JavaScript)

Code before:
  ChatGPT35PoeBot.getInstance(),
  ChatGPT4Bot.getInstance(),
  ChatGPT4MobileBot.getInstance(),
  ChatGPT4PoeBot.getInstance(),
  ChatGPTBrowsingBot.getInstance(),
  ClaudeInstantPoeBot.getInstance(),
  ClaudeInstant100kPoeBot.getInstance(),
  ClaudeBot.getInstance(),
  ClaudePlusPoeBot.getInstance(),
  GradioAppBot.getInstance(),
  HuggingChatBot.getInstance(),
  MOSSBot.getInstance(),
  OpenAIAPI35Bot.getInstance(),
  OpenAIAPI3516KBot.getInstance(),
  OpenAIAPI4Bot.getInstance(),
  AzureOpenAIAPIBot.getInstance(),
  QianWenBot.getInstance(),
  SageBot.getInstance(),
  SkyWorkBot.getInstance(),
  SparkBot.getInstance(),
  VicunaBot.getInstance(),
  WenxinQianfanBot.getInstance(),
  WinxinQianfanTurboBot.getInstance(),
  YouChatBot.getInstance(),
  PiBot.getInstance(),
  OpenAssistantBot.getInstance(),
];

const disabled = [];

if (process.env.NODE_ENV !== "production") {
  all.push(DevBot.getInstance());
}

const bots = {
  all,
  getBotByClassName(className) {
    const bot = disabled.find((bot) => bot.getClassname() === className);
    if (bot) {
      return bot;
    } else {
      return all.find((bot) => bot.getClassname() === className);
    }
  },
  isBotDisabled(className) {
    return disabled.some((bot) => bot.getClassname() === className);
  },
};

export default bots;


Review comment (suggestion):
Insert it before `QianWenBot.getInstance()` to keep order. And also, the `PiBot` should be moved up.

Code after:
  ChatGPT35PoeBot.getInstance(),
  ChatGPT4Bot.getInstance(),
  ChatGPT4MobileBot.getInstance(),
  ChatGPT4PoeBot.getInstance(),
  ChatGPTBrowsingBot.getInstance(),
  ClaudeInstantPoeBot.getInstance(),
  ClaudeInstant100kPoeBot.getInstance(),
  ClaudeBot.getInstance(),
  ClaudePlusPoeBot.getInstance(),
  GradioAppBot.getInstance(),
  HuggingChatBot.getInstance(),
  MOSSBot.getInstance(),
  OpenAIAPI35Bot.getInstance(),
  OpenAIAPI3516KBot.getInstance(),
  OpenAIAPI4Bot.getInstance(),
  AzureOpenAIAPIBot.getInstance(),
  OpenAssistantBot.getInstance(),
  PiBot.getInstance(),
  QianWenBot.getInstance(),
  SageBot.getInstance(),
  SkyWorkBot.getInstance(),
  SparkBot.getInstance(),
  VicunaBot.getInstance(),
  WenxinQianfanBot.getInstance(),
  WinxinQianfanTurboBot.getInstance(),
  YouChatBot.getInstance(),
];

const disabled = [];

if (process.env.NODE_ENV !== "production") {
  all.push(DevBot.getInstance());
}

const bots = {
  all,
  getBotByClassName(className) {
    const bot = disabled.find((bot) => bot.getClassname() === className);
    if (bot) {
      return bot;
    } else {
      return all.find((bot) => bot.getClassname() === className);
    }
  },
  isBotDisabled(className) {
    return disabled.some((bot) => bot.getClassname() === className);
  },
};

export default bots;
Repository: sunner/ChatALL
File: src/bots/ChatGLMBot.js (JavaScript)

Code before:
import AsyncLock from "async-lock";
import Bot from "@/bots/Bot";
import axios from "axios";
import store from "@/store";
import { SSE } from "sse.js";
import { v4 as uuidv4 } from "uuid";

export default class ChatGLMBot extends Bot {
  static _brandId = "chatGLM"; // Brand id of the bot, should be unique. Used in i18n.
  static _className = "ChatGLMBot"; // Class name of the bot
  static _logoFilename = "chatglm-logo.svg"; // Place it in public/bots/
  static _loginUrl = "https://chatglm.cn/detail";
  static _lock = new AsyncLock(); // AsyncLock for prompt requests
  // Remove Electron from the user agent to avoid blank login screen
  static _userAgent =
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) chatall/1.29.40 Chrome/114.0.5735.134 Safari/537.36";
  _glmLogin = "https://chatglm.cn/chatglm/backend-api/v1/user/login";
  _glmLogout = "https://chatglm.cn/chatglm/backend-api/v1/user/logout";
  _glmRefreshToken = "https://chatglm.cn/chatglm/backend-api/v1/user/refresh";

  constructor() {
    super();
  }

  getAuthHeader() {
    return {
      headers: {
        Authorization: `Bearer ${store.state.chatglm?.token}`,
      },
    };
  }

  /**
   * Check whether the bot is logged in, settings are correct, etc.

Review comment (suggestion):
```suggestion
  static _brandId = "chatGlm"; // Brand id of the bot, should be unique. Used in i18n.
```

Code after:
import AsyncLock from "async-lock";
import Bot from "@/bots/Bot";
import axios from "axios";
import store from "@/store";
import { SSE } from "sse.js";
import { v4 as uuidv4 } from "uuid";

export default class ChatGLMBot extends Bot {
  static _brandId = "chatGlm"; // Brand id of the bot, should be unique. Used in i18n.
  static _className = "ChatGLMBot"; // Class name of the bot
  static _logoFilename = "chatglm-logo.png"; // Place it in public/bots/
  static _loginUrl = "https://chatglm.cn/detail";
  static _lock = new AsyncLock(); // AsyncLock for prompt requests

  constructor() {
    super();
  }

  getAuthHeader() {
    return {
      headers: {
        Authorization: `Bearer ${store.state.chatGlm?.token}`,
      },
    };
  }

  /**
   * Check whether the bot is logged in, settings are correct, etc.
   * @returns {boolean} - true if the bot is available, false otherwise.
   */
  async _checkAvailability() {
    let available = false;
    let userInfoUrl = "https://chatglm.cn/chatglm/backend-api/v3/user/info";
    const context = await this.getChatContext();
Repository: sunner/ChatALL
File: src/bots/openai/OpenAIAPIBot.js (JavaScript)

Code before:
    super();
  }

  async _checkAvailability() {
    let available = false;

    if (store.state.openaiApi.apiKey) {
      this.setupModel();
      available = true;
    }
    return available;
  }

  setupModel() {
    const chatModel = new ChatOpenAI({
      configuration: {
        basePath: store.state.openaiApi.alterUrl
          ? store.state.openaiApi.alterUrl
          : "",
      },
      openAIApiKey: store.state.openaiApi.apiKey,
      modelName: this.constructor._model ? this.constructor._model : "",
      temperature: store.state.openaiApi.temperature,
      streaming: true,
    });
    this.constructor._chatModel = chatModel;
  }

  getPastRounds() {
    return store.state.openaiApi.pastRounds;
  }
}


Review comment (refactor):
The `setupModel()` is great! How about making it as a common method within `LangChainBot` and move this line of code to `LangChainBot.setupModel()`?

Code after:
    super();
  }

  async _checkAvailability() {
    let available = false;

    if (store.state.openaiApi.apiKey) {
      this.setupModel();
      available = true;
    }
    return available;
  }

  _setupModel() {
    const chatModel = new ChatOpenAI({
      configuration: {
        basePath: store.state.openaiApi.alterUrl
          ? store.state.openaiApi.alterUrl
          : "",
      },
      openAIApiKey: store.state.openaiApi.apiKey,
      modelName: this.constructor._model ? this.constructor._model : "",
      temperature: store.state.openaiApi.temperature,
      streaming: true,
    });
    return chatModel;
  }

  getPastRounds() {
    return store.state.openaiApi.pastRounds;
  }
}
Repository: sunner/ChatALL
File: src/bots/index.js (JavaScript)

Code before:
  Llama213bBot.getInstance(),
  Llama270bPoeBot.getInstance(),
  Llama270bBot.getInstance(),
  Llama2HC70bBot.getInstance(),
  MOSSBot.getInstance(),
  HuggingChatBot.getInstance(),
  OpenAssistantBot.getInstance(),
  GooglePalm2PoeBot.getInstance(),
  PhindBot.getInstance(),
  PiBot.getInstance(),
  QianWenBot.getInstance(),
  SkyWorkBot.getInstance(),
  SparkBot.getInstance(),
  Vicuna7bBot.getInstance(),
  Vicuna13bBot.getInstance(),
  VicunaBot.getInstance(),
  Wizardlm13bBot.getInstance(),
  Wizardlm70bBot.getInstance(),
  Zephyr7bBot.getInstance(),
  YouChatBot.getInstance(),
  ClaudeAPIOpusBot.getInstance(),
  ClaudeAPISonnetBot.getInstance(),
  ClaudeAPIHaikuBot.getInstance(),
  ClaudeAPI20Bot.getInstance(),
  ClaudeAPI21Bot.getInstance(),
  ClaudeAPIInstant12Bot.getInstance(),
];

const disabled = [
  "ClaudeBot",
  "AlpacaBot",
  "HuggingChatBot",
  "Falcon180bBot",
  "ChatGLM6bBot",
  "ChatGLM36bBot",
  "CodeLlamaBot",
  "Vicuna7bBot",
  "Wizardlm13bBot",
];

if (process.env.NODE_ENV !== "production") {
  all.push(DevBot.getInstance());
}

const bots = {
  all,
  getBotByClassName(className) {
    return all.find((bot) => bot.getClassname() === className);
  },
};


Review comment (suggestion):
The place where call `getInstance()` is exactly the place the bot is shown in bots menu. So it is better to move these lines of code up to `ClaudeXXXXBot` groups.

Code after:
  OpenAIAPI4Bot.getInstance(),
  OpenAIAPI4128KBot.getInstance(),
  ChatGPT432kPoeBot.getInstance(),
  GradioAppBot.getInstance(),
  KimiBot.getInstance(),
  Llama27bBot.getInstance(),
  Llama213bBot.getInstance(),
  Llama270bPoeBot.getInstance(),
  Llama270bBot.getInstance(),
  Llama2HC70bBot.getInstance(),
  MOSSBot.getInstance(),
  HuggingChatBot.getInstance(),
  OpenAssistantBot.getInstance(),
  GooglePalm2PoeBot.getInstance(),
  PhindBot.getInstance(),
  PiBot.getInstance(),
  QianWenBot.getInstance(),
  SkyWorkBot.getInstance(),
  SparkBot.getInstance(),
  Vicuna7bBot.getInstance(),
  Vicuna13bBot.getInstance(),
  VicunaBot.getInstance(),
  Wizardlm13bBot.getInstance(),
  Wizardlm70bBot.getInstance(),
  Zephyr7bBot.getInstance(),
  YouChatBot.getInstance(),
];

const disabled = [
  "ClaudeBot",
  "AlpacaBot",
  "HuggingChatBot",
  "Falcon180bBot",
  "ChatGLM6bBot",
  "ChatGLM36bBot",
  "CodeLlamaBot",
  "Vicuna7bBot",
  "Wizardlm13bBot",
];

if (process.env.NODE_ENV !== "production") {
  all.push(DevBot.getInstance());
}

const bots = {
  all,
  getBotByClassName(className) {
    return all.find((bot) => bot.getClassname() === className);
  },
};
Repository: sunner/ChatALL
File: src/bots/anthropic/ClaudeAPI20Bot.js (JavaScript)

Code before:
import ClaudeAPIBot from "./ClaudeAPIBot";

export default class ClaudeAPI20Bot extends ClaudeAPIBot {
  static _className = "ClaudeAPI20Bot";
  static _logoFilename = "claude-logo.png";
  static _model = "claude-2.0";
  constructor() {
    super();
  }
}


Review comment (suggestion):
I make 6 logos for the bots. Could you use them?

![claude-20-logo](https://github.com/sunner/ChatALL/assets/255413/e88b54f9-7758-4173-b0dd-b4eaf0c062ec)
![claude-21-logo](https://github.com/sunner/ChatALL/assets/255413/39fd1bf8-d637-45d8-a24a-a5c7ed92993e)
![claude-haiku-logo](https://github.com/sunner/ChatALL/assets/255413/b6bef4cc-92a0-4628-a5bb-3c1d3e8ef231)
![claude-inst-logo](https://github.com/sunner/ChatALL/assets/255413/f453b6bd-7bee-4b33-879b-b3e8e3180ea5)
![claude-opus-logo](https://github.com/sunner/ChatALL/assets/255413/a2e712d1-7e17-4f50-b8d3-2b9dd4652019)
![claude-sonnet-logo](https://github.com/sunner/ChatALL/assets/255413/1560b8d1-cef1-4073-aeb8-ac3acff3553d)


Code after:
import ClaudeAPIBot from "./ClaudeAPIBot";

export default class ClaudeAPI20Bot extends ClaudeAPIBot {
  static _className = "ClaudeAPI20Bot";
  static _logoFilename = "claudeapi-20-logo.png";
  static _model = "claude-2.0";
  constructor() {
    super();
  }
}
Repository: supabase/supabase
File: apps/docs/lib/historyUtils.ts (TypeScript)

Code before:
import { debounce } from 'lodash-es'

let lastUrl = ''

const debouncedHistoryReplaceState = debounce((url: string) => {
  if (typeof window === 'undefined') return

  if (url === lastUrl) return

  try {
    window.history.replaceState(null, '', url)
    lastUrl = url
  } catch (error) {
    console.warn('Failed to call history.replaceState:', error)
  }
}, 120)

export const safeHistoryReplaceState = (url: string): void => {
  const normalizedUrl = url.toString()
  debouncedHistoryReplaceState(normalizedUrl)
}


Review comment (refactor):
Here tracking the last url to avoid unnecessary duplicate calls and also avoiding updating history when URL hasn't actually changed

Code after:
import { debounce } from 'lodash-es'

export const safeHistoryReplaceState = debounce((url: string) => {
  if (typeof window === 'undefined') return

  if (url === window.location.href) return

  try {
    window.history.replaceState(null, '', url)
  } catch (error) {
    console.warn('Failed to call history.replaceState:', error)
  }
}, 120)
Repository: supabase/supabase
File: apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx (TypeScript)

Code before:
  misc: {
    iconKey: 'twitch-icon',
    requiresRedirect: true,
  },
}

const EXTERNAL_PROVIDER_TWITTER = {
  $schema: JSON_SCHEMA_VERSION,
  type: 'object',
  title: 'Twitter',
  link: `${DOCS_URL}/guides/auth/social-login/auth-twitter`,
  properties: {
    EXTERNAL_TWITTER_ENABLED: {
      title: 'Twitter enabled',
      type: 'boolean',
    },
    EXTERNAL_TWITTER_CLIENT_ID: {
      title: 'API Key',
      type: 'string',
    },
    EXTERNAL_TWITTER_SECRET: {
      title: 'API Secret Key',
      type: 'string',
      isSecret: true,
    },
    EXTERNAL_TWITCH_EMAIL_OPTIONAL: {
      title: 'Allow users without an email',
      description:
        'Allows the user to successfully authenticate when the provider does not return an email address.',
      type: 'boolean',
    },
  },
  validationSchema: object().shape({
    EXTERNAL_TWITTER_ENABLED: boolean().required(),
    EXTERNAL_TWITTER_CLIENT_ID: string().when('EXTERNAL_TWITTER_ENABLED', {
      is: true,
      then: (schema) => schema.required('API Key is required'),
      otherwise: (schema) => schema,
    }),
    EXTERNAL_TWITTER_SECRET: string().when('EXTERNAL_TWITTER_ENABLED', {
      is: true,
      then: (schema) => schema.required('API Secret Key is required'),
      otherwise: (schema) => schema,
    }),
    EXTERNAL_TWITCH_EMAIL_OPTIONAL: boolean().optional(),
  }),
  misc: {
    iconKey: 'twitter-icon',
    requiresRedirect: true,
  },
}

Review comment (suggestion):
```suggestion
    EXTERNAL_TWITTER_EMAIL_OPTIONAL: {
```

Code after:
    EXTERNAL_TWITCH_EMAIL_OPTIONAL: boolean().optional(),
  }),
  misc: {
    iconKey: 'twitch-icon',
    requiresRedirect: true,
  },
}

const EXTERNAL_PROVIDER_TWITTER = {
  $schema: JSON_SCHEMA_VERSION,
  type: 'object',
  title: 'Twitter',
  link: `${DOCS_URL}/guides/auth/social-login/auth-twitter`,
  properties: {
    EXTERNAL_TWITTER_ENABLED: {
      title: 'Twitter enabled',
      type: 'boolean',
    },
    EXTERNAL_TWITTER_CLIENT_ID: {
      title: 'API Key',
      type: 'string',
    },
    EXTERNAL_TWITTER_SECRET: {
      title: 'API Secret Key',
      type: 'string',
      isSecret: true,
    },
    EXTERNAL_TWITTER_EMAIL_OPTIONAL: {
      title: 'Allow users without an email',
      description:
        'Allows the user to successfully authenticate when the provider does not return an email address.',
      type: 'boolean',
    },
  },
  validationSchema: object().shape({
    EXTERNAL_TWITTER_ENABLED: boolean().required(),
    EXTERNAL_TWITTER_CLIENT_ID: string().when('EXTERNAL_TWITTER_ENABLED', {
      is: true,
      then: (schema) => schema.required('API Key is required'),
      otherwise: (schema) => schema,
    }),
    EXTERNAL_TWITTER_SECRET: string().when('EXTERNAL_TWITTER_ENABLED', {
      is: true,
      then: (schema) => schema.required('API Secret Key is required'),
      otherwise: (schema) => schema,
    }),
    EXTERNAL_TWITTER_EMAIL_OPTIONAL: boolean().optional(),
  }),
  misc: {
    iconKey: 'twitter-icon',
    requiresRedirect: true,
Repository: supabase/supabase
File: apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx (TypeScript)

Code before:
    },
    EXTERNAL_TWITTER_SECRET: {
      title: 'API Secret Key',
      type: 'string',
      isSecret: true,
    },
    EXTERNAL_TWITCH_EMAIL_OPTIONAL: {
      title: 'Allow users without an email',
      description:
        'Allows the user to successfully authenticate when the provider does not return an email address.',
      type: 'boolean',
    },
  },
  validationSchema: object().shape({
    EXTERNAL_TWITTER_ENABLED: boolean().required(),
    EXTERNAL_TWITTER_CLIENT_ID: string().when('EXTERNAL_TWITTER_ENABLED', {
      is: true,
      then: (schema) => schema.required('API Key is required'),
      otherwise: (schema) => schema,
    }),
    EXTERNAL_TWITTER_SECRET: string().when('EXTERNAL_TWITTER_ENABLED', {
      is: true,
      then: (schema) => schema.required('API Secret Key is required'),
      otherwise: (schema) => schema,
    }),
    EXTERNAL_TWITCH_EMAIL_OPTIONAL: boolean().optional(),
  }),
  misc: {
    iconKey: 'twitter-icon',
    requiresRedirect: true,
  },
}

const EXTERNAL_PROVIDER_SLACK = {
  $schema: JSON_SCHEMA_VERSION,
  type: 'object',
  title: 'Slack (Deprecated)',
  link: `${DOCS_URL}/guides/auth/social-login/auth-slack`,
  properties: {
    EXTERNAL_SLACK_ENABLED: {
      title: 'Slack enabled',
      type: 'boolean',
    },
    EXTERNAL_SLACK_CLIENT_ID: {
      title: 'Client ID',
      type: 'string',
    },
    EXTERNAL_SLACK_SECRET: {
      title: 'Client Secret',
      type: 'string',
      isSecret: true,

Review comment (suggestion):
```suggestion
    EXTERNAL_TWITTER_EMAIL_OPTIONAL: boolean().optional(),
```

Code after:
      title: 'API Key',
      type: 'string',
    },
    EXTERNAL_TWITTER_SECRET: {
      title: 'API Secret Key',
      type: 'string',
      isSecret: true,
    },
    EXTERNAL_TWITTER_EMAIL_OPTIONAL: {
      title: 'Allow users without an email',
      description:
        'Allows the user to successfully authenticate when the provider does not return an email address.',
      type: 'boolean',
    },
  },
  validationSchema: object().shape({
    EXTERNAL_TWITTER_ENABLED: boolean().required(),
    EXTERNAL_TWITTER_CLIENT_ID: string().when('EXTERNAL_TWITTER_ENABLED', {
      is: true,
      then: (schema) => schema.required('API Key is required'),
      otherwise: (schema) => schema,
    }),
    EXTERNAL_TWITTER_SECRET: string().when('EXTERNAL_TWITTER_ENABLED', {
      is: true,
      then: (schema) => schema.required('API Secret Key is required'),
      otherwise: (schema) => schema,
    }),
    EXTERNAL_TWITTER_EMAIL_OPTIONAL: boolean().optional(),
  }),
  misc: {
    iconKey: 'twitter-icon',
    requiresRedirect: true,
  },
}

const EXTERNAL_PROVIDER_SLACK = {
  $schema: JSON_SCHEMA_VERSION,
  type: 'object',
  title: 'Slack (Deprecated)',
  link: `${DOCS_URL}/guides/auth/social-login/auth-slack`,
  properties: {
    EXTERNAL_SLACK_ENABLED: {
      title: 'Slack enabled',
      type: 'boolean',
    },
    EXTERNAL_SLACK_CLIENT_ID: {
      title: 'Client ID',
      type: 'string',
    },
    EXTERNAL_SLACK_SECRET: {
      title: 'Client Secret',
Repository: supabase/supabase
File: apps/studio/components/interfaces/Linter/LinterPageFooter.tsx (TypeScript)

Code before:
import { Button, cn } from 'ui'
import { Markdown } from '../Markdown'

interface LinterPageFooterProps {
  isLoading: boolean
  isRefetching: boolean
  refetch: () => void
  hideDbInspectCTA?: boolean
}

const LinterPageFooter = ({
  isLoading,
  isRefetching,
  refetch,
  hideDbInspectCTA,
}: LinterPageFooterProps) => {
  return (
    <div className="px-6 py-6 flex gap-x-4 border-t ">
      <div
        className={cn(hideDbInspectCTA ? 'w-[35%]' : 'w-[33%]', 'flex flex-col gap-y-1 text-sm')}
      >
        <p>Reset suggestions</p>
        <p className="text-xs text-foreground-light">
          Consider resetting the analysis after making any changes
        </p>

        <Button
          type="default"
          className="!mt-3 w-min"
          disabled={isLoading || isRefetching}
          loading={isLoading || isRefetching}
          onClick={() => refetch()}
        >
          Rerun linter
        </Button>
      </div>

      <div
        className={cn(hideDbInspectCTA ? 'w-[35%]' : 'w-[33%]', 'flex flex-col gap-y-1 text-sm')}
      >
        <p>How are these suggestions generated?</p>
        <div className="prose text-xs">
          <p>
            <span>These suggestions use </span>
            <a href="https://github.com/supabase/splinter" target="" rel="">
              splinter (Supabase Postgres LINTER)

Review comment (security):
This local storage key is shared for both Performance and Security Advisor. I figured that’s fine since they are so similar in nature; if a user dismisses one, they’re likely to have the other dismissed too.

Code after:
import { X } from 'lucide-react'
import { LOCAL_STORAGE_KEYS } from 'common'
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
import { Button, cn } from 'ui'
import { Markdown } from '../Markdown'

interface LinterPageFooterProps {
  isLoading: boolean
  isRefetching: boolean
  refetch: () => void
  hideDbInspectCTA?: boolean
}

const LinterPageFooter = ({
  isLoading,
  isRefetching,
  refetch,
  hideDbInspectCTA,
}: LinterPageFooterProps) => {
  const [showBottomSection, setShowBottomSection] = useLocalStorageQuery(
    LOCAL_STORAGE_KEYS.LINTER_SHOW_FOOTER,
    true
  )

  if (!showBottomSection) {
    return null
  }

  return (
    <div className="px-6 py-6 flex gap-x-4 border-t relative">
      <Button
        className="absolute top-1.5 right-3 px-1.5"
        type="text"
        size="tiny"
        onClick={() => setShowBottomSection(false)}
      >
        <X size="14" />
      </Button>
      <div
        className={cn(hideDbInspectCTA ? 'w-[35%]' : 'w-[33%]', 'flex flex-col gap-y-1 text-sm')}
      >
        <p>Reset suggestions</p>
        <p className="text-xs text-foreground-light">
          Consider resetting the analysis after making any changes
        </p>
Repository: supabase/supabase
File: apps/studio/lib/api/self-hosted/query.ts (TypeScript)

Code before:
import { assertSelfHosted } from './util'

export type QueryOptions = {
  query: string
  headers?: HeadersInit
}

/**
 * Executes a SQL query against the self-hosted Postgres instance via pg-meta service.
 *
 * _Only call this from server-side self-hosted code._
 */
export async function executeQuery<T = unknown>({
  query,
  headers,
}: QueryOptions): Promise<WrappedResult<T[]>> {
  assertSelfHosted()

  const response = await fetch(`${PG_META_URL}/query`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...constructHeaders(headers ?? {}),
    },
    body: JSON.stringify({ query }),
  })

  try {
    const result = await response.json()

    if (!response.ok) {
      const { message, code } = databaseErrorSchema.parse(result)
      const error = new DatabaseError(message, code)
      return { data: undefined, error }
    }

    return { data: result, error: undefined }
  } catch (error) {
    if (error instanceof Error) {
      return { data: undefined, error }
    }
    throw error
  }
}


Review comment (bug):
Switching this to a vanilla `fetch()` in order to capture pg-meta specific database errors. I'm 99% sure we don't need the special `fetchPost()` logic in the context of server-side self-hosted code, but let me know if this is wrong.

Code after:
import { assertSelfHosted } from './util'

export type QueryOptions = {
  query: string
  headers?: HeadersInit
}

/**
 * Executes a SQL query against the self-hosted Postgres instance via pg-meta service.
 *
 * _Only call this from server-side self-hosted code._
 */
export async function executeQuery<T = unknown>({
  query,
  headers,
}: QueryOptions): Promise<WrappedResult<T[]>> {
  assertSelfHosted()

  const response = await fetch(`${PG_META_URL}/query`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...constructHeaders(headers ?? {}),
    },
    body: JSON.stringify({ query }),
  })

  try {
    const result = await response.json()

    if (!response.ok) {
      const { message, code, formattedError } = databaseErrorSchema.parse(result)
      const error = new PgMetaDatabaseError(message, code, response.status, formattedError)
      return { data: undefined, error }
    }

    return { data: result, error: undefined }
  } catch (error) {
    if (error instanceof Error) {
      return { data: undefined, error }
    }
    throw error
  }
}