DEV Community

Katie Liu
Katie Liu

Posted on

ChatCraft week 14: Releasing v2.0!

Today marks the final day on the open source team working on ChatCraft! It's been an eventful week as everyone scrambles to polish up their feature code with final bug fixes.

Meeting with Taras

This week we met with Taras, the founder of ChatCraft online to showcase our contributions and get some professional advice from him. It was very rewarding to see what we managed to get done in the span of four months with our small team of six!

Some of our notable features include but are not limited to:

  • Image reading and image generation
  • Custom provider support
  • Text to Speech
  • Google OAuth support
  • Mobile support


This week, I focused my attention on bug fixes since this is the last week and I didn't want to risk introducing any new issues. The issue I worked on was something brought up to me by Rachit in the previous week - we don't want to save an api key into localStorage unless it has been validated.

It was not a problem previously to save invalid api keys, but now it has become a problem since we can now toggle between Providers by using the up arrow next to the "Ask" button:

Image description

When you press the up arrow, as you can see in the screenshot above, you get to toggle between all the providers you have saved keys for. This includes any custom providers you have added! However we don't want to show any provider with an invalid key in this list, since even if a user selects it they won't be able to use it. (They will get error when they try to send a message)

To fix this issue I opened the following PR:

Enhancement - only save keys to settings.providers if validated #597

Fixes #596

Summary: No longer saving providers or their api keys to settings.providers array unless the api key is validated. If an invalid or blank is entered, the provider is REMOVED from settings.providers.

Important coding points:

  • Removed the placeholder text in the api key field when you create a new custom provider row (placeholder text was showing up as asterix)
  • Removed the useDebounce code, it wasn't working and is not worth the trouble to fix. useDebounce is sort of like a useEffect, but which allows us to wait until the user stops typing to validate the key. However, we do not expect anyone to be typing out a 32 character api key anyways, so opted to remove.
  • The keys are stored in tableProviders and only when they are validated they are stored to settings.providers
  • In these scenarios, tableProviders is synced with settings.providers: (when "syncing" happens, those invalid and blank api keys will disappear)
    • When modal first opens
    • When modal closes
    • When current provider is set (need to sync to update the checkmark)
    • When a custom provider is deleted (need to sync to show the row deleted)
    • When a custom provider is added (need to sync to show the new row)
  • Note: If you create a custom provider and then later set the key to something invalid, when you close the modal the custom provider row will disappear since we only save it if it has a valid key.

I am no longer automatically updating localStorage when the user enters a key; instead, I store the key in the tableProviders array. Only when the key has been validated I will store it to settings.providers (localStorage). And if a key is invalid or blank, I will remove it from localStorage.

  const handleApiKeyChange = async (provider: ChatCraftProvider, apiKey: string) => {
    const newProvider = providerFromUrl(


    const newProviders = { ...settings.providers };

    // Update api key in table
    tableProviders[] = newProvider;

    // Api key validation
    try {

      const result = await newProvider.validateApiKey(newProvider.apiKey!);


      if (result) {
        // Valid key, update in settings.providers
        newProviders[] = newProvider;
      } else {
        // Invalid key, remove from settings.providers
        delete newProviders[];
    } catch (err: any) {

      // Invalid key, remove from settings.providers
      delete newProviders[];

      ...( === && { currentProvider: newProvider }),
      providers: newProviders,

    if ( === selectedProvider?.name) {

Enter fullscreen mode Exit fullscreen mode


This week I am the sheriff, meaning I am the go-to contact person whenever there is any issues with PRs blocked or needed reviews. As I result I reviewed 5 PRs this week! I also contributed code to one PR.

See all the PR's in this week's 2.0 release!

Top comments (0)