npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@toobstudio/blog

v0.2.1

Published

SDK para consumir a API de blog do TOOB

Downloads

488

Readme

@toobstudio/blog

SDK oficial para consumir a API de blog do TOOB.

Instalação

npm install @toobstudio/blog

Configuração

Defina as variáveis de ambiente no seu projeto:

TOOB_API_KEY=sua_chave_aqui
TOOB_PROJECT_ID=seu_project_id

Você encontra essas informações no painel do TOOB, na seção Conexão API.

Uso

Inicialização

import { ToobBlog } from "@toobstudio/blog";

// Lê TOOB_API_KEY e TOOB_PROJECT_ID das variáveis de ambiente
const blog = new ToobBlog();

// Ou com configuração explícita
const blog = new ToobBlog({
  apiKey: "toob_xxx",
  projectId: "abc123",
});

Listar posts

const { posts, total, page, totalPages } = await blog.getPosts({
  page: 1,     // padrão: 1
  limit: 12,   // padrão: 12, máximo: 50
  tag: "tech", // opcional: filtrar por tag
});

Buscar post por slug

const post = await blog.getPost("meu-post-slug");
// Retorna null se o post não existir

Exemplo com Next.js App Router

// app/blog/page.tsx
import { ToobBlog } from "@toobstudio/blog";

const blog = new ToobBlog();

