@sveltebase/utils
v2.0.1
Published
Small helpers for Svelte 5 apps: cookies, async actions with loading state, toasts, ids, delays, and simple plural formatting.
Readme
@sveltebase/utils
Small helpers for Svelte 5 apps: cookies, async actions with loading state, toasts, ids, delays, and simple plural formatting.
Install
bun add @sveltebase/utilssvelte is a peer dependency. For toast notifications from the async helpers, also install:
bun add svelte-sonnerCookies
Browser-only helpers around document.cookie. On the server they are no-ops (get returns null).
import { Cookies } from "@sveltebase/utils";
Cookies.set("theme", "dark", {
expires: 30, // days
path: "/",
sameSite: "Lax"
});
Cookies.get("theme"); // "dark" | null
Cookies.remove("theme");Defaults when options are omitted: path: "/", sameSite: "Lax", and secure when the page is HTTPS. sameSite: "None" always sets secure.
remove accepts optional path and domain — use the same ones you used when setting the cookie.
Async actions
createAsync wraps an async function with reactive loading and error state.
import { createAsync } from "@sveltebase/utils";
const save = createAsync(async (name: string) => {
const response = await fetch("/api/profile", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name })
});
// Optional: return a toast message
return response.ok
? { success: "Profile saved" }
: { error: "Could not save profile" };
});
await save.run("Ahror");
save.isLoading(); // true while the request is in flight
save.error; // last thrown Error, or nullReturn values:
{ success: "..." }— success toast (ifsvelte-sonneris available){ error: "..." }— error toast; does not setsave.erroror rejectnull/void— finishes quietly- thrown error — stored on
save.error, shown as a toast, and rethrown
Multiple concurrent actions
Track loading per item with a key:
await save.runWithKey(rowId, "New name");
save.isLoading(rowId); // only that row
save.isLoading(); // the shared “global” keyOne-off try/catch with toasts
import { tryCatch } from "@sveltebase/utils";
await tryCatch(async () => {
const response = await fetch("/api/invite", { method: "POST" });
return response.ok
? { success: "Invite sent" }
: { error: "Could not send invite" };
});Unlike createAsync, tryCatch swallows thrown errors (and still toasts them). Customize the toast:
await tryCatch(() => loadPrivateData(), {
onError(error) {
if (error instanceof SessionExpiredError) {
return {
message: "Your session has expired",
description: "Sign in again to continue."
};
}
// return null/undefined for the default message
}
});Toasts are browser-only and load lazily — SSR is fine, and you don’t need a <Toaster /> mounted at import time.
Other helpers
timestamps
timestamps(false); // { createdAt, updatedAt } — same millisecond
timestamps(true); // { updatedAt }wait
await wait(250); // resolves after 250mscreateId
const id = createId(); // UUID v4-styleUses crypto.randomUUID() when available, then getRandomValues(), then a Math.random() fallback.
pluralize
pluralize(0, { zero: "No items", one: "item", other: "items" });
// "No items"
pluralize(1, { one: "item", other: "items" });
// "1 item"
pluralize(4, { one: "item", other: "items" });
// "4 items"
pluralize(3, { other: (n) => `${n} matches found` });
// "3 matches found"zero— only when count is0one— only when count is1(prefixed with1)other— everything else (string or function)
License
ISC
