@estetica/ts-sdk
v0.1.1
Published
TypeScript SDK for the Estetica API
Readme
estetica-ts-sdk
TypeScript SDK for the Estetica API — a B2B aesthetic discovery engine. No runtime dependencies, works in any JS/TS runtime.
Installation
bun add @estetica/ts-sdkSetup
import { Estetica } from "@estetica/ts-sdk"
const client = Estetica({
baseUrl: "https://your-estetica-instance.com",
apiKey: "your-brand-api-key", // brand operations (items, queries)
adminSecret: "your-admin-secret", // admin operations (brands, categories, attributes)
})Queries
Execute an aesthetic query — the API translates the text into attribute weights via LLM, scores all ready items, and returns ranked results in a single synchronous call.
const result = await client.queries.execute({ query: "minimalist coastal aesthetic", limit: 20 })
// {
// id, query, categoryFilter,
// weights: [{ attribute: { slug, name }, weight, targetValue? }],
// results: [{ rank, score, item: { id, externalId, name, category, attributes, meta } }],
// meta: { provider, model, generatedAt }
// }
// Re-run a stored query against the current catalog
const stored = await client.queries.get(result.id)Items
// Submit for async LLM ingest — returns immediately with status: "pending"
const pending = await client.items.submit({ externalId: "sku-001", name: "Blue Shirt" })
// Poll until status is "ready" or "failed"
const item = await client.items.get("sku-001")
// List all items for the brand
const items = await client.items.list()
// Update name or meta
await client.items.update("sku-001", { name: "Navy Shirt", meta: { source: "shopify" } })
// Manually set or remove an attribute value
await client.items.setAttribute("sku-001", "color", "navy")
await client.items.removeAttribute("sku-001", "color")
// List extracted attribute values for an item
const attrs = await client.items.listAttributes("sku-001")
// Delete
await client.items.delete("sku-001")Brands (admin)
const brand = await client.brands.create({ slug: "acme", name: "Acme", type: "read_write" })
// apiKey is returned once only — store it immediately
await client.brands.list()
await client.brands.get("acme")
await client.brands.update("acme", { name: "Acme Corp" })
await client.brands.delete("acme")Brand type controls permissions: "read" | "write" | "read_write".
Categories (admin)
await client.categories.create({ name: "Tops" })
await client.categories.list()
await client.categories.get("tops")
await client.categories.update("tops", { name: "Tops & Shirts" })
// Link / unlink attributes to a category
await client.categories.linkAttribute("tops", "color")
await client.categories.listAttributes("tops")
await client.categories.unlinkAttribute("tops", "color")
await client.categories.delete("tops")Attributes (admin)
await client.attributes.create({ slug: "color", name: "Color", type: "enum", allowedValues: ["red", "blue"] })
await client.attributes.list()
await client.attributes.get("color")
await client.attributes.update("color", { allowedValues: ["red", "blue", "green"] })
await client.attributes.delete("color")Attribute type: "text" | "number" | "boolean" | "enum".
Error handling
Non-2xx responses throw an EsteticaError. Use the isEsteticaError type guard to narrow:
import { isEsteticaError } from "@estetica/ts-sdk"
try {
await client.items.get("missing")
} catch (e) {
if (isEsteticaError(e)) {
console.error(e.code) // "NOT_FOUND"
console.error(e.status) // 404
console.error(e.statusText) // "Not Found"
console.error(e.body) // parsed JSON or raw text from the server
}
}Error codes
| Code | HTTP | When |
|---|---|---|
| UNAUTHORIZED | 401 | Missing or invalid API key / admin secret |
| FORBIDDEN | 403 | Insufficient permissions for the operation |
| NOT_FOUND | 404 | Resource not found |
| CONFLICT | 409 | Slug or externalId already exists |
| VALIDATION_ERROR | 422 | Invalid request body |
| LLM_ERROR | 502 | LLM provider unavailable — safe to retry |
| INTERNAL_ERROR | 500 | Unexpected server error |
LLM_ERROR is the one worth building retry logic around — it means the upstream model provider had a transient failure.
TypeScript
The SDK ships its own types. No @types/ package needed.
import type {
Attribute, AttributeType,
Brand, BrandType, BrandWithKey,
Category,
ErrorCode, EsteticaError,
Item, ItemAttribute, ItemCategory, ItemIngestResult, ItemStatus,
Meta,
QueryResult, QueryResultItem, QueryWeight,
} from "@estetica/ts-sdk"Development
bun install
bun run build # emit dist/ (JS + .d.ts) via tsgo
bun run test # run tests
bun run typecheck # tsgo --noEmit
bun run format # biome format --write .
bun run lint # biome lint --write .
bun run check # biome check --write . (format + lint)
bun run ci # biome ci + typecheck + tests (read-only, used in CI)
bun run update-spec # pull latest openapi.json from killallservers/esteticaOpenAPI spec
openapi.json is committed to this repo and represents the API version this SDK was built against. To update:
bun run update-spec # requires gh auth with access to killallservers/esteticaReview the diff, update the SDK as needed, then commit openapi.json and code changes together.