export default async function BlogPage() {
  const { posts } = await blog.getPosts();

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
// app/blog/[slug]/page.tsx
import { ToobBlog } from "@toobstudio/blog";
import { notFound } from "next/navigation";

const blog = new ToobBlog();

export default async function PostPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const post = await blog.getPost(slug);

  if (!post) notFound();

  return (
    <article>
      <h1>{post.title}</h1>
      <article className="toob-blog-content" dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

Estilos para o conteúdo do post

O conteúdo dos posts (post.content) é HTML gerado pelo editor TipTap. O SDK inclui um CSS pronto para estilizar esse conteúdo.

Importando o CSS

// No layout.tsx, _app.tsx ou arquivo global
import "@toobstudio/blog/styles.css";

Usando no HTML do post

Envolva o conteúdo do post com a classe toob-blog-content:

<article
  className="toob-blog-content"
  dangerouslySetInnerHTML={{ __html: post.content }}
/>

Customizando cores

O CSS usa CSS custom properties com valores padrão. Sobrescreva no seu CSS para adaptar ao seu tema:

.toob-blog-content {
  --toob-text: #1a1a1a;
  --toob-text-muted: #6b7280;
  --toob-bg: #ffffff;
  --toob-bg-muted: #f5f5f5;
  --toob-border: #e5e5e5;
  --toob-link: #f97316;
  --toob-link-hover: #ea580c;
  --toob-font-body: system-ui, -apple-system, sans-serif;
  --toob-font-display: system-ui, -apple-system, sans-serif;
  --toob-font-mono: ui-monospace, "SFMono-Regular", Menlo, monospace;
}

Sobre cache

O cache dos posts é gerenciado inteiramente no servidor do TOOB. Quando um post é criado, editado ou deletado no painel, o cache é invalidado automaticamente. Não é necessário implementar nenhuma estratégia de cache no lado do cliente — cada request bate no servidor TOOB que já serve do cache interno.

Referência da API

new ToobBlog(config?)

| Parâmetro | Tipo | Descrição | | -------------------- | -------- | ---------------------------------- | | config.apiKey | string | Chave da API (ou env TOOB_API_KEY) | | config.projectId | string | ID do projeto (ou env TOOB_PROJECT_ID) |

blog.getPosts(options?)

Retorna Promise<BlogPostList>.

| Opção | Tipo | Padrão | Descrição | | ------- | -------- | ------ | -------------------- | | page | number | 1 | Página | | limit | number | 12 | Itens por página (máx 50) | | tag | string | — | Filtrar por tag |

blog.getPost(slug)

Retorna Promise<BlogPost | null>. Retorna null se o post não for encontrado.

Tipos exportados

import type {
  BlogPost,
  BlogPostList,
  BlogPostListItem,
  GetPostsOptions,
  ToobBlogConfig,
} from "@toobstudio/blog";

Implementação com IA (Claude Code / Codex / Cursor)

Copie o prompt abaixo e cole no seu assistente de IA para implementar o blog automaticamente no seu projeto:

Implemente um blog completo no meu projeto usando o SDK @toobstudio/blog.

## Passo 1: Instalação
Instale o pacote:
npm install @toobstudio/blog

## Passo 2: Variáveis de ambiente
Adicione no .env (ou .env.local se for Next.js):
TOOB_API_KEY=<minha_chave>
TOOB_PROJECT_ID=<meu_project_id>

## Passo 3: Criar as páginas

### Página de listagem de posts (/blog)
- Use `ToobBlog` do `@toobstudio/blog`
- Instancie `const blog = new ToobBlog()` (lê as envs automaticamente)
- Chame `blog.getPosts({ page, limit: 12 })` para listar posts
- Renderize cards com: título, excerpt, coverImage, tags, publishedAt, authorName
- Implemente paginação usando `total`, `page` e `totalPages` da resposta
- Suporte filtro por tag via query string (ex: /blog?tag=tech)
- Use os dados de SEO do post (`post.seo.metaTitle`, `post.seo.metaDescription`) para gerar metadata da página

### Página individual do post (/blog/[slug])
- Chame `blog.getPost(slug)` para buscar o post
- Se retornar `null`, mostre 404 (no Next.js use `notFound()`)
- Renderize: título, coverImage, content (é HTML, use dangerouslySetInnerHTML ou equivalente), tags, authorName, publishedAt
- Use `post.seo` para gerar metadata/og tags da página
- Se `post.structuredData` existir, injete como JSON-LD no <head>
- Se `post.geo` existir:
  - Renderize `geo.faq` como seção de FAQ (accordion ou lista)
  - Renderize `geo.keyTakeaways` como lista de pontos-chave
  - Use `geo.aiSummary` como resumo no topo do post se disponível

## Tipos disponíveis no SDK (para referência)

interface BlogPostListItem {
  id: string;
  title: string;
  slug: string;
  excerpt: string;
  coverImage: string | null;
  tags: string[];
  authorName: string;
  publishedAt: string | null;
  createdAt: string;
  seo: {
    metaTitle: string | null;
    metaDescription: string | null;
    ogImageUrl: string | null;
  } | null;
  geo: {
    aiSummary: string | null;
    faq: Array<{ question: string; answer: string }>;
    keyTakeaways: string[];
    topicCategory: string | null;
    contentType: string | null;
    entities: string[];
  } | null;
}

interface BlogPost extends BlogPostListItem {
  content: string;       // HTML
  structuredData: unknown | null;  // JSON-LD
}

interface BlogPostList {
  posts: BlogPostListItem[];
  total: number;
  page: number;
  totalPages: number;
}

## Passo 4: Estilos do conteúdo
- Importe o CSS do SDK no layout ou arquivo global: `import "@toobstudio/blog/styles.css";`
- Envolva o `post.content` com a classe `toob-blog-content`:
  `<article className="toob-blog-content" dangerouslySetInnerHTML={{ __html: post.content }} />`
- O CSS já estiliza headings, listas, code blocks, blockquotes, tabelas, imagens, task lists, etc.
- Para customizar cores, sobrescreva as CSS variables (--toob-text, --toob-link, --toob-border, etc.) no CSS do projeto

## Regras importantes
- NÃO implemente cache — o servidor TOOB gerencia todo o cache
- NÃO use `next: { revalidate }` nem nenhuma estratégia de cache
- Cada chamada do SDK = 1 fetch direto para a API
- Use o sistema de estilização que já existe no projeto (Tailwind, CSS Modules, etc) para os COMPONENTES (cards, layout, paginação), mas use a classe `toob-blog-content` com o CSS do SDK para o conteúdo HTML do post
- Siga os padrões e convenções já existentes no projeto
- Adapte a estrutura de pastas ao framework usado (Next.js App Router, Pages Router, Astro, etc)
- Trate erros: importe `ToobAuthError` e `ToobRateLimitError` de `@toobstudio/blog` para erros específicos

Tratamento de erros

| Classe | Status | Mensagem | | ------------------- | ------ | ----------------------------------------------------------- | | ToobAuthError | 401 | API Key inválida. Verifique a variável TOOB_API_KEY. | | ToobRateLimitError| 429 | Limite de requisições excedido. Tente novamente em instantes.| | ToobApiError | outros | Erro na API TOOB: {status} {statusText} |

import { ToobAuthError, ToobRateLimitError, ToobApiError } from "@toobstudio/blog";

try {
  const posts = await blog.getPosts();
} catch (error) {
  if (error instanceof ToobAuthError) {
    // API key inválida
  }
}