refelt
v0.1.15
Published
Cel: minimalny kod w aplikacji końcowej (generator CRUD / backoffice). Ten plik jest zoptymalizowany pod LLM (krótko, deterministycznie, z gotowymi blokami).
Readme
Refelt — LLM Quick Guide
Cel: minimalny kod w aplikacji końcowej (generator CRUD / backoffice). Ten plik jest zoptymalizowany pod LLM (krótko, deterministycznie, z gotowymi blokami).
0. Słownik
- Refelt – host/DI na serwisy.
- DataService – jednolite CRUD (HTTP lub Supabase).
- QueryService – cache + staleTime + retry.
- MutationService – operacje zapisu + invalidacja cache.
- Resource plugin – cukier do CRUD modeli.
- Backoffice – fasada: składa wszystko i wystawia
defineModel().
1. Instalacja (copy-paste)
npm i refelt svelte
# (opcjonalnie) Supabase:
npm i @supabase/supabase-js2. Najkrótszy start z Supabase (copy-paste)
// app/main.ts
import { createClient } from '@supabase/supabase-js';
import { createBackoffice } from 'refelt';
const supabase = createClient(import.meta.env.VITE_SB_URL, import.meta.env.VITE_SB_ANON);
export const bo = createBackoffice({ supabase: { client: supabase, schema: 'public', idField: 'id' } });// app/models/users.ts
import { bo } from '../main';
export type User = { id: number; name: string; email: string };
export const Users = bo.defineModel<User, User, Pick<User,'name'|'email'>, Partial<User>>({
resource: 'users',
defaultList: { perPage: 20, sortBy: 'name', order: 'asc' }
});
// Użycie
const listQ = Users.list(); // Query<User[]>
const oneQ = Users.one(123); // Query<User>
const createM = Users.create(); // Mutation<User, {name; email}>
const updateM = Users.update(); // Mutation<User, {id; data}>
const deleteM = Users.remove(); // Mutation<void, {id}>3. HTTP zamiast Supabase (copy-paste)
import { createBackoffice } from 'refelt';
export const bo = createBackoffice({
http: {
baseURL: 'https://api.example.com',
getAuthHeaders: async () => ({ Authorization: 'Bearer TOKEN' })
}
});4. API (sygnatury — skrót)
// core
createRefelt({ services, apiVersion? }): Refelt
Refelt: getService<T>(name): T; registerService(name, svc); hasService(name): boolean;
onCleanup(cb); _runCleanups(); apiVersion: string
// data
createDataService({ baseURL, headers?, getAuthHeaders? }): DataService
createSupabaseDataService({ client, schema?, idField? }): DataService & { getCapability(name) }
DataService: kind; getList<T>(res, {page?, perPage?, sortBy?, order?, filter?}) -> {data:T[]; total}
getOne<T>(res, id) -> T; create<T>(res, row) -> T; update<T>(res, id, row) -> T; delete(res, id)
// query
createQueryService({ defaultStaleTime?, defaultRetry? }): QueryService
QueryService: createQuery<T>(key:string[], fn:()=>Promise<T>, {staleTime?}) -> Query<T>
invalidate(prefix?: string[]): void
Query<T>: subscribe; refetch()
// mutation
createMutationService(queryService): MutationService
MutationService: createMutation<TData, TVars>(fn, {onMutate?, onSuccess?, onError?, invalidateKeys?}) -> Mutation
Mutation: subscribe; mutate(vars); reset()
// resource plugin
ResourceService: defineResource(cfg) -> { list, one, create, update, remove, keys }
cfg: { resource; defaultList?; keyPrefix?; mapIn?; mapOut? }
// backoffice
createBackoffice({ supabase? | http?, query? }) -> Backoffice
Backoffice: defineModel(cfg) -> { list, one, create, update, remove, keys }; invalidate(prefix?)5. Wzorce użycia (copy-paste)
5.1 Subskrypcja Query (gołe Svelte store’y)
const q = Users.list({ perPage: 50 });
const unsub = q.subscribe(({ data, isLoading, isError, error }) => {
// render / logika
});5.2 Mutacja z invalidacją
const createUser = Users.create();
await createUser.mutate({ name: 'Ada', email: '[email protected]' });
// powiązane listy zostaną odświeżone (ustawione w pluginie resource)5.3 Ręczna invalidacja
import { bo } from '../main';
bo.invalidate(['res', 'users']); // oznacz wszystko pod prefiksem jako nieświeże5.4 Mapowania/validacja (np. z Zod – opcjonalnie)
import { z } from 'zod';
const CreateDTO = z.object({ name: z.string(), email: z.string().email() });
const Users = bo.defineModel({
resource: 'users',
mapOut: { create: (dto) => CreateDTO.parse(dto) }
});6. Capabilities (Supabase – opcjonalnie)
import type { DataService } from 'refelt';
const data = bo.refelt.getService<DataService>('data');
const withClient = data.getCapability?.<(<T>(fn:(client:any)=>Promise<T>)=>Promise<T>)>('supabase:withClient');
if (withClient) {
await withClient(async (client) => {
await client.from('public.audit').insert({ event: 'login' });
});
}7. Zasady edycji dla LLM (ważne)
- Nie zmieniaj publicznych nazw eksportów i ścieżek w
src/index.ts. - Nie mieszaj implementacji
DataService(jeden aktywny perRefelt). - Nie usuwaj
invalidateKeysz mutacji w pluginie resource. - Nie dodawaj zależności runtime poza
sveltei (opcjonalnie)@supabase/supabase-js. - Nie zmieniaj
apiVersionbez powodu (kompatybilność pluginów). - Nie wprowadzaj
require()(pakiet jest ESM).
8. Debug — szybkie checklisty
- Brak danych? Sprawdź
DataService.kindi parametry połączenia. - Cache się nie odświeża? Użyj
bo.invalidate(prefix)lub sprawdźstaleTime. - Supabase błąd? Upewnij się, że
schema/idFieldsą poprawne. - HTTP
getListbezX-Total-Count? Total policzy się z długości tablicy.
9. Licencja
MIT
