@unirate/svelte
v0.1.0
Published
Svelte store integration for the UniRate currency-exchange API. createUniRate() returns reactive readable stores — rate, conversion, currencies, vatRates — each carrying { data, error, loading } with a refresh(). Zero runtime deps.
Maintainers
Readme
@unirate/svelte
Plain Svelte store integration for the UniRate currency exchange API.
createUniRate() gives you reactive readable stores — rate, rates, conversion, currencies, vatRates — each carrying { data, error, loading } with a refresh() method. Works with Svelte 4 and Svelte 5. Zero runtime dependencies (native fetch + svelte/store).
Framework-agnostic: this is the plain-Svelte-stores package. If you're on SvelteKit and want server load helpers, a geo hook, and an API-route proxy, use
@unirate/sveltekitinstead.
Install
npm install @unirate/svelte svelteQuick start
# .env — get a free key at https://unirateapi.com
UNIRATE_API_KEY=your-api-key-here<script>
import { createUniRate } from '@unirate/svelte';
const uni = createUniRate({ apiKey: import.meta.env.VITE_UNIRATE_API_KEY });
const rate = uni.rate('USD', 'EUR');
const price = uni.conversion('USD', 'EUR', 99.99);
const codes = uni.currencies();
</script>
{#if $rate.loading}
Loading…
{:else if $rate.error}
{$rate.error.message}
{:else}
<p>1 USD = {$rate.data} EUR</p>
{/if}
<button on:click={rate.refresh}>Refresh</button>Never ship a real API key to the browser in production. Proxy UniRate through your own backend and point the client's
baseUrlat your proxy, or fetch on the server and pass values down.
API
createUniRate(options)
Builds one UniRateClient and returns store constructors bound to it.
const uni = createUniRate({
apiKey: 'your-key', // required
baseUrl?: string, // default https://api.unirateapi.com
fetch?: typeof fetch, // inject a custom fetch (e.g. SvelteKit's load fetch)
timeoutMs?: number, // default 30000
userAgent?: string,
});Returns:
| Member | Returns | Notes |
|---|---|---|
| uni.client | UniRateClient | The underlying imperative client. |
| uni.rate(from, to) | QueryStore<number> | Single exchange rate. |
| uni.rates(from) | QueryStore<Record<string, number>> | All rates for from. |
| uni.conversion(from, to, amount) | QueryStore<number> | amount of from in to. |
| uni.currencies() | QueryStore<string[]> | Supported currency codes. |
| uni.vatRates() | QueryStore<VATRatesAll> | All countries. |
| uni.vatRates(country) | QueryStore<VATRateOne> | One country (ISO-3166 alpha-2). |
QueryStore<T>
A Svelte readable of:
interface QueryState<T> {
data: T | undefined; // settled value, or undefined until first success
error: Error | undefined; // last error, or undefined while healthy
loading: boolean; // true until the first request settles; true again during refresh()
}plus:
store.refresh(); // abort any in-flight request and re-fetch (no-op with no subscribers)The request fires lazily on the first subscription and is torn down when the last subscriber leaves — the standard Svelte store lifecycle. An in-flight request is aborted whenever refresh() runs again or the store stops, so a stale response can never overwrite a newer one. During a refresh() the previously settled data stays put while loading flips to true.
Imperative client
Everything is also available directly on uni.client (or import UniRateClient and construct it yourself):
import { UniRateClient } from '@unirate/svelte/client';
const client = new UniRateClient({ apiKey: 'your-key' });
const rate = await client.getRate('USD', 'EUR'); // number
const map = await client.getRate('USD'); // Record<string, number>
const eur = await client.convert('EUR', 100, 'USD'); // number
const codes = await client.listCurrencies(); // string[]
const vat = await client.getVatRates('DE'); // { country, vat_data }Historical/timeseries methods exist for parity but require a UniRate Pro subscription and return 403 (ProRequiredError) on the free tier.
Error handling
Errors are mapped to typed subclasses of UniRateError, surfaced through store.error (or thrown by the client):
| HTTP | Error | |
|---|---|---|
| 400 | InvalidRequestError | Invalid request parameters |
| 401 | AuthenticationError | Missing or invalid API key |
| 403 | ProRequiredError | Endpoint requires a Pro subscription |
| 404 | InvalidCurrencyError | Currency not found or no data available |
| 429 | RateLimitError | Rate limit exceeded |
| 503 / other | UniRateError | carries .status and .body |
| network | UniRateError | wraps the underlying transport error |
{#if $rate.error}
{#if $rate.error.name === 'RateLimitError'}
Slow down — try again in a moment.
{:else}
{$rate.error.message}
{/if}
{/if}Building
This package is pure TypeScript stores — there are no .svelte component files to compile — so it builds with plain tsc:
npm run build # tsc -p tsconfig.build.json → dist/ (ESM + .d.ts)Related
@unirate/sveltekit— SvelteKit server helpers, hooks, and components@unirate/react— React hooks@unirate/vue— Vue 3 composablesunirate-api— the core Node client
License
MIT © Unirate Team
