# Rafael Thayto - Full Content
> Complete blog content for LLM consumption. Written in Portuguese (BR) and English.
---
## Home
# Rafael Thayto
> Senior Software Engineer
Atualmente tenho mais de 7 anos de experiência como desenvolvedor. Desde o inicio da minha carreira lá em 2018 (quando comecei à atuar profissionalmente) sempre trabalhei com sistemas distribuídos, microsserviços, microfrontends e observabilidade. Já trabalhei em grandes empresas ([BlindPay](https://blindpay.com/), [Clerk](https://clerk.com), [Nike](https://nike.com), [Resend](https://resend.com), [Outlit (YC W25)](https://outlit.ai), [Flash](https://flashapp.com.br), [🦄 Creditas](https://creditas.com), Safra Bank ([NY](https://www.safra.com/), [BR](https://www.safra.com.br/), [Suíça](https://www.jsafrasarasin.com/)), [Avanade](https://avanade.com)) com milhões de usuarios ativos, milhões de transações diárias e que já transacionaram bilhões de dólares, empresas no Brasil, EUA e Suíça.
Aqui vocês vão encontrar alguns posts sobre tecnologia e alguns pensamentos (tanto em inglês quanto em português).
## Curiosidades
Fiz minha própria ferramenta de trabalho para orquestrar meus agentes, o [Thaytool](https://thaytool.com). Algumas contribuições open source que já fiz ([CLI da Clerk](https://github.com/clerk/cli), [CLI da Resend](https://github.com/resend/resend-cli), [SDK e CLI da Outlit](https://github.com/OutlitAI/outlit-sdk), [MCP Apps](https://github.com/modelcontextprotocol/ext-apps)), publiquei o [ajusta](https://www.npmjs.com/package/ajusta) e o [mdlens](https://www.npmjs.com/package/mdlens) no npm, escrevo artigos no [dev.to](https://dev.to/thayto), no [TabNews](https://www.tabnews.com.br/thayto) e no [Substack](https://thayto.substack.com/), criei o podcast [DevSenior Cast](https://creators.spotify.com/pod/profile/devseniorscast/), posto sobre tech e carreira no [X/Twitter](https://x.com/thayto_dev), no [Instagram](https://www.instagram.com/thayto_dev), no [TikTok](https://www.tiktok.com/@thayto_dev) e no [YouTube](https://www.youtube.com/@thayto_dev), e já fui tão apaixonado por perfumes que até tive um [TikTok de perfumes](https://www.tiktok.com/@thayto_perfumes) por um tempo. Se quiser mais links dá uma olhada no meu [linktree](https://thayto.com/linktree).
## Posts
- [Como Deixar a Sugestão de Arquivos do Claude Code Mais Rápida](https://thayto.com/blog/claude-code-faster-file-suggestion.md) - 2026-01-08
- [Micro Frontends com Next.js Multi Zones](https://thayto.com/blog/microfrontends-next-js-multi-zones.md) - 2024-10-01
- [Deploy sem downtime com Docker Compose em VPS OCI usando GitHub Actions](https://thayto.com/blog/zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions.md) - 2024-09-13
- [Expondo seu localhost com Ngrok (muito útil para testar webhooks)](https://thayto.com/blog/expondo-seu-localhost-com-ngrok.md) - 2024-07-06
- [TypeScript - Como pegar uma string no seu Literal Types](https://thayto.com/blog/ts-como-pegar-string-no-seu-literal-types.md) - 2023-07-24
- [TypeScript - Template Literal Types](https://thayto.com/blog/typescript-template-literal-types.md) - 2023-07-07
- [Como abrir o Visual Studio Code (VSCode) dentro do GitHub](https://thayto.com/blog/como-abrir-o-vscode-direto-do-github.md) - 2022-11-05
- [Diferença entre os operadores ?, ?? e || no JavaScript / TypeScript](https://thayto.com/blog/diferenca-entre-operadores-js-ts.md) - 2022-10-31
- [Turbinando seu git bash (Windows) adicionando aliases (como se fosse o git plugin do zsh)](https://thayto.com/blog/turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh.md) - 2022-10-23
- [Como configurar o deploy do Turborepo no Netlify](https://thayto.com/blog/como-configurar-o-deploy-do-turborepo-no-netlify.md) - 2022-06-21
- [Como 'settar' a versão default do Node usando nvm](https://thayto.com/blog/como-settar-a-versao-default-do-node-usando-nvm.md) - 2022-06-19
## Links
- [Blog](https://thayto.com/blog)
- [About](https://thayto.com/about)
- [Books](https://thayto.com/books)
- [Hobbies](https://thayto.com/hobbies)
- [Linktree](https://thayto.com/linktree)
---
# Rafael Thayto
> Senior Software Engineer
I currently have over 7 years of experience as a developer. Since the beginning of my career back in 2018 (when I started working professionally) I have always worked with distributed systems, microservices, microfrontends and observability. I have worked at large companies ([BlindPay](https://blindpay.com/), [Clerk](https://clerk.com), [Nike](https://nike.com), [Resend](https://resend.com), [Outlit (YC W25)](https://outlit.ai), [Flash](https://flashapp.com.br), [🦄 Creditas](https://creditas.com), Safra Bank ([NY](https://www.safra.com/), [BR](https://www.safra.com.br/), [Switzerland](https://www.jsafrasarasin.com/)), [Avanade](https://avanade.com)) with millions of active users, millions of daily transactions and billions of dollars transacted, companies in Brazil, USA and Switzerland.
Here you will find some posts about technology and some thoughts (both in English and Portuguese).
## Fun facts
I built my own work tool to orchestrate my agents, [Thaytool](https://thaytool.com). Some open source contributions I've made ([Clerk's CLI](https://github.com/clerk/cli), [Resend's CLI](https://github.com/resend/resend-cli), [Outlit's SDK and CLI](https://github.com/OutlitAI/outlit-sdk), [MCP Apps](https://github.com/modelcontextprotocol/ext-apps)), published [ajusta](https://www.npmjs.com/package/ajusta) and [mdlens](https://www.npmjs.com/package/mdlens) on npm, write articles on [dev.to](https://dev.to/thayto), [TabNews](https://www.tabnews.com.br/thayto) and [Substack](https://thayto.substack.com/), created the [DevSenior Cast](https://creators.spotify.com/pod/profile/devseniorscast/) podcast, post about tech and career on [X/Twitter](https://x.com/thayto_dev), [Instagram](https://www.instagram.com/thayto_dev), [TikTok](https://www.tiktok.com/@thayto_dev) and [YouTube](https://www.youtube.com/@thayto_dev), and I was once so passionate about perfumes that I even had a [perfume TikTok](https://www.tiktok.com/@thayto_perfumes) for a while. If you want more links, check out my [linktree](https://thayto.com/linktree).
## Posts
- [Quick Guide to Make Claude Code File Suggestion Faster](https://thayto.com/en/blog/claude-code-faster-file-suggestion.md) - 2026-01-08
- [Micro Frontends with Next.js Multi Zones](https://thayto.com/en/blog/microfrontends-next-js-multi-zones.md) - 2024-10-01
- [Zero Downtime Deployment with Docker Compose in an OCI VPS using GitHub Actions](https://thayto.com/en/blog/zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions.md) - 2024-09-13
- [Exposing Your Localhost with Ngrok (Very Useful for Testing Webhooks)](https://thayto.com/en/blog/expondo-seu-localhost-com-ngrok.md) - 2024-07-06
- [TypeScript - How to Extract a String from Your Literal Types](https://thayto.com/en/blog/ts-como-pegar-string-no-seu-literal-types.md) - 2023-07-24
- [TypeScript - Template Literal Types](https://thayto.com/en/blog/typescript-template-literal-types.md) - 2023-07-07
- [How to Open Visual Studio Code (VSCode) Inside GitHub](https://thayto.com/en/blog/como-abrir-o-vscode-direto-do-github.md) - 2022-11-05
- [Difference Between the ?, ?? and || Operators in JavaScript / TypeScript](https://thayto.com/en/blog/diferenca-entre-operadores-js-ts.md) - 2022-10-31
- [Supercharging Your Git Bash (Windows) by Adding Aliases (Like the zsh git plugin)](https://thayto.com/en/blog/turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh.md) - 2022-10-23
- [How to Configure Turborepo Deployment on Netlify](https://thayto.com/en/blog/como-configurar-o-deploy-do-turborepo-no-netlify.md) - 2022-06-21
- [How to Set the Default Node Version Using nvm](https://thayto.com/en/blog/como-settar-a-versao-default-do-node-usando-nvm.md) - 2022-06-19
## Links
- [Blog](https://thayto.com/en/blog)
- [About](https://thayto.com/en/about)
- [Books](https://thayto.com/en/books)
- [Hobbies](https://thayto.com/en/hobbies)
- [Linktree](https://thayto.com/en/linktree)
---
## Blog Posts (Portuguese)
### Como Deixar a Sugestão de Arquivos do Claude Code Mais Rápida
Source: https://thayto.com/blog/claude-code-faster-file-suggestion
---
title: 'Como Deixar a Sugestão de Arquivos do Claude Code Mais Rápida'
publishedTime: '2026-01-08T12:00:00Z'
modifiedTime: '2026-01-08T12:00:00Z'
description: 'Aprenda a melhorar a sugestão de arquivos do Claude Code usando fzf para fuzzy matching, suporte a symlinks e melhor performance.'
image:
{
src: 'claude-code-faster-file-suggestion.jpg',
placeholder: 'claude-code-faster-file-suggestion-small.jpg',
type: 'image/jpeg',
}
tags: ['claude-code', 'cli', 'fzf', 'productivity', 'tutorial']
href: '/blog/claude-code-faster-file-suggestion'
reactionsLength: 0
commentsLength: 0
---
A sugestão padrão de arquivos com `@` do Claude Code sempre me decepcionou, sendo acostumado com opções superiores tipo fzf.
Além disso, não sugeria arquivos de pastas gitignored ou symlinks, o que era chato pra caramba.
Mas recentemente a Anthropic liberou a customização via File Suggestion settings.
E cara! Fuzzy matching de verdade com fzf é muito melhor do que o padrão!
## Pré-requisitos
Você vai precisar instalar essas ferramentas CLI:
- **rg (ripgrep)** - pra listagem rápida de arquivos com suporte a symlink
- **fzf** - pro fuzzy matching
- **jq** - pra parsear o JSON de entrada
## Setup
### 1. Configurar o Claude Code
Adiciona isso no seu `~/.claude/settings.json`:
```json
"fileSuggestion": {
"type": "command",
"command": "~/.claude/file-suggestion.sh"
}
```
### 2. Criar o Script de Sugestão de Arquivos
Cria o arquivo `~/.claude/file-suggestion.sh` com esse conteúdo:
```bash
#!/bin/bash
# Custom file suggestion script for Claude Code
# Uses rg + fzf for fuzzy matching and symlink support
# Parse JSON input to get query
QUERY=$(jq -r '.query // ""')
# Use project dir from env, fallback to pwd
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
# cd into project dir so rg outputs relative paths
cd "$PROJECT_DIR" || exit 1
{
# Main search - respects .gitignore, includes hidden files, follows symlinks
rg --files --follow --hidden . 2>/dev/null
# Additional paths - include even if gitignored (uncomment and customize)
# [ -e .notes ] && rg --files --follow --hidden --no-ignore-vcs .notes 2>/dev/null
} | sort -u | fzf --filter "$QUERY" | head -15
```
### 3. Tornar o Script Executável
Não esquece de deixar o script executável:
```bash
chmod +x ~/.claude/file-suggestion.sh
```
### 4. Reiniciar o Claude Code
Reinicia o Claude Code e boa!
tmj :)
---
### Micro Frontends com Next.js Multi Zones
Source: https://thayto.com/blog/microfrontends-next-js-multi-zones
---
title: 'Micro Frontends com Next.js Multi Zones'
publishedTime: '2024-10-01T16:09:33Z'
modifiedTime: '2024-10-03T16:09:33Z'
description: 'Quando estamos desenvolvendo uma aplicação Web e ela acaba escalando, geralmente precisamos de um time. Quando essa aplicação escala mais ainda, precisamos de mais times trabalhando na mesma aplicação.'
image:
{
src: 'microfrontends-next-js-multi-zones.jpg',
placeholder: 'microfrontends-next-js-multi-zones-small.jpg',
type: 'image/jpeg',
}
tags: ['microfrontends', 'nextjs', 'tutorial', 'react']
href: '/blog/microfrontends-next-js-multi-zones'
reactionsLength: 0
commentsLength: 0
---
## Introdução
Quando estamos desenvolvendo uma aplicação Web e ela acaba escalando, geralmente precisamos de um time. Quando essa aplicação escala mais ainda, precisamos de mais times trabalhando na mesma aplicação.
Por que estou falando isso?
Porque geralmente quando temos muitas pessoas alterando o mesmo projeto, podemos ter diversos problemas. Sejam eles muitos _Pull Requests_, diferenças de escopos, regras de negócio distintas, conflitos de _merge_ e até mesmo divergências de ideias.
Quando isso acontece o que geralmente pensamos é em separar um pedaço dele em outro projeto e criar o famoso Micro Frontend que vai agilizar nossas entregas e garantir que o projeto evolua de maneira mais rápida e independente de outros escopos.
O que facilita e muito o desenvolvimento!
Com o isso o time do _Next.js_ criou uma feature avançada que chama [**Multi Zones**](https://nextjs.org/docs/advanced-features/multi-zones), com ela a gente consegue criar diversos Micro Frontends de forma muito rápida e simples utilizando _**Next.js**_
## Pré-requisitos
Antes de continuar a ler esse artigo, eu presumo que você tenha uma noção básica / familiaridade com **_Next.js_**
## O que vamos fazer
Até o final desse artigo vamos fazer 2 apps com Next.js, combinar eles usando a feature de **Multi Zones**. Vou fazer também uma parte 2 mostrando como deployar as 2 aplicações na Vercel.
## Criando a pasta do projeto
Abre seu terminal/cmd e manda o seguinte comando:
```bash
mkdir nextjs-multi-zones-post
cd nextjs-multi-zones-post
```
Logo em seguida abram essa mesma pasta no editor preferido de vocês! (nessa época era o VSCode 💩, hoje em dia é o Neovim/VIM ❤️)
## Criando os projetos
Após ter entrado na pasta que vai centralizar nossos projetos, chegou a hora de criá-los!
### Primeira aplicação - Home
Abre seu terminal aí e escreve o seguinte comando para criarmos o primeiro projeto que vai ser nossa **HOME**:
```bash
npx create-next-app --ts home
cd home
```
Depois de criar a home, vamos alterar a porta em que o projeto vai rodar pra facilitar a nossa vida e termos um padrão até o final do post
Abra o arquivo `package.json` que está dentro da sua home e altere o script de dev de:
```json
...
"scripts": {
"dev": "next dev",
...
},
...
```
para:
```json
...
"scripts": {
"dev": "next dev -p 4444",
...
},
...
```
Abra seu terminal na mesma pasta e rode o seguinte comando pra executar a aplicação:
```
npm run dev
```
### Segunda aplicação - Blog
Abra outro terminal e rode o seguinte comando para criarmos o nosso segundo projeto que vai ser nosso **BLOG**:
```bash
npx create-next-app --ts blog
cd blog
```
Vamos seguir o mesmo procedimento que fizemos para home agora com o blog
Abra o arquivo `package.json` que está dentro do seu blog e altere o script de dev de:
```json
...
"scripts": {
"dev": "next dev",
...
},
...
```
para:
```json
...
"scripts": {
"dev": "next dev -p 7777",
...
},
...
```
Abra seu terminal na mesma pasta e rode o seguinte comando pra executar a aplicação:
```
npm run dev
```
Pronto, agora já temos as 2 aplicações rodando e o resultado tem que ser algo parecido com isso:

**Home (Aplicação 1)** rodando na porta **http://localhost:4444** e o **Blog (Aplicação 2)** rodando na porta **http://localhost:7777**
## Configurando a Home (Aplicação 1)
O primeiro projeto que vamos desenvolver e configurar vai ser Home que além de ser o projeto base também vai ser nossa Home. É nele onde vamos configurar as URLs que vamos fazer o [rewrite](https://nextjs.org/docs/api-reference/next.config.js/rewrites) para que o Micro Frontend e as Multi Zones funcionem.
Abram o arquivo `next.config.js` e adicionem as seguintes linhas de código:
```js
const { BLOG_URL } = process.env
const nextConfig = {
async rewrites() {
return [
{
source: '/:path*',
destination: `/:path*`,
},
{
source: '/blog',
destination: `${BLOG_URL}/blog`,
},
{
source: '/blog/:path*',
destination: `${BLOG_URL}/blog/:path*`,
},
]
},
}
```
Na parte de `rewrites` é basicamente uma reescrita mesmo, vamos reescrever as rotas `/blog` e tudo que vier depois, como por exemplo `/blog/posts/hello-world`. Para saber mais sobre rewrites é só acessar a documentação oficial do **Next.js**.
E vocês podem perceber que também adicionamos uma constante usando uma desestruturação no objeto `process.env` para podermos pegara `URL` do blog via variáveis de ambiente.
Agora bora criar o arquivo `.env` na raiz do nosso projeto da `home` como mostra no exemplo abaixo.

É nele onde vamos colocar o `BLOG_URL` apontando para o `http://localhost:7777` que é onde está rodando nosso projeto do blog.
`.env`
```txt
BLOG_URL=http://localhost:7777
```
Agora dentro do nosso projeto da home vamos transformar o `index.tsx` nisso daqui:
```tsx
import type { NextPage } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import styles from '../styles/Home.module.css'
const Home: NextPage = () => {
return (
)
}
export default Home
```
Basicamente adicionamos 3 links, sendo 2 deles para páginas do nosso blog (ainda não construído) e 1 link para o redirecionamento para uma página interna nossa que é a _About Us_.

Agora vamos criar o arquivo `about.tsx` dentro de `home/pages/about.tsx`:

`about.tsx`
```tsx
import type { NextPage } from 'next'
import Link from 'next/link'
const About: NextPage = () => {
return (
)
}
export default About
```
Aqui criamos uma página sobre nós bem simples que só tem um texto e um link que nos faz voltar para a home.
E assim finalizamos a parte da **Home**. Agora bora pro Blog!
## Configurando o Blog (Aplicação 2)
Agora vamos configurar o blog. No blog vai ser um pouco mais simples, basicamente vamos abrir o arquivo `next.config.js` e adicionar a propriedade `basePath` dentro do `nextConfig`, ele vai dizer para o next que a _URL_ base dele vai começar no endereço que escolhermos, que nesse caso vai ser `/blog`
`next.config.js`
```js
const nextConfig = {
basePath: '/blog',
}
module.exports = nextConfig
```
> Lembrando que toda vez que alteramos o arquivo **next.config.js** ou adicionamos algo no **.env** precisamos parar o servidor e inicia-lo novamente 😁
Agora dentro do nosso projeto da blog vamos transformar o `index.tsx` nisso daqui:
```tsx
import type { NextPage } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import styles from '../styles/Home.module.css'
const Blog: NextPage = () => {
return (
)
}
export default Blog
```
Na raiz do nosso blog temos 1 link que leva para nossa **Home** e 2 links que nos levam a posts no nosso blog

Na imagem acima vocês já conseguem ver a mágica acontecendo, se vocês olharem para o URL vão perceber que estamos rodando no **http://localhost:4444/blog**, mas por quê isso acontece?
Quando configuramos o `basePath` dentro do `next.config.js` do projeto **Blog**, dizemos para o next que o `index.tsx` e todos os outros arquivos vão ser acessados sempre a partir do nosso `basePath` que nesse caso é `/blog`.
Também devemos nos lembrar que no `next.config.js` do nosso projeto **Home** configuramos que sempre que estivermos em **http://localhost:4444** e acessarmos o `/blog` ou qualquer coisa depois de blog, estaremos fazendo um rewrite da rota e estaremos apontando para o nosso **Blog** via **Home**.
> Ou seja: http://localhost:4444/blog vai apontar para http://localhost:7777/blog
O mais incrível de tudo isso é que conseguimos acessar a nossa outra aplicação (blog) dentro da nossa aplicação (home) **sem alterar a URL** 🤯, não é impressionante?
_Cover Image: Photo by Andrey Tikhonovskiy on Unsplash_
---
### Deploy sem downtime com Docker Compose em VPS OCI usando GitHub Actions
Source: https://thayto.com/blog/zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions
---
title: 'Deploy sem downtime com Docker Compose em VPS OCI usando GitHub Actions'
publishedTime: '2024-09-13T21:16:36Z'
modifiedTime: '2024-09-13T21:16:36Z'
description: 'Primeiro, você precisa ter um VPS Linux (vou usar Ubuntu 22 nesse tutorial). Tags: docker, devops, github actions, linux, tutorial.'
image:
{
src: 'zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions.jpg',
placeholder: 'zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions-small.jpg',
type: 'image/jpeg',
}
tags: ['docker', 'devops', 'github actions', 'linux', 'tutorial']
href: '/blog/zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions'
reactionsLength: 0
commentsLength: 0
---
Primeiro, você precisa ter um VPS Linux (vou usar Ubuntu 22 nesse tutorial).
## Requisitos
- Docker
- Docker Compose
- [Docker Rollout Plugin](https://github.com/Wowu/docker-rollout?tab=readme-ov-file#installation)
### Instalando o Docker Rollout Plugin
É bem simples:
```bash
# Create directory for Docker cli plugins
mkdir -p ~/.docker/cli-plugins
# Download docker-rollout script to Docker cli plugins directory
curl https://raw.githubusercontent.com/wowu/docker-rollout/master/docker-rollout -o ~/.docker/cli-plugins/docker-rollout
# Make the script executable
chmod +x ~/.docker/cli-plugins/docker-rollout
```
### Como usar o Docker Rollout
Rode `docker rollout ` ao invés de `docker compose up -d ` para atualizar um serviço sem downtime.
```bash
$ docker rollout -f docker-compose.yml
```
## Workflow GitHub Actions build_and_deploy.yml
> Nesse caso estou usando um registry privado no Digital Ocean.
```yaml
name: CI
# 1
# Controls when the workflow will run
on:
# Triggers the workflow on push events but only for the master branch
push:
branches: [main]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
inputs:
version:
description: 'Image version'
required: true
#2
env:
REGISTRY: 'registry.digitalocean.com/YOUR_REGISTRY_NAME'
IMAGE_NAME: 'YOUR_IMAGE_NAME'
#3
jobs:
build_and_push:
runs-on: ubuntu-latest
steps:
- name: Checkout the repo
uses: actions/checkout@v4
- name: Build container image
run: docker build -t $(echo $REGISTRY)/$(echo $IMAGE_NAME):$(echo $GITHUB_SHA | head -c7) .
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Log in to DigitalOcean Container Registry with short-lived credentials
run: doctl registry login --expiry-seconds 600
- name: Remove all old images
run: if [ ! -z "$(doctl registry repository list | grep "$(echo $IMAGE_NAME)")" ]; then doctl registry repository delete-manifest $(echo $IMAGE_NAME) $(doctl registry repository list-tags $(echo $IMAGE_NAME) | grep -o "sha.*") --force; else echo "No repository"; fi
- name: Push image to DigitalOcean Container Registry
run: docker push $(echo $REGISTRY)/$(echo $IMAGE_NAME):$(echo $GITHUB_SHA | head -c7)
deploy:
runs-on: ubuntu-latest
needs: build_and_push
steps:
- name: Deploy to Digital Ocean droplet via SSH action
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.OCI_HOST }}
username: ${{ secrets.OCI_USERNAME }}
key: ${{ secrets.OCI_SSH_KEY }}
envs: IMAGE_NAME,REGISTRY,{{ secrets.DIGITALOCEAN_ACCESS_TOKEN }},GITHUB_SHA
script: |
whoami
cd ~/app
pwd
ls -la
# Login to registry
docker login -u ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} -p ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} registry.digitalocean.com
# Update the APP image in docker-compose.yml
sed -i '0,/image:/s|image: .*|image: '$(echo $REGISTRY)'/'$(echo $IMAGE_NAME)':'$(echo $GITHUB_SHA | head -c7)'|' docker-compose.yml
# Pull the latest image
docker compose pull
# Here is the magic docker plugin
docker rollout -f docker-compose.yml app
echo "Deployed with success to production"
```
## Conclusão
Espero que esse tutorial te ajude de alguma forma, tmj!
Rafael Thayto.
_Photo by Bernd 📷 Dittrich on Unsplash_
---
### Expondo seu localhost com Ngrok (muito útil para testar webhooks)
Source: https://thayto.com/blog/expondo-seu-localhost-com-ngrok
---
title: 'Expondo seu localhost com Ngrok (muito útil para testar webhooks)'
publishedTime: '2024-07-06T15:58:51Z'
modifiedTime: '2024-07-06T15:58:51Z'
description: 'Estava precisando fazer alguns testes de webhooks, porém só conhecia uma maneira que seria deployar a app e só assim conseguir testar os webhooks. Esse método funciona e é muito utilizado por devs. Mas ele tem um problema... todo teste você vai precisar deployar novamente sua aplicação e isso leva bastante tempo.'
image:
{
src: 'expondo-seu-localhost-com-ngrok.jpg',
placeholder: 'expondo-seu-localhost-com-ngrok-small.jpg',
type: 'image/jpeg',
}
tags: ['ngrok', 'webhooks', 'tutorial']
href: '/blog/expondo-seu-localhost-com-ngrok'
reactionsLength: 0
commentsLength: 0
---
> Os problemas de "na minha máquina funciona" acabaram!
## Problema
Estava precisando fazer alguns testes de webhooks, porém só conhecia uma maneira que seria deployar a app e só assim conseguir testar os webhooks. Esse método funciona e é muito utilizado por devs. Mas ele tem um problema... todo teste você vai precisar deployar novamente sua aplicação e isso leva bastante tempo.
Pesquisando por aí encontrei o [Ngrok](https://ngrok.com/) e com ele conseguimos expor nosso localhost de forma bem simples.
## Instalação
> você pode seguir a [Documentação Oficial](https://ngrok.com/docs/guides/getting-started/#step-2-install-the-ngrok-agent) também.
### Mac
Use o [Homebrew](https://brew.sh/):
```bash
brew install ngrok/ngrok/ngrok
```
### Linux
Use o apt
```bash
curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | \
sudo gpg --dearmor -o /etc/apt/keyrings/ngrok.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/ngrok.gpg] https://ngrok-agent.s3.amazonaws.com buster main" | \
sudo tee /etc/apt/sources.list.d/ngrok.list && \
sudo apt update && sudo apt install ngrok
```
### Windows
Use o [Chocolatey](https://chocolatey.org/install)
```bash
choco install ngrok
```
## Conecte o seu agent à sua conta do ngrok
Pra isso é necessário que você faça o [log in ou sign up](https://dashboard.ngrok.com/) no Ngrok e pegue seu Authtoken.
Copie o token e adicione no seu terminal
```bash
ngrok config add-authtoken
```
## Rode o Ngrok
Starte o Ngrok rodando o comando abaixo (você pode escolher a porta que preferir, mas no exemplo utilizei a porta `8000`):
```bash
ngrok http 8000
```
Obrigado por ler até aqui! Espero que esse post te ajude :)
Confira mais em https://thayto.com/links
_Cover Image: Photo by Stepan Kalinin on Unsplash_
---
### TypeScript - Como pegar uma string no seu Literal Types
Source: https://thayto.com/blog/ts-como-pegar-string-no-seu-literal-types
---
title: 'TypeScript - Como pegar uma string no seu Literal Types'
publishedTime: '2023-07-24T15:58:51Z'
modifiedTime: '2024-07-07T21:33:51Z'
description: 'Não vou enrolar nada. Basicamente é só você utilizar o Utility Type Extract do próprio TypeScript e boa!'
image:
{
src: 'ts-como-pegar-string-no-seu-literal-types.jpg',
placeholder: 'ts-como-pegar-string-no-seu-literal-types-small.jpg',
type: 'image/jpeg',
}
tags: ['typescript', 'utilities', 'types', 'tutorial']
href: '/blog/ts-como-pegar-string-no-seu-literal-types'
reactionsLength: 0
commentsLength: 0
---
Salve, salve devs seniors.
Não vou enrolar nada. Basicamente é só você utilizar o _Utility Type_ `Extract` do próprio **TypeScript** e boa! _**Por exemplo:**_
```ts
type CatNames = 'Garfield' | 'Yoru' | 'Yuki' | 'Fluffy' | 'Lady' | 'Lucky'
type MyCatNames = Extract
// |-> Extract these two `literal types` from CatNames `literal type`
type Cat = {
age: number
name: CatNames
}
function getMyCat(age: number, name: MyCatNames): Cat {
// |--> only show 'Yoru' and
// 'Yuki'
return {
age,
name,
} as Cat
}
const myCat1 = getMyCat(1, 'Yoru')
const myCat2 = getMyCat(1, 'Yuki')
const otherCat: Cat = {
age: 3,
name: 'Garfield',
}
const otherCatWithMyCatName: Cat = {
age: 5,
name: 'Yoru',
}
// tmj!
```
> link do [TS Playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAwghsAcnAthAzlAvFA5AcTgCcAzASwgBsATXKAHzwE0B7IgVzsdyfYGsyXPADFK7EiRBDcAGTjUpDPDPYBjPlIBQm0JCgBZEPCSoM2KAFEAHsCJxVwADzHkadABpmbTkp79BAHyaUCGhYeERkVEA9NEMALQBljZ2DlDAABYY0MAA7ixQAAaUZMAQdpTp4BiFUCRELCiwCK5mxaXlcJW6EIXaPc3A5gDewVBwAOYQAFxQAHbsKABG5e5jc6azLqbomgC+2iTscw5kLHNQU8CGxgAUkzPziytEnhtoszctOwCUWwhQUZRYEgsKxBKJKDnSggKDoDIsXJeDh0OBzahQMag7ERcE4kJ+AS4MZECDAdhEC5A0IPNZhd4QOlQPbjTDGfbaVTndBDFBGBAARnMVy+wFuAs8PG8uB+mi5cx5UD5xgATMKyaLxZLeETZXLuUMWJlysZ-kMcNSQg9ZgBmJkhBmzAjEchUWgc+WKo1ZIjGADqpQyotaZpGWPGU1mAFZ7fNNsjOPsgA)
espero que ajude alguém!
(OBS: esse post foi escrito em no máximo 10 minutos)
meus links: https://thayto.com/linktree
_Photo by Karina Vorozheeva on Unsplash_
---
### TypeScript - Template Literal Types
Source: https://thayto.com/blog/typescript-template-literal-types
---
title: 'TypeScript - Template Literal Types'
publishedTime: '2023-07-07T07:30:51Z'
modifiedTime: '2024-07-07T21:08:51Z'
description: 'Template Literal Types é um bglh insano que expande as possibilidades do que já era possível com o string literals + unions do TS, dá uma olhada! Ele tem a mesma sintaxe do template literal string do JavaScript.'
image:
{
src: 'typescript-template-literal-types.png',
placeholder: 'typescript-template-literal-types-small.png',
type: 'image/png',
}
tags: ['typescript', 'utilities', 'types', 'learning']
href: '/blog/typescript-template-literal-types'
reactionsLength: 0
commentsLength: 0
---
## O que é Template Literal Types?
**Template Literal Types** é um bglh insano que expande as possibilidades do que já era possível com o `string literals + unions` do TS, dá uma olhada!
Ele tem a mesma sintaxe do template literal string do JavaScript.
```ts
type Tchau = 'tchau!'
type Salve = `Oi ${Tchau}`
```
Com ele é possivel usar sua necessidade + imaginação pra fazer diversas coisas bacanas que vão agregar muito no seu projeto/type.
Um exemplo bacana seria padronizar que todas as propriedades extras que adicionarmos à um type, necessitem de ter o prefixo "data\_" e o suffixo "\_prop", assim conseguimos criar um objeto com um padrão que vai facilitar o consumo de leitura para sabermos quais as propriedades extras que foram enviadas.
Falar é fácil, mas cadê o exemplo? vamos começar criando um type EventData, ele é a nossa base para nosso objeto evento de evento.
```ts
type EventData = {
id: string
name: string
step: 'first_step' | 'second_step'
}
```
Ele já possui propriedades definidas, que não podem ser alteradas, mas agora precisamos enviar mais alguns campos relacionados aos fields que ele tem em cada step, poderiamos extender o type EventData e adicionar os campos, mas ao invés disso, bora usar o Template Literal Types!
```ts
type FormFields = {
name: string
age: number
}
type EventDataExtraProps = `field_${string & keyof T}`
// aqui vamos modificar um pouco o EventData
type EventData = {
id: string
name: string
step: 'first_step' | 'second_step'
} & Record, any>
const event: EventData = {
id: 'sextou?',
name: 'thayto',
step: 'first_step',
field_name: 'full_name',
field_age: 22,
}
```
Parece complexo, mas é bem simples, em projetos grandes / libs, com um único utilitário desses, conseguimos fazer mágica nos auto_completes e na padronização do envio de determinadas propriedades!
Espero que tenham aprendido algo, se não aprendeu, pelo menos leu até o final, tmj!
https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html

---
### Como abrir o Visual Studio Code (VSCode) dentro do GitHub
Source: https://thayto.com/blog/como-abrir-o-vscode-direto-do-github
---
title: 'Como abrir o Visual Studio Code (VSCode) dentro do GitHub'
publishedTime: '2022-11-05T15:16:36Z'
modifiedTime: '2024-07-07T20:43:36Z'
description: 'Todo dev já precisou em algum momento editar um arquivo dentro do GitHub e se deparou com essa tela de edição padrão do próprio GitHub'
image:
{
src: 'como-abrir-o-vscode-direto-do-github.png',
placeholder: 'como-abrir-o-vscode-direto-do-github-small.png',
type: 'image/png',
}
tags: ['github', 'tutorial', 'vscode']
href: '/blog/como-abrir-o-vscode-direto-do-github'
reactionsLength: 12
commentsLength: 0
---
## De forma rápida:
Basta apertar a tecla `.` dentro do seu repositório de preferência
> no final do post tem algumas outras maneiras de abrir o github.dev também!
## TL;DR
Todo dev já precisou em algum momento editar um arquivo dentro do GitHub e se deparou com essa tela de edição padrão do próprio GitHub:

No primeiro momento ela parece uma tela "OK" para fazermos uma edição rápida, mas quando precisamos pesquisar mais coisas dentro do repositório, essa tela não nos ajuda muito e é por isso que vou mostrar como abrir o Visual Studio Code(VSCode) direto do GitHub.
É bem simples, basta apertar a tecla `.` **(ponto)** do seu teclado e voilá, vai abrir magicamente um VSCode direto do seu navegador e dentro do seu repositório com quase todas as funcionalidades que o VSCode tem.


Agora você consegue fazer quantas pesquisas quiser, mexer em quantos arquivos forem necessários e também vai poder fazer commits, instalar extensões, mudar o tema, entre outras várias funcionalidades.
## Outras maneiras de abrir o VSCode direto do GitHub
Outras maneiras de abrir qualquer repo do GitHub no `github.dev` (VSCode do GitHub) são:
- Alterando a URL de `github.com` para `github.dev`
- Apertando a tecla `.` dentro de algum repositório
- Ao abrir um arquivo dentro de algum repositório, selecione o menu suspenso ▼ e clique em abrir com (open with) `github.dev`.

Essa foi a dica de hoje, espero ter ajudado, tmj! 😎
---
### Diferença entre os operadores ?, ?? e || no JavaScript / TypeScript
Source: https://thayto.com/blog/diferenca-entre-operadores-js-ts
---
title: 'Diferença entre os operadores ?, ?? e || no JavaScript / TypeScript'
publishedTime: '2022-10-31T19:34:48Z'
modifiedTime: '2024-07-11T19:34:53Z'
description: '? -> Optional Chaining Operator. Permite a leitura do valor de uma propriedade localizada internamente em uma cadeia de objetos conectados, sem que a validação de cada referência da cadeia seja expressivamente realizada.'
image:
{
src: 'diferenca-entre-operadores-js-ts.png',
placeholder: 'diferenca-entre-operadores-js-ts-small.png',
type: 'image/png',
}
tags: ['javascript', 'typescript', 'learning']
href: '/blog/diferenca-entre-operadores-js-ts'
reactionsLength: 0
commentsLength: 0
---
# Contexto
Acredito que todo dev já ficou em dúvida sobre as diferenças entre alguns operadores do JavaScript/TypeScript. Por isso fiz esse post simples e rápido sobre as diferenças entre os operadores ?, ?? e ||. Confira logo abaixo
## ? - Optional Chaining
`?` -> **Optional Chaining Operator**.
Permite a leitura do valor de uma propriedade localizada internamente em uma cadeia de objetos conectados, sem que a validação de cada referência da cadeia seja expressivamente realizada.
O operador `?.` funciona de maneira similar ao operador `.` de encadeamento, exceto que, ao invés de causar um erro se a referência é [nullish](https://developer.mozilla.org/en-US/docs/Glossary/Nullish) (`null` ou `undefined`), a expressão sofre um "curto-circuito" e retorna com um valor de `undefined`. Quando utilizado com uma chamada de função, retorna `undefined` se a função executada não existir.
Isso resulta em expressões mais curtas e simples ao acessar propriedades encadeadas quando a possibilidade de uma referência ser inexistente. Isso também pode auxiliar ao explorar o conteúdo de um objeto quando não existe garantia da existência de determinadas propriedades obrigatórias.
**Exemplo**
```js
const user = {
id: 13,
name: 'Thayto',
}
console.log(user?.name) // John
console.log(user?.fullName) // undefined, aplicação não vai quebrar.
console.log(user.fullName) // TypeError: Cannot read property ‘fullName’ of undefined, aplicação quebra.
```
## ?? - Nullish Coalesing
`??` -> **Nullish Coalescing Operator**.
É um operador lógico que retorna o seu operando do lado direito quando o seu operador do lado esquerdo é `null` ou `undefined`. Caso contrário, ele retorna o seu operando do lado esquerdo.
**Exemplo**
```js
console.log(13 ?? 'não encontrado') // 13
console.log(0 ?? 'não encontrado') // 0
console.log('Dri' ?? 'não encontrado') // "Dri"
console.log('' ?? 'não encontrado') // ""
console.log(true ?? 'não encontrado') // true
console.log(false ?? 'não encontrado') // false
console.log(undefined ?? 'não encontrado') // "não encontrado"
console.log(null ?? 'não encontrado') // "não encontrado"
```
## || - Logical OR
`||` é o **Logical OR Operator**
A expressão Logical OR é avaliada da esquerda para a direita, é testada para possível avaliação de "curto-circuito" usando a seguinte regra:
`(alguma truthy expression) || expr` é avaliado em curto-circuito para a expressão verdadeira.
Curto-circuito significa que a parte `expr` acima não é avaliada, portanto, quaisquer efeitos colaterais de fazê-lo não têm efeito (por exemplo, se `expr` é uma chamada de função, a chamada nunca ocorre). Isso acontece porque o valor do operador já é determinado após a avaliação do primeiro operando.
**Exemplo**
```js
console.log(13 || 'não encontrado') // 13
console.log(0 || 'não encontrado') // "não encontrado"
console.log('Dri' || 'não encontrado') // "Dri"
console.log('' || 'não encontrado') // "não encontrado"
console.log(true || 'não encontrado') // true
console.log(false || 'não encontrado') // "não encontrado"
console.log(undefined || 'não encontrado') // "não encontrado"
console.log(null || 'não encontrado') // "não encontrado"
```
---
### Turbinando seu git bash (Windows) adicionando aliases (como se fosse o git plugin do zsh)
Source: https://thayto.com/blog/turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh
---
title: 'Turbinando seu git bash (Windows) adicionando aliases (como se fosse o git plugin do zsh)'
publishedTime: '2022-10-23T18:55:46Z'
modifiedTime: '2022-10-23T18:55:46Z'
description: 'Nesse guia simples vou mostrar como turbinar o seu git bash com aliases que vão facilitar e agilizar muito na hora de fazer seus commits, pulls, pegarem logs, trocarem de branch, rebases, merges, etc..'
image:
{
src: 'turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh.jpg',
placeholder: 'turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh-small.jpg',
type: 'image/jpeg',
}
tags: ['git', 'bash', 'tutorial', 'windows']
href: '/blog/turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh'
reactionsLength: 0
commentsLength: 0
---
Nesse guia simples vou mostrar como turbinar o seu git bash com aliases que vão facilitar e agilizar muito na hora de fazer seus commits, pulls, pegarem logs, trocarem de branch, rebases, merges, etc..
> Primeiro pra quem não conhece, o famoso plugin de git do zsh é esse: [zsh git plugin](https://github.com/ohmyzsh/ohmyzsh/blob/master/plugins/git/git.plugin.zsh)
Bom o primeiro passo para adicionar esses aliases é você ter o [git bash](https://git-scm.com/download/win) instalado.
E para adicionar os aliases é bem simples basta acessar a pasta onde estão os profiles do git bash (lembrando que esse guia é somente para **Windows**), que vai estar no seguinte caminho: `C:\Program Files\Git\etc\profile.d`

Depois você vai procurar o arquivo `aliases.sh` e abrir no seu editor de texto preferido (pode até ser o notepad) e adicionar as seguintes linhas:
```bash
alias g=git
alias ga='git add'
alias gaa='git add --all'
alias gam='git am'
alias gama='git am --abort'
alias gamc='git am --continue'
alias gams='git am --skip'
alias gamscp='git am --show-current-patch'
alias gap='git apply'
alias gapa='git add --patch'
alias gapt='git apply --3way'
alias gau='git add --update'
alias gav='git add --verbose'
alias gb='git branch'
alias gbD='git branch -D'
alias gba='git branch -a'
alias gbd='git branch -d'
alias gbda='git branch --no-color --merged | command grep -vE "^([+*]|\s*($(git_main_branch)|$(git_develop_branch))\s*$)" | command xargs git branch -d 2>/dev/null'
alias gbl='git blame -b -w'
alias gbnm='git branch --no-merged'
alias gbr='git branch --remote'
alias gbs='git bisect'
alias gbsb='git bisect bad'
alias gbsg='git bisect good'
alias gbsr='git bisect reset'
alias gbss='git bisect start'
alias gc='git commit -v'
alias 'gc!'='git commit -v --amend'
alias gca='git commit -v -a'
alias 'gca!'='git commit -v -a --amend'
alias gcam='git commit -a -m'
alias 'gcan!'='git commit -v -a --no-edit --amend'
alias 'gcans!'='git commit -v -a -s --no-edit --amend'
alias gcas='git commit -a -s'
alias gcasm='git commit -a -s -m'
alias gcb='git checkout -b'
alias gcd='git checkout $(git_develop_branch)'
alias gcf='git config --list'
alias gcl='git clone --recurse-submodules'
alias gclean='git clean -id'
alias gcm='git checkout $(git_main_branch)'
alias gcmsg='git commit -m'
alias 'gcn!'='git commit -v --no-edit --amend'
alias gco='git checkout'
alias gcor='git checkout --recurse-submodules'
alias gcount='git shortlog -sn'
alias gcp='git cherry-pick'
alias gcpa='git cherry-pick --abort'
alias gcpc='git cherry-pick --continue'
alias gcs='git commit -S'
alias gcsm='git commit -s -m'
alias gcss='git commit -S -s'
alias gcssm='git commit -S -s -m'
alias gd='git diff'
alias gdca='git diff --cached'
alias gdct='git describe --tags $(git rev-list --tags --max-count=1)'
alias gdcw='git diff --cached --word-diff'
alias gds='git diff --staged'
alias gdt='git diff-tree --no-commit-id --name-only -r'
alias gdup='git diff @{upstream}'
alias gdw='git diff --word-diff'
alias gf='git fetch'
alias gfa='git fetch --all --prune --jobs=10'
alias gfg='git ls-files | grep'
alias gfo='git fetch origin'
alias gg='git gui citool'
alias gga='git gui citool --amend'
alias ggpull='git pull origin "$(git_current_branch)"'
alias ggpur=ggu
alias ggpush='git push origin "$(git_current_branch)"'
alias ggsup='git branch --set-upstream-to=origin/$(git_current_branch)'
alias ghh='git help'
alias gignore='git update-index --assume-unchanged'
alias gignored='git ls-files -v | grep "^[[:lower:]]"'
alias git-svn-dcommit-push='git svn dcommit && git push github $(git_main_branch):svntrunk'
alias gk='\gitk --all --branches &!'
alias gke='\gitk --all $(git log -g --pretty=%h) &!'
alias gl='git pull'
alias glg='git log --stat'
alias glgg='git log --graph'
alias glgga='git log --graph --decorate --all'
alias glgm='git log --graph --max-count=10'
alias glgp='git log --stat -p'
alias glo='git log --oneline --decorate'
alias globurl='noglob urlglobber '
alias glod='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset'\'
alias glods='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset'\'' --date=short'
alias glog='git log --oneline --decorate --graph'
alias gloga='git log --oneline --decorate --graph --all'
alias glol='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'\'
alias glola='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'\'' --all'
alias glols='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'\'' --stat'
alias glp=_git_log_prettily
alias gluc='git pull upstream $(git_current_branch)'
alias glum='git pull upstream $(git_main_branch)'
alias gm='git merge'
alias gma='git merge --abort'
alias gmom='git merge origin/$(git_main_branch)'
alias gmtl='git mergetool --no-prompt'
alias gmtlvim='git mergetool --no-prompt --tool=vimdiff'
alias gmum='git merge upstream/$(git_main_branch)'
alias gp='git push'
alias gpd='git push --dry-run'
alias gpf='git push --force-with-lease'
alias 'gpf!'='git push --force'
alias gpoat='git push origin --all && git push origin --tags'
alias gpr='git pull --rebase'
alias gpristine='git reset --hard && git clean -dffx'
alias gpsup='git push --set-upstream origin $(git_current_branch)'
alias gpu='git push upstream'
alias gpv='git push -v'
alias gr='git remote'
alias gra='git remote add'
alias grb='git rebase'
alias grba='git rebase --abort'
alias grbc='git rebase --continue'
alias grbd='git rebase $(git_develop_branch)'
alias grbi='git rebase -i'
alias grbm='git rebase $(git_main_branch)'
alias grbo='git rebase --onto'
alias grbom='git rebase origin/$(git_main_branch)'
alias grbs='git rebase --skip'
alias grep='grep --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn,.idea,.tox}'
alias grev='git revert'
alias grh='git reset'
alias grhh='git reset --hard'
alias grm='git rm'
alias grmc='git rm --cached'
alias grmv='git remote rename'
alias groh='git reset origin/$(git_current_branch) --hard'
alias grrm='git remote remove'
alias grs='git restore'
alias grset='git remote set-url'
alias grss='git restore --source'
alias grst='git restore --staged'
alias grt='cd "$(git rev-parse --show-toplevel || echo .)"'
alias gru='git reset --'
alias grup='git remote update'
alias grv='git remote -v'
alias gsb='git status -sb'
alias gsd='git svn dcommit'
alias gsh='git show'
alias gsi='git submodule init'
alias gsps='git show --pretty=short --show-signature'
alias gsr='git svn rebase'
alias gss='git status -s'
alias gst='git status'
alias gsta='git stash push'
alias gstaa='git stash apply'
alias gstall='git stash --all'
alias gstc='git stash clear'
alias gstd='git stash drop'
alias gstl='git stash list'
alias gstp='git stash pop'
alias gsts='git stash show --text'
alias gstu='gsta --include-untracked'
alias gsu='git submodule update'
alias gsw='git switch'
alias gswc='git switch -c'
alias gswd='git switch $(git_develop_branch)'
alias gswm='git switch $(git_main_branch)'
alias gtl='gtl(){ git tag --sort=-v:refname -n -l "${1}*" }; noglob gtl'
alias gts='git tag -s'
alias gtv='git tag | sort -V'
alias gunignore='git update-index --no-assume-unchanged'
alias gunwip='git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1'
alias gup='git pull --rebase'
alias gupa='git pull --rebase --autostash'
alias gupav='git pull --rebase --autostash -v'
alias gupom='git pull --rebase origin $(git_main_branch)'
alias gupomi='git pull --rebase=interactive origin $(git_main_branch)'
alias gupv='git pull --rebase -v'
alias gwch='git whatchanged -p --abbrev-commit --pretty=medium'
alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign -m "--wip-- [skip ci]"'
```
Pronto! Agora você pode ser mais feliz utilizando o git de forma mais ágil e escrevendo bem menos com esses aliases! :D
---
### Como configurar o deploy do Turborepo no Netlify
Source: https://thayto.com/blog/como-configurar-o-deploy-do-turborepo-no-netlify
---
title: 'Como configurar o deploy do Turborepo no Netlify'
publishedTime: '2022-06-21T15:14:48Z'
modifiedTime: '2022-10-25T23:50:06Z'
description: 'Um dia desses passei por uma dificuldade que foi fazer o deploy de uma aplicação minha utilizando Turborepo com Next.js e como acredito que mais pessoas possam ter esse problema, resolvi fazer um guia de como fazer as configurações iniciais, bora lá?'
image:
{
src: 'como-configurar-o-deploy-do-turborepo-no-netlify.png',
placeholder: 'como-configurar-o-deploy-do-turborepo-no-netlify-small.png',
type: 'image/png',
}
tags: ['turborepo', 'netlify', 'tutorial', 'react', 'next.js']
href: '/blog/como-configurar-o-deploy-do-turborepo-no-netlify'
reactionsLength: 0
commentsLength: 0
---
Um dia desses passei por uma dificuldade que foi fazer o deploy de uma aplicação minha utilizando Turborepo com Next.js e como acredito que mais pessoas possam ter esse problema, resolvi fazer um guia de como fazer as configurações iniciais, bora lá?
## Setup / Configurações iniciais
Bom primeiro vamos começar com o básico mesmo, criar uma aplicação utilizando o Turborepo, que é bem simples, basta você executar esse comando abaixo no terminal :)
```bash
npx create-turbo@latest
```
E aí provavelmente vai aparecer algo do tipo:
```bash
Need to install the following packages:
create-turbo@1.2.16
Ok to proceed? (y)
```
Basta você apertar `enter ⏎` ou `y` que ele vai baixar essa dependência pra você poder criar o projeto de uma forma bem mais simples. Logo após vai algo parecido com isso:
```bash
>>> TURBOREPO
>>> Welcome to Turborepo! Let's get you set up with a new codebase.
? Where would you like to create your turborepo? (./my-turborepo)
```
E nesse caso eu apertei `enter ⏎` pra ele usar esse nome padrão mesmo. Depois ele vai pedir pra você utilizar o package manager de sua preferência:
```bash
? Which package manager do you want to use? (Use arrow keys)
❯ npm
pnpm
yarn
```
Eu escolhi o `npm` mesmo pra facilitar a vida de vocês :D
Após tudo isso provavelmente na tela de vocês vai ter algo assim:
```bash
>>> TURBOREPO
>>> Welcome to Turborepo! Let's get you set up with a new codebase.
? Where would you like to create your turborepo? ./my-turborepo
? Which package manager do you want to use? npm
>>> Creating a new turborepo with the following:
- apps/web: Next.js with TypeScript
- apps/docs: Next.js with TypeScript
- packages/ui: Shared React component library
- packages/eslint-config-custom: Shared configuration (ESLint)
- packages/tsconfig: Shared TypeScript `tsconfig.json`
> Installing dependencies...
```
E por fim vai estar tudo instalado lindamente e a gente vai poder ir pra parte que interessa. 😎.
Vamos abrir a pasta com nosso editor de código preferido (no meu caso é o VSCode) e quando a gente abrir a gente vai ter algo parecido com isso na estrutura de pastas:

## Criando arquivo de configuração do Netlify
Após verificar que está tudo certo, vamos criar um arquivo chamado `netlify.toml` dentro do `./apps/web`

E dentro do `netlify.toml` vamos colocar o seguinte código:
```toml
[build]
command = "cd ../.. && npm install && npm run build"
publish = ".next"
[[plugins]]
package = "@netlify/plugin-nextjs"
```
Tá, mas pra que isso?
Bom, isso é basicamente o arquivo de configuração que o Netlify olha antes de fazer o deployment.
O `[build]` é a etapa que o Netlify olha para saber como vai fazer o build
O `[[plugins]]` é a etapa que antes de fazer o build ele instala alguns plugins que vão facilitar o deployment internamente. No nosso caso é de extrema importância adicionar o plugin do `Next.js` para não termos nenhuma complicação na hora dele criar o cache interno e utilizar o `SSR` e `Edge Functions` do Next.
Após isso configurado a gente vai fazer um commit no nosso repo para que a gente possa subir em um repo no GitHub e fazer o deploy em si. Nesse commit abaixo reparem que estou utilizando uma convenção famosa para commits que é o [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/#specification) coloquem um comentário caso queiram que eu traga algo relacionado a padrões de commit :)
```bash
git add .
git commit -m "build(web): adding Netlify configuration file"
```
Já feito o commit agora precisamos criar um repo no GitHub para settarmos o remote e podermos dar push

Aqui eu criei o repo com o nome `netlify-turborepo-post` mas vocês podem dar o nome que preferirem.
Após isso vai abrir a tela do GitHub mostrando algo tipo assim

Vocês vão copiar a parte de baixo já que já temos um repo existente

E depois vocês vão colar no terminal do nosso projeto, rodar os comandos e voilá ✨, temos agora o nosso código dentro do GitHub

Bom... depois de ter criado e subido nosso código no GitHub, agora podemos ir pro Netlify fazer a última etapa 😁!
## Deployando site no Netlify
Abram a conta de vocês no Netlify, depois clickem no `Add new site`

Selecionem a opção `Import an existent project`

Selecionem o provider do GitHub

Pesquisem o nome que deram ao projeto de vocês

Depois coloquem essas configurações no **Basic build settings**

Aí é só clicar em deploy e aguardar 😎...
Após alguns minutos o site de vocês já vai estar deployado no Netlify lindamente 😁🎆.
Porém ele vai ter essa cara feia aqui, masssssss... aí pra alterar isso é por conta de vocês!

Link do deploy: https://thayto-netlify-turborepo-post.netlify.app/
Link do repositório no GitHub: https://github.com/rafa-thayto/netlify-turborepo-post
---
### Como 'settar' a versão default do Node usando nvm
Source: https://thayto.com/blog/como-settar-a-versao-default-do-node-usando-nvm
---
title: "Como 'settar' a versão default do Node usando nvm"
publishedTime: '2022-06-19T18:52:06Z'
modifiedTime: '2022-10-25T23:52:06Z'
description: 'Pra quem ainda não conhece, o `nvm` é um excelente utilitário pra quando estamos querendo trocar a versão do node com agilidade sem precisar desinstalar a atual e instalar a desejada.'
image:
{
src: 'como-settar-a-versao-default-do-node-usando-nvm.png',
placeholder: 'como-settar-a-versao-default-do-node-usando-nvm-small.png',
type: 'image/png',
}
tags: ['node', 'nvm', 'tutorial']
href: '/blog/como-settar-a-versao-default-do-node-usando-nvm'
reactionsLength: 0
commentsLength: 0
---
Pra quem ainda não conhece, o `nvm` é um excelente utilitário pra quando estamos querendo trocar a versão do node com agilidade sem precisar desinstalar a atual e instalar a desejada.
Por um bom tempo eu utilizei o comando:
```bash
nvm use
```
Para alternar a versão do node pra uma mais recente, até que uns dias atrás descobri como alterar de forma bem simples a versão default do nvm.
Basta utilizar o seguinte comando alterando o trecho `` pela versão que você deseja manter como a padrão, por ex `16.5.0`:
```bash
nvm alias default
```
E pronto, agora você vai estar sempre utilizando essa versão do nvm em qualquer momento ou terminal que você abrir 😁.
---
## Blog Posts (English)
### Quick Guide to Make Claude Code File Suggestion Faster
Source: https://thayto.com/en/blog/claude-code-faster-file-suggestion
---
title: 'Quick Guide to Make Claude Code File Suggestion Faster'
publishedTime: '2026-01-08T12:00:00Z'
modifiedTime: '2026-01-08T12:00:00Z'
description: 'Learn how to improve Claude Code file suggestion with fzf for proper fuzzy matching, symlink support, and better performance.'
image:
{
src: 'claude-code-faster-file-suggestion.jpg',
placeholder: 'claude-code-faster-file-suggestion-small.jpg',
type: 'image/jpeg',
}
tags: ['claude-code', 'cli', 'fzf', 'productivity', 'tutorial']
href: '/blog/claude-code-faster-file-suggestion'
reactionsLength: 0
commentsLength: 0
---
The default `@` file matcher in Claude Code was always disappointing me, being used to superior options like fzf.
It was also not suggesting files from gitignored or symlinked folders, which was annoying as hell.
But Anthropic recently allowed us to customize it with File Suggestion settings.
And oh boy! Proper fuzzy matching via fzf is so much better than what was there by default!
## Prerequisites
You'll need these CLI tools installed:
- **rg (ripgrep)** - for fast file listing with symlink support
- **fzf** - for fuzzy matching
- **jq** - for parsing JSON input
## Setup
### 1. Configure Claude Code Settings
Add this to your `~/.claude/settings.json`:
```json
"fileSuggestion": {
"type": "command",
"command": "~/.claude/file-suggestion.sh"
}
```
### 2. Create the File Suggestion Script
Create `~/.claude/file-suggestion.sh` with the following content:
```bash
#!/bin/bash
# Custom file suggestion script for Claude Code
# Uses rg + fzf for fuzzy matching and symlink support
# Parse JSON input to get query
QUERY=$(jq -r '.query // ""')
# Use project dir from env, fallback to pwd
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
# cd into project dir so rg outputs relative paths
cd "$PROJECT_DIR" || exit 1
{
# Main search - respects .gitignore, includes hidden files, follows symlinks
rg --files --follow --hidden . 2>/dev/null
# Additional paths - include even if gitignored (uncomment and customize)
# [ -e .notes ] && rg --files --follow --hidden --no-ignore-vcs .notes 2>/dev/null
} | sort -u | fzf --filter "$QUERY" | head -15
```
### 3. Make it Executable
Don't forget to make the script executable:
```bash
chmod +x ~/.claude/file-suggestion.sh
```
### 4. Restart Claude Code
Restart Claude Code and enjoy!
Be happy :)
---
### Micro Frontends with Next.js Multi Zones
Source: https://thayto.com/en/blog/microfrontends-next-js-multi-zones
---
title: 'Micro Frontends with Next.js Multi Zones'
publishedTime: '2024-10-01T16:09:33Z'
modifiedTime: '2024-10-03T16:09:33Z'
description: "When we're developing a Web application and it ends up scaling, we usually need a team. When that application scales even more, we need more teams working on the same application."
image:
{
src: 'microfrontends-next-js-multi-zones.jpg',
placeholder: 'microfrontends-next-js-multi-zones-small.jpg',
type: 'image/jpeg',
}
tags: ['microfrontends', 'nextjs', 'tutorial', 'react']
href: '/blog/microfrontends-next-js-multi-zones'
reactionsLength: 0
commentsLength: 0
---
## Introduction
When we're developing a Web application and it ends up scaling, we usually need a team. When that application scales even more, we need more teams working on the same application.
Why am I talking about this?
Because usually when we have many people changing the same project, we can have several problems. Whether it's many _Pull Requests_, differences in scopes, distinct business rules, _merge_ conflicts and even differences of opinion.
When this happens what we usually think about is separating a piece of it into another project and creating the famous Micro Frontend that will speed up our deliveries and ensure the project evolves faster and independently of other scopes.
Which makes development much easier!
With that, the _Next.js_ team created an advanced feature called [**Multi Zones**](https://nextjs.org/docs/advanced-features/multi-zones), with it we can create several Micro Frontends very quickly and simply using _**Next.js**_
## Prerequisites
Before continuing to read this article, I assume you have basic knowledge / familiarity with **_Next.js_**
## What We're Going to Do
By the end of this article we'll make 2 apps with Next.js, combine them using the **Multi Zones** feature. I'll also make a part 2 showing how to deploy the 2 applications on Vercel.
## Creating the Project Folder
Open your terminal/cmd and run the following command:
```bash
mkdir nextjs-multi-zones-post
cd nextjs-multi-zones-post
```
Right after open that same folder in your preferred editor! (back then it was VSCode 💩, nowadays it's Neovim/VIM ❤️)
## Creating the Projects
After entering the folder that will centralize our projects, it's time to create them!
### First Application - Home
Open your terminal there and write the following command to create the first project which will be our **HOME**:
```bash
npx create-next-app --ts home
cd home
```
After creating the home, let's change the port that the project will run on to make our lives easier and have a standard until the end of the post
Open the `package.json` file inside your home and change the dev script from:
```json
...
"scripts": {
"dev": "next dev",
...
},
...
```
to:
```json
...
"scripts": {
"dev": "next dev -p 4444",
...
},
...
```
Open your terminal in the same folder and run the following command to execute the application:
```
npm run dev
```
### Second Application - Blog
Open another terminal and run the following command to create our second project which will be our **BLOG**:
```bash
npx create-next-app --ts blog
cd blog
```
We'll follow the same procedure we did for home now with the blog
Open the `package.json` file inside your blog and change the dev script from:
```json
...
"scripts": {
"dev": "next dev",
...
},
...
```
to:
```json
...
"scripts": {
"dev": "next dev -p 7777",
...
},
...
```
Open your terminal in the same folder and run the following command to execute the application:
```
npm run dev
```
Done, now we have the 2 applications running and the result should be something like this:

**Home (Application 1)** running on port **http://localhost:4444** and the **Blog (Application 2)** running on port **http://localhost:7777**
## Configuring Home (Application 1)
The first project we're going to develop and configure will be Home which besides being the base project will also be our Home. It's in it where we'll configure the URLs that we'll [rewrite](https://nextjs.org/docs/api-reference/next.config.js/rewrites) so that the Micro Frontend and Multi Zones work.
Open the `next.config.js` file and add the following lines of code:
```js
const { BLOG_URL } = process.env
const nextConfig = {
async rewrites() {
return [
{
source: '/:path*',
destination: `/:path*`,
},
{
source: '/blog',
destination: `${BLOG_URL}/blog`,
},
{
source: '/blog/:path*',
destination: `${BLOG_URL}/blog/:path*`,
},
]
},
}
```
In the `rewrites` part it's basically a rewrite, we'll rewrite the `/blog` routes and everything that comes after, like `/blog/posts/hello-world`. To learn more about rewrites just access the official **Next.js** documentation.
And you can see that we also added a constant using destructuring on the `process.env` object to get the blog `URL` via environment variables.
Now let's create the `.env` file at the root of our `home` project as shown in the example below.

It's in it where we'll put the `BLOG_URL` pointing to `http://localhost:7777` which is where our blog project is running.
`.env`
```txt
BLOG_URL=http://localhost:7777
```
Now inside our home project we'll transform the `index.tsx` into this:
```tsx
import type { NextPage } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import styles from '../styles/Home.module.css'
const Home: NextPage = () => {
return (
)
}
export default Home
```
Basically we added 3 links, 2 of them to pages of our blog (not yet built) and 1 link to redirect to an internal page of ours which is _About Us_.

Now let's create the `about.tsx` file inside `home/pages/about.tsx`:

`about.tsx`
```tsx
import type { NextPage } from 'next'
import Link from 'next/link'
const About: NextPage = () => {
return (
)
}
export default About
```
Here we created a very simple about us page that just has some text and a link that takes us back home.
And so we finish the **Home** part. Now let's go to Blog!
## Configuring Blog (Application 2)
Now we'll configure the blog. In the blog it'll be a bit simpler, basically we'll open the `next.config.js` file and add the `basePath` property inside `nextConfig`, it will tell next that its base _URL_ will start at the address we choose, which in this case will be `/blog`
`next.config.js`
```js
const nextConfig = {
basePath: '/blog',
}
module.exports = nextConfig
```
> Remember that every time we change the **next.config.js** file or add something to **.env** we need to stop the server and start it again 😁
Now inside our blog project we'll transform the `index.tsx` into this:
```tsx
import type { NextPage } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import styles from '../styles/Home.module.css'
const Blog: NextPage = () => {
return (
)
}
export default Blog
```
At the root of our blog we have 1 link that leads to our **Home** and 2 links that lead us to posts in our blog

In the image above you can already see the magic happening, if you look at the URL you'll notice we're running on **http://localhost:4444/blog**, but why does this happen?
When we configured the `basePath` inside the **Blog** project's `next.config.js`, we tell next that `index.tsx` and all other files will always be accessed from our `basePath` which in this case is `/blog`.
We should also remember that in our **Home** project's `next.config.js` we configured that whenever we're on **http://localhost:4444** and access `/blog` or anything after blog, we'll be doing a route rewrite and pointing to our **Blog** via **Home**.
> In other words: http://localhost:4444/blog will point to http://localhost:7777/blog
The most amazing thing about all this is that we can access our other application (blog) inside our application (home) **without changing the URL** 🤯, isn't that impressive?
_Cover Image: Photo by Andrey Tikhonovskiy on Unsplash_
---
### Zero Downtime Deployment with Docker Compose in an OCI VPS using GitHub Actions
Source: https://thayto.com/en/blog/zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions
---
title: 'Zero Downtime Deployment with Docker Compose in an OCI VPS using GitHub Actions'
publishedTime: '2024-09-13T21:16:36Z'
modifiedTime: '2024-09-13T21:16:36Z'
description: 'First, you must have a Linux VPS (Ill use Ubuntu 22 in this tutorial). Tagged with docker, devops, github actions, linux, tutorial.'
image:
{
src: 'zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions.jpg',
placeholder: 'zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions-small.jpg',
type: 'image/jpeg',
}
tags: ['docker', 'devops', 'github actions', 'linux', 'tutorial']
href: '/blog/zero-downtime-deployment-with-docker-compose-in-an-oci-vps-using-github-actions'
reactionsLength: 0
commentsLength: 0
---
First, you must have a Linux VPS (I'll use Ubuntu 22 in this tutorial).
## Requirements
- Docker
- Docker Compose
- [Docker Rollout Plugin](https://github.com/Wowu/docker-rollout?tab=readme-ov-file#installation)
### Installing Docker Rollout Plugin
It's very simple:
```bash
# Create directory for Docker cli plugins
mkdir -p ~/.docker/cli-plugins
# Download docker-rollout script to Docker cli plugins directory
curl https://raw.githubusercontent.com/wowu/docker-rollout/master/docker-rollout -o ~/.docker/cli-plugins/docker-rollout
# Make the script executable
chmod +x ~/.docker/cli-plugins/docker-rollout
```
### Docker Rollout Usage
Run `docker rollout ` instead of `docker compose up -d ` to update a service without downtime.
```bash
$ docker rollout -f docker-compose.yml
```
## GitHub Actions build_and_deploy.yml workflow
> In this case I'm using a private registry on Digital Ocean.
```yaml
name: CI
# 1
# Controls when the workflow will run
on:
# Triggers the workflow on push events but only for the master branch
push:
branches: [main]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
inputs:
version:
description: 'Image version'
required: true
#2
env:
REGISTRY: 'registry.digitalocean.com/YOUR_REGISTRY_NAME'
IMAGE_NAME: 'YOUR_IMAGE_NAME'
#3
jobs:
build_and_push:
runs-on: ubuntu-latest
steps:
- name: Checkout the repo
uses: actions/checkout@v4
- name: Build container image
run: docker build -t $(echo $REGISTRY)/$(echo $IMAGE_NAME):$(echo $GITHUB_SHA | head -c7) .
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Log in to DigitalOcean Container Registry with short-lived credentials
run: doctl registry login --expiry-seconds 600
- name: Remove all old images
run: if [ ! -z "$(doctl registry repository list | grep "$(echo $IMAGE_NAME)")" ]; then doctl registry repository delete-manifest $(echo $IMAGE_NAME) $(doctl registry repository list-tags $(echo $IMAGE_NAME) | grep -o "sha.*") --force; else echo "No repository"; fi
- name: Push image to DigitalOcean Container Registry
run: docker push $(echo $REGISTRY)/$(echo $IMAGE_NAME):$(echo $GITHUB_SHA | head -c7)
deploy:
runs-on: ubuntu-latest
needs: build_and_push
steps:
- name: Deploy to Digital Ocean droplet via SSH action
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.OCI_HOST }}
username: ${{ secrets.OCI_USERNAME }}
key: ${{ secrets.OCI_SSH_KEY }}
envs: IMAGE_NAME,REGISTRY,{{ secrets.DIGITALOCEAN_ACCESS_TOKEN }},GITHUB_SHA
script: |
whoami
cd ~/app
pwd
ls -la
# Login to registry
docker login -u ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} -p ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} registry.digitalocean.com
# Update the APP image in docker-compose.yml
sed -i '0,/image:/s|image: .*|image: '$(echo $REGISTRY)'/'$(echo $IMAGE_NAME)':'$(echo $GITHUB_SHA | head -c7)'|' docker-compose.yml
# Pull the latest image
docker compose pull
# Here is the magic docker plugin
docker rollout -f docker-compose.yml app
echo "Deployed with success to production"
```
## Conclusion
I hope this tutorial helps you in some way,
best regards Rafael Thayto.
_Photo by Bernd 📷 Dittrich on Unsplash_
---
### Exposing Your Localhost with Ngrok (Very Useful for Testing Webhooks)
Source: https://thayto.com/en/blog/expondo-seu-localhost-com-ngrok
---
title: 'Exposing Your Localhost with Ngrok (Very Useful for Testing Webhooks)'
publishedTime: '2024-07-06T15:58:51Z'
modifiedTime: '2024-07-06T15:58:51Z'
description: 'I needed to test some webhooks, but only knew one way which would be to deploy the app and only then be able to test the webhooks. This method works and is widely used by devs. But it has a problem... every test you need to deploy your application again and that takes quite some time.'
image:
{
src: 'expondo-seu-localhost-com-ngrok.jpg',
placeholder: 'expondo-seu-localhost-com-ngrok-small.jpg',
type: 'image/jpeg',
}
tags: ['ngrok', 'webhooks', 'tutorial']
href: '/blog/expondo-seu-localhost-com-ngrok'
reactionsLength: 0
commentsLength: 0
---
> The "it works on my machine" problems are over!
## Problem
I needed to test some webhooks, but only knew one way which would be to deploy the app and only then be able to test the webhooks. This method works and is widely used by devs. But it has a problem... every test you need to deploy your application again and that takes quite some time.
Searching around I found [Ngrok](https://ngrok.com/) and with it we can expose our localhost in a very simple way.
## Installation
> you can also follow the [Official Documentation](https://ngrok.com/docs/guides/getting-started/#step-2-install-the-ngrok-agent).
### Mac
Use [Homebrew](https://brew.sh/):
```bash
brew install ngrok/ngrok/ngrok
```
### Linux
Use apt
```bash
curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | \
sudo gpg --dearmor -o /etc/apt/keyrings/ngrok.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/ngrok.gpg] https://ngrok-agent.s3.amazonaws.com buster main" | \
sudo tee /etc/apt/sources.list.d/ngrok.list && \
sudo apt update && sudo apt install ngrok
```
### Windows
Use [Chocolatey](https://chocolatey.org/install)
```bash
choco install ngrok
```
## Connect Your Agent to Your Ngrok Account
To do this, you need to [log in or sign up](https://dashboard.ngrok.com/) on Ngrok and get your Authtoken.
Copy the token and add it to your terminal
```bash
ngrok config add-authtoken
```
## Run Ngrok
Start Ngrok by running the command below (you can choose the port you prefer, but in the example I used port `8000`):
```bash
ngrok http 8000
```
Thanks for reading this far! Hope this post helps you :)
Check out more at https://thayto.com/links
_Cover Image: Photo by Stepan Kalinin on Unsplash_
---
### TypeScript - How to Extract a String from Your Literal Types
Source: https://thayto.com/en/blog/ts-como-pegar-string-no-seu-literal-types
---
title: 'TypeScript - How to Extract a String from Your Literal Types'
publishedTime: '2023-07-24T15:58:51Z'
modifiedTime: '2024-07-07T21:33:51Z'
description: "I won't beat around the bush. Basically just use TypeScript's Extract Utility Type and that's it!"
image:
{
src: 'ts-como-pegar-string-no-seu-literal-types.jpg',
placeholder: 'ts-como-pegar-string-no-seu-literal-types-small.jpg',
type: 'image/jpeg',
}
tags: ['typescript', 'utilities', 'types', 'tutorial']
href: '/blog/ts-como-pegar-string-no-seu-literal-types'
reactionsLength: 0
commentsLength: 0
---
Hey there, senior devs.
I won't beat around the bush. Basically just use **TypeScript**'s _Utility Type_ `Extract` and that's it! _**For example:**_
```ts
type CatNames = 'Garfield' | 'Yoru' | 'Yuki' | 'Fluffy' | 'Lady' | 'Lucky'
type MyCatNames = Extract
// |-> Extract these two `literal types` from CatNames `literal type`
type Cat = {
age: number
name: CatNames
}
function getMyCat(age: number, name: MyCatNames): Cat {
// |--> only show 'Yoru' and
// 'Yuki'
return {
age,
name,
} as Cat
}
const myCat1 = getMyCat(1, 'Yoru')
const myCat2 = getMyCat(1, 'Yuki')
const otherCat: Cat = {
age: 3,
name: 'Garfield',
}
const otherCatWithMyCatName: Cat = {
age: 5,
name: 'Yoru',
}
// cheers!
```
> [TS Playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAwghsAcnAthAzlAvFA5AcTgCcAzASwgBsATXKAHzwE0B7IgVzsdyfYGsyXPADFK7EiRBDcAGTjUpDPDPYBjPlIBQm0JCgBZEPCSoM2KAFEAHsCJxVwADzHkadABpmbTkp79BAHyaUCGhYeERkVEA9NEMALQBljZ2DlDAABYY0MAA7ixQAAaUZMAQdpTp4BiFUCRELCiwCK5mxaXlcJW6EIXaPc3A5gDewVBwAOYQAFxQAHbsKABG5e5jc6azLqbomgC+2iTscw5kLHNQU8CGxgAUkzPziytEnhtoszctOwCUWwhQUZRYEgsKxBKJKDnSggKDoDIsXJeDh0OBzahQMag7ERcE4kJ+AS4MZECDAdhEC5A0IPNZhd4QOlQPbjTDGfbaVTndBDFBGBAARnMVy+wFuAs8PG8uB+mi5cx5UD5xgATMKyaLxZLeETZXLuUMWJlysZ-kMcNSQg9ZgBmJkhBmzAjEchUWgc+WKo1ZIjGADqpQyotaZpGWPGU1mAFZ7fNNsjOPsgA) link
hope this helps someone!
(NOTE: this post was written in 10 minutes max)
my links: https://thayto.com/linktree
_Photo by Karina Vorozheeva on Unsplash_
---
### TypeScript - Template Literal Types
Source: https://thayto.com/en/blog/typescript-template-literal-types
---
title: 'TypeScript - Template Literal Types'
publishedTime: '2023-07-07T07:30:51Z'
modifiedTime: '2024-07-07T21:08:51Z'
description: 'Template Literal Types is really cool and expands the possibilities of what was already possible with string literals + unions in TS, check it out! It has the same syntax as JavaScript template literal strings.'
image:
{
src: 'typescript-template-literal-types.png',
placeholder: 'typescript-template-literal-types-small.png',
type: 'image/png',
}
tags: ['typescript', 'utilities', 'types', 'learning']
href: '/blog/typescript-template-literal-types'
reactionsLength: 0
commentsLength: 0
---
## What is Template Literal Types?
**Template Literal Types** is really cool and expands the possibilities of what was already possible with `string literals + unions` in TS, check it out!
It has the same syntax as JavaScript template literal strings.
```ts
type Goodbye = 'goodbye!'
type Greeting = `Hi ${Goodbye}`
```
With it, you can use your needs + imagination to do several cool things that will add a lot to your project/type.
A nice example would be to standardize that all extra properties we add to a type need to have the prefix "data\_" and the suffix "\_prop", so we can create an object with a pattern that will make it easier to read and know which extra properties were sent.
Talk is cheap, but where's the example? Let's start by creating an EventData type, it's our base for our event object.
```ts
type EventData = {
id: string
name: string
step: 'first_step' | 'second_step'
}
```
It already has defined properties that cannot be changed, but now we need to send some more fields related to the fields it has in each step. We could extend the EventData type and add the fields, but instead, let's use Template Literal Types!
```ts
type FormFields = {
name: string
age: number
}
type EventDataExtraProps = `field_${string & keyof T}`
// here we'll modify EventData a bit
type EventData = {
id: string
name: string
step: 'first_step' | 'second_step'
} & Record, any>
const event: EventData = {
id: 'sextou?',
name: 'thayto',
step: 'first_step',
field_name: 'full_name',
field_age: 22,
}
```
It seems complex, but it's quite simple. In large projects / libs, with a single utility like this, we can work magic on auto_completes and standardize sending certain properties!
Hope you learned something, if not, at least you read until the end, cheers!
https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html

---
### How to Open Visual Studio Code (VSCode) Inside GitHub
Source: https://thayto.com/en/blog/como-abrir-o-vscode-direto-do-github
---
title: 'How to Open Visual Studio Code (VSCode) Inside GitHub'
publishedTime: '2022-11-05T15:16:36Z'
modifiedTime: '2024-07-07T20:43:36Z'
description: 'Every developer at some point has needed to edit a file inside GitHub and encountered this standard GitHub editing screen'
image:
{
src: 'como-abrir-o-vscode-direto-do-github.png',
placeholder: 'como-abrir-o-vscode-direto-do-github-small.png',
type: 'image/png',
}
tags: ['github', 'tutorial', 'vscode']
href: '/blog/como-abrir-o-vscode-direto-do-github'
reactionsLength: 12
commentsLength: 0
---
## Quick way:
Just press the `.` key inside your repository of choice
> at the end of the post there are some other ways to open github.dev too!
## TL;DR
Every developer at some point has needed to edit a file inside GitHub and encountered this standard GitHub editing screen:

At first it seems like an "OK" screen for making a quick edit, but when we need to search for more things inside the repository, this screen doesn't help us much and that's why I'm going to show you how to open Visual Studio Code (VSCode) directly from GitHub.
It's pretty simple, just press the `.` **(period)** key on your keyboard and voila, it will magically open a VSCode directly in your browser and inside your repository with almost all the features that VSCode has.


Now you can do as many searches as you want, work on as many files as necessary, and you'll also be able to make commits, install extensions, change the theme, among many other features.
## Other Ways to Open VSCode Directly from GitHub
Other ways to open any GitHub repo in `github.dev` (GitHub's VSCode) are:
- Changing the URL from `github.com` to `github.dev`
- Pressing the `.` key inside any repository
- When opening a file inside any repository, select the dropdown menu ▼ and click on open with `github.dev`.

That was today's tip, hope it helped, cheers! 😎
---
### Difference Between the ?, ?? and || Operators in JavaScript / TypeScript
Source: https://thayto.com/en/blog/diferenca-entre-operadores-js-ts
---
title: 'Difference Between the ?, ?? and || Operators in JavaScript / TypeScript'
publishedTime: '2022-10-31T19:34:48Z'
modifiedTime: '2024-07-11T19:34:53Z'
description: '? -> Optional Chaining Operator. Allows reading the value of a property located internally in a chain of connected objects without having to explicitly validate each reference in the chain.'
image:
{
src: 'diferenca-entre-operadores-js-ts.png',
placeholder: 'diferenca-entre-operadores-js-ts-small.png',
type: 'image/png',
}
tags: ['javascript', 'typescript', 'learning']
href: '/blog/diferenca-entre-operadores-js-ts'
reactionsLength: 0
commentsLength: 0
---
# Context
I believe every developer has had doubts about the differences between some JavaScript/TypeScript operators. That's why I made this quick and simple post about the differences between the ?, ?? and || operators. Check it out below
## ? - Optional Chaining
`?` -> **Optional Chaining Operator**.
Allows reading the value of a property located internally in a chain of connected objects without having to explicitly validate each reference in the chain.
The `?.` operator works similarly to the `.` chaining operator, except that instead of causing an error if a reference is [nullish](https://developer.mozilla.org/en-US/docs/Glossary/Nullish) (`null` or `undefined`), the expression short-circuits and returns with a value of `undefined`. When used with a function call, it returns `undefined` if the executed function does not exist.
This results in shorter and simpler expressions when accessing chained properties when there's a possibility of a reference being non-existent. This can also help when exploring the content of an object when there's no guarantee of certain required properties existing.
**Example**
```js
const user = {
id: 13,
name: 'Thayto',
}
console.log(user?.name) // John
console.log(user?.fullName) // undefined, application won't break.
console.log(user.fullName) // TypeError: Cannot read property 'fullName' of undefined, application breaks.
```
## ?? - Nullish Coalescing
`??` -> **Nullish Coalescing Operator**.
Is a logical operator that returns its right-hand side operand when its left-hand side operand is `null` or `undefined`. Otherwise, it returns its left-hand side operand.
**Example**
```js
console.log(13 ?? 'not found') // 13
console.log(0 ?? 'not found') // 0
console.log('Dri' ?? 'not found') // "Dri"
console.log('' ?? 'not found') // ""
console.log(true ?? 'not found') // true
console.log(false ?? 'not found') // false
console.log(undefined ?? 'not found') // "not found"
console.log(null ?? 'not found') // "not found"
```
## || - Logical OR
`||` is the **Logical OR Operator**
The Logical OR expression is evaluated from left to right, it is tested for possible "short-circuit" evaluation using the following rule:
`(some truthy expression) || expr` is short-circuit evaluated to the truthy expression.
Short-circuit means that the `expr` part above is not evaluated, therefore any side effects of doing so do not take effect (for example, if `expr` is a function call, the call never occurs). This happens because the value of the operator is already determined after evaluation of the first operand.
**Example**
```js
console.log(13 || 'not found') // 13
console.log(0 || 'not found') // "not found"
console.log('Dri' || 'not found') // "Dri"
console.log('' || 'not found') // "not found"
console.log(true || 'not found') // true
console.log(false || 'not found') // "not found"
console.log(undefined || 'not found') // "not found"
console.log(null || 'not found') // "not found"
```
---
### Supercharging Your Git Bash (Windows) by Adding Aliases (Like the zsh git plugin)
Source: https://thayto.com/en/blog/turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh
---
title: 'Supercharging Your Git Bash (Windows) by Adding Aliases (Like the zsh git plugin)'
publishedTime: '2022-10-23T18:55:46Z'
modifiedTime: '2022-10-23T18:55:46Z'
description: "In this simple guide I'll show you how to supercharge your git bash with aliases that will make it much easier and faster when making your commits, pulls, getting logs, switching branches, rebases, merges, etc."
image:
{
src: 'turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh.jpg',
placeholder: 'turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh-small.jpg',
type: 'image/jpeg',
}
tags: ['git', 'bash', 'tutorial', 'windows']
href: '/blog/turbinando-seu-git-bash-windows-adicionando-aliases-como-se-fosse-o-git-plugin-do-zsh'
reactionsLength: 0
commentsLength: 0
---
In this simple guide I'll show you how to supercharge your git bash with aliases that will make it much easier and faster when making your commits, pulls, getting logs, switching branches, rebases, merges, etc..
> First, for those who don't know, the famous zsh git plugin is this one: [zsh git plugin](https://github.com/ohmyzsh/ohmyzsh/blob/master/plugins/git/git.plugin.zsh)
Well, the first step to add these aliases is to have [git bash](https://git-scm.com/download/win) installed.
And to add the aliases is quite simple, just access the folder where the git bash profiles are (remembering that this guide is only for **Windows**), which will be at the following path: `C:\Program Files\Git\etc\profile.d`

Then you'll look for the `aliases.sh` file and open it in your preferred text editor (can even be notepad) and add the following lines:
```bash
alias g=git
alias ga='git add'
alias gaa='git add --all'
alias gam='git am'
alias gama='git am --abort'
alias gamc='git am --continue'
alias gams='git am --skip'
alias gamscp='git am --show-current-patch'
alias gap='git apply'
alias gapa='git add --patch'
alias gapt='git apply --3way'
alias gau='git add --update'
alias gav='git add --verbose'
alias gb='git branch'
alias gbD='git branch -D'
alias gba='git branch -a'
alias gbd='git branch -d'
alias gbda='git branch --no-color --merged | command grep -vE "^([+*]|\s*($(git_main_branch)|$(git_develop_branch))\s*$)" | command xargs git branch -d 2>/dev/null'
alias gbl='git blame -b -w'
alias gbnm='git branch --no-merged'
alias gbr='git branch --remote'
alias gbs='git bisect'
alias gbsb='git bisect bad'
alias gbsg='git bisect good'
alias gbsr='git bisect reset'
alias gbss='git bisect start'
alias gc='git commit -v'
alias 'gc!'='git commit -v --amend'
alias gca='git commit -v -a'
alias 'gca!'='git commit -v -a --amend'
alias gcam='git commit -a -m'
alias 'gcan!'='git commit -v -a --no-edit --amend'
alias 'gcans!'='git commit -v -a -s --no-edit --amend'
alias gcas='git commit -a -s'
alias gcasm='git commit -a -s -m'
alias gcb='git checkout -b'
alias gcd='git checkout $(git_develop_branch)'
alias gcf='git config --list'
alias gcl='git clone --recurse-submodules'
alias gclean='git clean -id'
alias gcm='git checkout $(git_main_branch)'
alias gcmsg='git commit -m'
alias 'gcn!'='git commit -v --no-edit --amend'
alias gco='git checkout'
alias gcor='git checkout --recurse-submodules'
alias gcount='git shortlog -sn'
alias gcp='git cherry-pick'
alias gcpa='git cherry-pick --abort'
alias gcpc='git cherry-pick --continue'
alias gcs='git commit -S'
alias gcsm='git commit -s -m'
alias gcss='git commit -S -s'
alias gcssm='git commit -S -s -m'
alias gd='git diff'
alias gdca='git diff --cached'
alias gdct='git describe --tags $(git rev-list --tags --max-count=1)'
alias gdcw='git diff --cached --word-diff'
alias gds='git diff --staged'
alias gdt='git diff-tree --no-commit-id --name-only -r'
alias gdup='git diff @{upstream}'
alias gdw='git diff --word-diff'
alias gf='git fetch'
alias gfa='git fetch --all --prune --jobs=10'
alias gfg='git ls-files | grep'
alias gfo='git fetch origin'
alias gg='git gui citool'
alias gga='git gui citool --amend'
alias ggpull='git pull origin "$(git_current_branch)"'
alias ggpur=ggu
alias ggpush='git push origin "$(git_current_branch)"'
alias ggsup='git branch --set-upstream-to=origin/$(git_current_branch)'
alias ghh='git help'
alias gignore='git update-index --assume-unchanged'
alias gignored='git ls-files -v | grep "^[[:lower:]]"'
alias git-svn-dcommit-push='git svn dcommit && git push github $(git_main_branch):svntrunk'
alias gk='\gitk --all --branches &!'
alias gke='\gitk --all $(git log -g --pretty=%h) &!'
alias gl='git pull'
alias glg='git log --stat'
alias glgg='git log --graph'
alias glgga='git log --graph --decorate --all'
alias glgm='git log --graph --max-count=10'
alias glgp='git log --stat -p'
alias glo='git log --oneline --decorate'
alias globurl='noglob urlglobber '
alias glod='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset'\'
alias glods='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset'\'' --date=short'
alias glog='git log --oneline --decorate --graph'
alias gloga='git log --oneline --decorate --graph --all'
alias glol='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'\'
alias glola='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'\'' --all'
alias glols='git log --graph --pretty='\''%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'\'' --stat'
alias glp=_git_log_prettily
alias gluc='git pull upstream $(git_current_branch)'
alias glum='git pull upstream $(git_main_branch)'
alias gm='git merge'
alias gma='git merge --abort'
alias gmom='git merge origin/$(git_main_branch)'
alias gmtl='git mergetool --no-prompt'
alias gmtlvim='git mergetool --no-prompt --tool=vimdiff'
alias gmum='git merge upstream/$(git_main_branch)'
alias gp='git push'
alias gpd='git push --dry-run'
alias gpf='git push --force-with-lease'
alias 'gpf!'='git push --force'
alias gpoat='git push origin --all && git push origin --tags'
alias gpr='git pull --rebase'
alias gpristine='git reset --hard && git clean -dffx'
alias gpsup='git push --set-upstream origin $(git_current_branch)'
alias gpu='git push upstream'
alias gpv='git push -v'
alias gr='git remote'
alias gra='git remote add'
alias grb='git rebase'
alias grba='git rebase --abort'
alias grbc='git rebase --continue'
alias grbd='git rebase $(git_develop_branch)'
alias grbi='git rebase -i'
alias grbm='git rebase $(git_main_branch)'
alias grbo='git rebase --onto'
alias grbom='git rebase origin/$(git_main_branch)'
alias grbs='git rebase --skip'
alias grep='grep --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn,.idea,.tox}'
alias grev='git revert'
alias grh='git reset'
alias grhh='git reset --hard'
alias grm='git rm'
alias grmc='git rm --cached'
alias grmv='git remote rename'
alias groh='git reset origin/$(git_current_branch) --hard'
alias grrm='git remote remove'
alias grs='git restore'
alias grset='git remote set-url'
alias grss='git restore --source'
alias grst='git restore --staged'
alias grt='cd "$(git rev-parse --show-toplevel || echo .)"'
alias gru='git reset --'
alias grup='git remote update'
alias grv='git remote -v'
alias gsb='git status -sb'
alias gsd='git svn dcommit'
alias gsh='git show'
alias gsi='git submodule init'
alias gsps='git show --pretty=short --show-signature'
alias gsr='git svn rebase'
alias gss='git status -s'
alias gst='git status'
alias gsta='git stash push'
alias gstaa='git stash apply'
alias gstall='git stash --all'
alias gstc='git stash clear'
alias gstd='git stash drop'
alias gstl='git stash list'
alias gstp='git stash pop'
alias gsts='git stash show --text'
alias gstu='gsta --include-untracked'
alias gsu='git submodule update'
alias gsw='git switch'
alias gswc='git switch -c'
alias gswd='git switch $(git_develop_branch)'
alias gswm='git switch $(git_main_branch)'
alias gtl='gtl(){ git tag --sort=-v:refname -n -l "${1}*" }; noglob gtl'
alias gts='git tag -s'
alias gtv='git tag | sort -V'
alias gunignore='git update-index --no-assume-unchanged'
alias gunwip='git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1'
alias gup='git pull --rebase'
alias gupa='git pull --rebase --autostash'
alias gupav='git pull --rebase --autostash -v'
alias gupom='git pull --rebase origin $(git_main_branch)'
alias gupomi='git pull --rebase=interactive origin $(git_main_branch)'
alias gupv='git pull --rebase -v'
alias gwch='git whatchanged -p --abbrev-commit --pretty=medium'
alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign -m "--wip-- [skip ci]"'
```
Done! Now you can be happier using git more quickly and writing much less with these aliases! :D
---
### How to Configure Turborepo Deployment on Netlify
Source: https://thayto.com/en/blog/como-configurar-o-deploy-do-turborepo-no-netlify
---
title: 'How to Configure Turborepo Deployment on Netlify'
publishedTime: '2022-06-21T15:14:48Z'
modifiedTime: '2022-10-25T23:50:06Z'
description: "The other day I faced a challenge deploying one of my applications using Turborepo with Next.js and since I believe more people might have this problem, I decided to make a guide on how to do the initial configurations, let's go?"
image:
{
src: 'como-configurar-o-deploy-do-turborepo-no-netlify.png',
placeholder: 'como-configurar-o-deploy-do-turborepo-no-netlify-small.png',
type: 'image/png',
}
tags: ['turborepo', 'netlify', 'tutorial', 'react', 'next.js']
href: '/blog/como-configurar-o-deploy-do-turborepo-no-netlify'
reactionsLength: 0
commentsLength: 0
---
The other day I faced a challenge deploying one of my applications using Turborepo with Next.js and since I believe more people might have this problem, I decided to make a guide on how to do the initial configurations, let's go?
## Setup / Initial Configurations
Well first let's start with the basics, create an application using Turborepo, which is quite simple, just execute this command below in the terminal :)
```bash
npx create-turbo@latest
```
And then something like this will probably appear:
```bash
Need to install the following packages:
create-turbo@1.2.16
Ok to proceed? (y)
```
Just press `enter ⏎` or `y` and it will download this dependency so you can create the project in a much simpler way. Right after you'll see something like this:
```bash
>>> TURBOREPO
>>> Welcome to Turborepo! Let's get you set up with a new codebase.
? Where would you like to create your turborepo? (./my-turborepo)
```
And in this case I pressed `enter ⏎` to use the default name. Then it will ask you to use your preferred package manager:
```bash
? Which package manager do you want to use? (Use arrow keys)
❯ npm
pnpm
yarn
```
I chose `npm` to make things easier for you :D
After all this you'll probably have something like this on your screen:
```bash
>>> TURBOREPO
>>> Welcome to Turborepo! Let's get you set up with a new codebase.
? Where would you like to create your turborepo? ./my-turborepo
? Which package manager do you want to use? npm
>>> Creating a new turborepo with the following:
- apps/web: Next.js with TypeScript
- apps/docs: Next.js with TypeScript
- packages/ui: Shared React component library
- packages/eslint-config-custom: Shared configuration (ESLint)
- packages/tsconfig: Shared TypeScript `tsconfig.json`
> Installing dependencies...
```
And finally everything will be beautifully installed and we can move on to the interesting part. 😎.
Let's open the folder with our preferred code editor (in my case it's VSCode) and when we open it we'll have something like this in the folder structure:

## Creating Netlify Configuration File
After verifying that everything is correct, let's create a file called `netlify.toml` inside `./apps/web`

And inside `netlify.toml` we'll put the following code:
```toml
[build]
command = "cd ../.. && npm install && npm run build"
publish = ".next"
[[plugins]]
package = "@netlify/plugin-nextjs"
```
Okay, but what's this for?
Well, this is basically the configuration file that Netlify looks at before deploying.
The `[build]` is the step that Netlify looks at to know how to build
The `[[plugins]]` is the step where before building it installs some plugins that will make deployment easier internally. In our case it's extremely important to add the `Next.js` plugin to avoid any complications when it creates the internal cache and uses Next's `SSR` and `Edge Functions`.
After this is configured we'll make a commit to our repo so we can push it to a GitHub repo and do the actual deployment. In the commit below notice that I'm using a famous convention for commits which is [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/#specification) leave a comment if you want me to bring something related to commit standards :)
```bash
git add .
git commit -m "build(web): adding Netlify configuration file"
```
Once the commit is done we now need to create a repo on GitHub to set the remote and be able to push

Here I created the repo with the name `netlify-turborepo-post` but you can give it whatever name you prefer.
After that the GitHub screen will open showing something like this

You'll copy the bottom part since we already have an existing repo

And then you'll paste it in our project's terminal, run the commands and voila ✨, we now have our code inside GitHub

Well... after creating and pushing our code to GitHub, we can now go to Netlify for the final step 😁!
## Deploying Site on Netlify
Open your Netlify account, then click on `Add new site`

Select the `Import an existent project` option

Select the GitHub provider

Search for the name you gave your project

Then put these settings in the **Basic build settings**

Then just click deploy and wait 😎...
After a few minutes your site will be beautifully deployed on Netlify 😁🎆.
However it will look ugly like this, buttttt... changing that is up to you!

Deploy link: https://thayto-netlify-turborepo-post.netlify.app/
GitHub repository link: https://github.com/rafa-thayto/netlify-turborepo-post
---
### How to Set the Default Node Version Using nvm
Source: https://thayto.com/en/blog/como-settar-a-versao-default-do-node-usando-nvm
---
title: 'How to Set the Default Node Version Using nvm'
publishedTime: '2022-06-19T18:52:06Z'
modifiedTime: '2022-10-25T23:52:06Z'
description: "For those who don't know yet, `nvm` is an excellent utility for when we want to switch Node versions quickly without having to uninstall the current one and install the desired one."
image:
{
src: 'como-settar-a-versao-default-do-node-usando-nvm.png',
placeholder: 'como-settar-a-versao-default-do-node-usando-nvm-small.png',
type: 'image/png',
}
tags: ['node', 'nvm', 'tutorial']
href: '/blog/como-settar-a-versao-default-do-node-usando-nvm'
reactionsLength: 0
commentsLength: 0
---
For those who don't know yet, `nvm` is an excellent utility for when we want to switch Node versions quickly without having to uninstall the current one and install the desired one.
For a long time I used the command:
```bash
nvm use
```
To switch the Node version to a newer one, until a few days ago I discovered how to change the nvm default version in a very simple way.
Just use the following command changing the `` part to the version you want to keep as default, for example `16.5.0`:
```bash
nvm alias default
```
And that's it, now you'll always be using this nvm version at any time or in any terminal you open 😁.
---
## Books
# Livros
> Minha pequena biblioteca.
## Lido
- Código Limpo - Robert C. Martin (★★★★★) ♥
- Arquitetura Limpa - Robert C. Martin
- Domain-Driven Design - Eric Evans
- The Pragmatic Programmer - Andrew Hunt, David Thomas (★★★★★) ♥
- Refatoração - Martin Fowler (★★★★☆)
- Design Patterns - Gang of Four
- Organize Sua Mente - Tiago Forte
- O Lado Difícil das Situações Difíceis - Ben Horowitz
- Data Science para Negócios - Foster Provost, Tom Fawcett
- O Poder do Hábito - Charles Duhigg
- A Coragem de Ser Imperfeito - Brené Brown
- A Regra é Não Ter Regras - Reed Hastings, Erin Meyer
- Lean Inception - Paulo Caroli
- Product Backlog Building - Fábio Aguiar, Paulo Caroli
- Gatilhos Mentais - Gustavo Ferreira
- Sócrates Café - Christopher Phillips
- Os Primeiros 90 Dias - Michael Watkins
- Receita Previsível - Aaron Ross, Marylou Tyler
- StoryBrand - Donald Miller
- Comunicação Não Violenta - Marshall B. Rosenberg
- Arrume a Sua Cama - William H. McRaven
- Meditações - Marco Aurélio
- As Leis da Simplicidade - John Maeda
- Ganbatte - Nobuo Suzuki
- Estruturas de Dados e Algoritmos com JavaScript - Loiane Groner
- Entendendo Algoritmos - Aditya Bhargava
- O Ato Criativo: Uma Forma de Ser - Rick Rubin
- System Design Interview - Alex Xu
- O Projeto Fênix - Gene Kim, Kevin Behr, George Spafford
- Cracking the Coding Interview - Gayle Laakmann McDowell
- 10 Cases do Design Brasileiro - Vol. 1 - Auresnede Pires Stephan
- 10 Cases do Design Brasileiro - Vol. 2 - Auresnede Pires Stephan
- 10 Cases do Design Brasileiro - Vol. 3 - Auresnede Pires Stephan
- System Design Interview – An Insider's Guide: Volume 2 - Alex Xu, Sahn Lam
---
# Books
> My own little library.
## Read
- Clean Code - Robert C. Martin (★★★★★) ♥
- Clean Architecture - Robert C. Martin
- Domain-Driven Design - Eric Evans
- The Pragmatic Programmer - Andrew Hunt, David Thomas (★★★★★) ♥
- Refactoring - Martin Fowler (★★★★☆)
- Design Patterns - Gang of Four
- Building a Second Brain - Tiago Forte
- The Hard Thing About Hard Things - Ben Horowitz
- Data Science for Business - Foster Provost, Tom Fawcett
- The Power of Habit - Charles Duhigg
- The Gifts of Imperfection - Brené Brown
- No Rules Rules - Reed Hastings, Erin Meyer
- Lean Inception - Paulo Caroli
- Product Backlog Building - Fábio Aguiar, Paulo Caroli
- Mental Triggers - Gustavo Ferreira
- Socrates Café - Christopher Phillips
- The First 90 Days - Michael Watkins
- Predictable Revenue - Aaron Ross, Marylou Tyler
- Building a StoryBrand - Donald Miller
- Nonviolent Communication - Marshall B. Rosenberg
- Make Your Bed - William H. McRaven
- Meditations - Marco Aurélio
- The Laws of Simplicity - John Maeda
- Ganbatte - Nobuo Suzuki
- Data Structures and Algorithms with JavaScript - Loiane Groner
- Grokking Algorithms - Aditya Bhargava
- The Creative Act: A Way of Being - Rick Rubin
- System Design Interview - Alex Xu
- The Phoenix Project - Gene Kim, Kevin Behr, George Spafford
- Cracking the Coding Interview - Gayle Laakmann McDowell
- 10 Cases of Brazilian Design - Vol. 1 - Auresnede Pires Stephan
- 10 Cases of Brazilian Design - Vol. 2 - Auresnede Pires Stephan
- 10 Cases of Brazilian Design - Vol. 3 - Auresnede Pires Stephan
- System Design Interview – An Insider's Guide: Volume 2 - Alex Xu, Sahn Lam
---
## About
# Sobre mim
Rafael Thayto é um desenvolvedor com mais de 7 anos de experiência, apaixonado por resolver problemas e aprender novas tecnologias e boas práticas de desenvolvimento. Atuei em diversos projetos, sempre me dedicando ao máximo para garantir a entrega de soluções eficientes e de alta qualidade.
Ele gosta bastante de jogar, conhecer pessoas e lugares novos. Posso ter certeza que se conversar com ele, em poucos minutos já terão criado um conexão.
---
# About me
Rafael Thayto is a developer with over 7 years of experience, passionate about solving problems and learning new technologies and good development practices. I have worked on several projects, always dedicating myself to the maximum to ensure the delivery of efficient and high quality solutions.
He really enjoys playing, meeting new people and places. I can be sure that if you talk to him, in a few minutes you will have already created a connection.
---
## Hobbies
# Hobbies
> Coisas que eu gosto de fazer fora do código.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
---
# Hobbies
> Things I like to do outside of code.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
---
## Linktree
# Rafael Thayto - Links
> Senior Software Engineer
- [lista de espera | linkedin](https://hub.la/r/lista-espera)
- [Discord - Tutorandus Community](https://discord.gg/JXxC4xTdDU)
- [Higlobe - USD 20$ pra você e pra mim](https://higlobe.com?grsf=rafael-xnn88r)
- [❤️ Neovim Configs](https://github.com/rafa-thayto/lazy-thayto-vim)
- [Newsletter - First Time Founder](https://thayto.substack.com/)
- [Blog](https://thayto.com/blog)
- [LinkedIn](https://www.linkedin.com/in/thayto/)
- [Youtube](https://www.youtube.com/@thayto_dev)
- [🎙️ DevSenior Cast](https://podcasters.spotify.com/pod/show/devseniorscast)
- [GitHub](https://github.com/rafa-thayto)
- [Instagram](https://www.instagram.com/thayto_dev/?utm_source=thayto.com)
- [X/Twitter](https://x.com/thayto_dev)
- [Bluesky](https://bsky.app/profile/thayto.dev)
- [Twitch](https://twitch.tv/thayto_dev)
- [Formação TS](https://hotm.art/hnWXd89A)
- [CRUD com qualidade](https://bit.ly/3nLnPQZ)
- [Estrutura de dados e algoritmos com JavaScript - Loiane](https://www.amazon.com.br/dp/8575226932?&_encoding=UTF8&tag=thayto-20&linkCode=ur2&linkId=a8887fab2c901ae25fb1855a72f0bc61&camp=1789&creative=9325)
- [Dev.to](https://dev.to/thayto/)
- [TabNews](https://www.tabnews.com.br/thayto)
---