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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ministerjs/store

v2.0.4

Published

Gerenciamento de estado opinado para Vue 3 + Pinia com foco em simplicidade, tipagem forte e reutilização. Fornece factories para **ItemStore** (estado de um único objeto) e **TableStore** (coleções) além de um gerenciador com **cache inteligente** (`useS

Readme

@ministerjs/store

Gerenciamento de estado opinado para Vue 3 + Pinia com foco em simplicidade, tipagem forte e reutilização. Fornece factories para ItemStore (estado de um único objeto) e TableStore (coleções) além de um gerenciador com cache inteligente (useStores).

📦 Instalação

npm install @ministerjs/store
# ou
pnpm add @ministerjs/store
# ou
yarn add @ministerjs/store

🚀 Funcionalidades

  • ItemStore: Estado de um item único (perfil, configurações, sessão...)
  • TableStore: Coleções (listas, tabelas, catálogos) com utilidades frequentes
  • Cache inteligente via useStores para evitar recriações
  • Tipagem 100% (inferência de chaves, primary key, partial updates)
  • Pinia under the hood: integra DevTools sem esforço
  • Debug logging opcional (debug: true)
  • APIs mínimas e coesas: apenas o que é realmente usado no dia a dia

📖 Uso Básico

ItemStore – Gerenciando um item único

import { createItemStore } from "@ministerjs/store";

interface UserProfile {
  id: number;
  name: string;
  email: string;
  avatar?: string;
}

// Criando o store
const useUserProfile = createItemStore<UserProfile>({
  displayName: "User Profile",
  initialState: { name: "", email: "" },
  debug: true,
});

// Usando no componente Vue
const { get, set, update, clear } = useUserProfile();

// Estado reativo
const profile = get();
console.log(profile.value.name); // Acesso reativo

// Definindo dados completos
set({ id: 1, name: "João", email: "[email protected]" });

// Atualizando parcialmente
update({ name: "João Silva" });

// Limpando o estado
clear();

TableStore – Gerenciando coleções

import { createTableStore } from "@ministerjs/store";

interface User {
  id: number;
  name: string;
  email: string;
  active: boolean;
}

// Criando o store
const useUsersStore = createTableStore<User, "id">({
  primaryKey: "id",
  displayName: "Users Store",
  initialState: [],
  debug: true,
});

// Usando no componente Vue
const store = useUsersStore();

// Adicionando itens
store.add({ id: 1, name: "João", email: "[email protected]", active: true });
store.add({ id: 2, name: "Maria", email: "[email protected]", active: false });

// Buscando por ID
const user = store.get(1);

// Listando todos (reativo)
const allUsers = store.list();

// Busca por propriedade personalizada
const activeUser = store.getByProperty("email", "[email protected]");

// Atualizando
store.update(1, { name: "João Silva" });

// Removendo
store.remove(1);

// Substituindo toda a coleção
store.replaceAll([
  { id: 3, name: "Pedro", email: "[email protected]", active: true },
]);

// Lista computada com transformação
const activeUsers = store.computedList((users) =>
  users.value.filter((u) => u.active),
);

// Ordenação
const sortedUsers = store.sort((a, b) => a.name.localeCompare(b.name));

🏗️ Gerenciamento Avançado com useStores

O composable useStores centraliza criação e cache de múltiplos stores. Ele exige que você informe as factories padrão (createItemStore, createTableStore) uma única vez.

1. Uso Dinâmico (on-demand)

import {
  useStores,
  createItemStore,
  createTableStore,
} from "@ministerjs/store";

// Passamos `undefined` para o primeiro argumento (não há pré-configuração)
const { generateItem, generateTable, getCacheSize } = useStores(undefined, {
  createItemStore,
  createTableStore,
});

console.log(getCacheSize()); // { items: 0, tables: 0 }

// Cria e cacheia um ItemStore
const userProfile = generateItem<UserProfile>("profile", {
  debug: true,
  initialState: { name: "", email: "" },
});

// Cria e cacheia um TableStore (primaryKey padrão = "id")
const usersTable = generateTable<User>("users", {
  primaryKey: "id", // opcional; se omitido usa 'id'
  debug: true,
});

// Reutiliza do cache
const profileAgain = generateItem("profile"); // Missão cumprida: cache hit

2. Stores Pré-configurados

import {
  useStores,
  createItemStore,
  createTableStore,
} from "@ministerjs/store";

// Definições lazy (cada função só roda uma vez)
const stores = useStores(
  {
    users: () =>
      createTableStore<User>({ primaryKey: "id", displayName: "Users" }),
    profile: () =>
      createItemStore<UserProfile>({ displayName: "Profile", debug: true }),
    settings: () =>
      createItemStore<AppSettings>({
        displayName: "App Settings",
        initialState: { theme: "light", language: "pt-BR" },
      }),
  },
  {
    createItemStore,
    createTableStore,
  },
);

const userStore = stores.get("users"); // primeira chamada instancia
const userStoreAgain = stores.get("users"); // cache hit
console.log(stores.getCacheSize()); // { items: 2, tables: 1 } (exemplo)

3. Integração Rápida em uma App Vue

// main.ts
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";

const app = createApp(App);
app.use(createPinia());
app.mount("#app");

// Em qualquer composable
import {
  useStores,
  createItemStore,
  createTableStore,
} from "@ministerjs/store";
export const stores = useStores(undefined, {
  createItemStore,
  createTableStore,
});

🔧 API Reference

ItemStore Interface

interface ItemStore<T> {
  get(): Ref<Partial<T>>; // Estado reativo
  set(item: Partial<T>): void; // Define dados completos
  update(data: Partial<T>): void; // Atualização parcial
  clear(): void; // Limpa o estado
}

TableStore Interface

interface TableStore<T, PK> {
  add(data: T): void; // Adiciona item
  get(primaryKey: T[PK]): T | undefined; // Busca por ID
  list(): T[]; // Lista todos os itens
  computedList<R>(callback: (items: Ref<T[]>) => R): Ref<R>; // Lista computada
  getByProperty<K>(key: K, value: T[K]): T | undefined; // Busca por propriedade
  update(primaryKey: T[PK], data: Partial<T>): void; // Atualiza item
  remove(primaryKey: T[PK]): boolean; // Remove item
  replaceAll(data: T[]): void; // Substitui todos
  sort(callback: (a: T, b: T) => number): T[]; // Ordena itens
}

Opções de Configuração

interface CreateItemStoreOptions<T> {
  displayName?: string; // Nome para DevTools
  initialState?: T; // Estado inicial
  debug?: boolean; // Logs de debug
}

interface CreateTableStoreOptions<T, PK> {
  primaryKey?: PK; // Chave primária (default: 'id')
  displayName?: string; // Nome para DevTools
  initialState?: T[]; // Estado inicial
  debug?: boolean; // Logs de debug
}

### useStores

```typescript
// Sem stores pré-configurados
useStores(undefined, {
  createItemStore,
  createTableStore,
});

// Com stores pré-configurados
useStores({
  users: () => createTableStore<User>({ primaryKey: 'id' }),
  profile: () => createItemStore<UserProfile>({}),
}, {
  createItemStore,
  createTableStore,
});

Métodos retornados:

generateItem(key, options?) // Cria ou retorna ItemStore cacheado
generateTable(key, options?) // Cria ou retorna TableStore cacheado
get(key) // Quando configurado com objeto de setups
getCacheSize() // { items, tables }

## 🏆 Boas Práticas

### 1. Organização de Stores

```typescript
// stores/user.ts
export const useUserProfile = createItemStore<UserProfile>({
  displayName: "User Profile",
});

export const useUsers = createTableStore<User, "id">({
  primaryKey: "id",
  displayName: "Users",
});

// stores/index.ts
export const stores = useStores({
  userProfile: () => useUserProfile(),
  users: () => useUsers(),
});

2. Composables Especializados

// composables/useAuth.ts
export const useAuth = () => {
  const profile = stores.get("userProfile");

  const login = async (credentials: LoginData) => {
    const user = await authService.login(credentials);
    profile.set(user);
  };

  const logout = () => {
    profile.clear();
  };

  return { login, logout, profile: profile.get() };
};

3. Integração com APIs

// composables/useUsersApi.ts
export const useUsersApi = () => {
  const store = stores.get("users");

  const fetchUsers = async () => {
    const users = await api.get<User[]>("/users");
    store.replaceAll(users);
  };

  const createUser = async (userData: Omit<User, "id">) => {
    const user = await api.post<User>("/users", userData);
    store.add(user);
    return user;
  };

  return { fetchUsers, createUser, store };
};

🔗 Dependências & Peer Deps

Certifique-se de ter instalado (peer dependencies):

pnpm add vue pinia

Versões sugeridas:

  • Vue >= 3.5
  • Pinia >= 2.0
  • TypeScript >= 5

O pacote não inicializa o Pinia automaticamente; você ainda precisa chamar app.use(createPinia()) em sua aplicação.

🧪 Testes

Dentro do monorepo:

pnpm test --filter @ministerjs/store

⚠️ Notas & Gotchas

  • primaryKey em createTableStore é opcional (default "id").
  • generateItem e generateTable não recebem a factory como argumento (a factory é injetada uma vez em useStores).
  • computedList recebe um callback que recebe um Ref<T[]> e retorna um valor derivado reativo.
  • Evite mutar diretamente objetos retornados por get() / itens da lista fora de ações controladas se quiser padronizar logs.
  • O cache vive no escopo onde useStores foi chamado; para um cache global, exporte a instância.

📄 Licença

UNLICENSED – Uso interno do MinisterJS Framework.

🤝 Contribuindo

Este pacote faz parte do monorepo MinisterJS. Para contribuir:

  1. Clone o repositório principal
  2. Instale as dependências: pnpm install
  3. Execute os testes: pnpm test
  4. Faça suas alterações no pacote packages/store/
  5. Execute o build: pnpm build

Para mais informações, consulte o README principal do MinisterJS.