@sveltebase/utils 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,332 @@
1
+ # `@sveltebase/utils`
2
+
3
+ Utility helpers for Svelte 5 apps, with small primitives for cookies, async actions, timestamps, waiting, and toast-friendly error handling.
4
+
5
+ ## Install
6
+
7
+ With Bun:
8
+
9
+ ```bash
10
+ bun add @sveltebase/utils
11
+ ```
12
+
13
+ If you want toast notifications from `createAsync` or `tryCatch`, also install `svelte-sonner`:
14
+
15
+ ```bash
16
+ bun add svelte-sonner
17
+ ```
18
+
19
+ > `svelte` is a peer dependency and should already exist in your app.
20
+
21
+ ## What’s included
22
+
23
+ - `Cookies` — browser cookie helpers
24
+ - `createAsync` — wraps async functions with loading and error state
25
+ - `tryCatch` — run a task with built-in toast/error handling
26
+ - `timestamps` — generate `createdAt` / `updatedAt` values
27
+ - `wait` — simple promise-based delay helper
28
+ - `TryCatchReturn` — shared return type for async helpers
29
+
30
+ ## Exports
31
+
32
+ ```ts
33
+ import {
34
+ Cookies,
35
+ createAsync,
36
+ timestamps,
37
+ tryCatch,
38
+ wait,
39
+ type TryCatchReturn
40
+ } from "@sveltebase/utils";
41
+ ```
42
+
43
+ ---
44
+
45
+ ## `Cookies`
46
+
47
+ A small browser-only cookie helper with `set`, `get`, and `remove`.
48
+
49
+ ### Example
50
+
51
+ ```ts
52
+ import { Cookies } from "@sveltebase/utils";
53
+
54
+ Cookies.set("theme", "dark", {
55
+ path: "/",
56
+ sameSite: "Lax",
57
+ expires: 30
58
+ });
59
+
60
+ const theme = Cookies.get("theme");
61
+
62
+ Cookies.remove("theme");
63
+ ```
64
+
65
+ ### API
66
+
67
+ #### `Cookies.set(name, value, options?)`
68
+
69
+ Sets a cookie.
70
+
71
+ Options:
72
+
73
+ - `expires?: number` — number of days
74
+ - `path?: string`
75
+ - `domain?: string`
76
+ - `secure?: boolean`
77
+ - `sameSite?: "Lax" | "Strict" | "None"`
78
+ - `partitioned?: boolean`
79
+
80
+ #### `Cookies.get(name)`
81
+
82
+ Returns the cookie value as `string | null`.
83
+
84
+ #### `Cookies.remove(name, options?)`
85
+
86
+ Removes a cookie by setting an expired value.
87
+
88
+ ---
89
+
90
+ ## `createAsync`
91
+
92
+ Wraps an async function and gives you:
93
+
94
+ - loading state
95
+ - last thrown error
96
+ - optional success/error toasts
97
+
98
+ Your async function can return:
99
+
100
+ - `{ success: string }`
101
+ - `{ error: string }`
102
+ - `null`
103
+ - `void`
104
+
105
+ ### Example
106
+
107
+ ```ts
108
+ import { createAsync } from "@sveltebase/utils";
109
+
110
+ const saveProfile = createAsync(async (name: string) => {
111
+ const response = await fetch("/api/profile", {
112
+ method: "POST",
113
+ headers: {
114
+ "Content-Type": "application/json"
115
+ },
116
+ body: JSON.stringify({ name })
117
+ });
118
+
119
+ if (!response.ok) {
120
+ return { error: "Failed to save profile" };
121
+ }
122
+
123
+ return { success: "Profile saved" };
124
+ });
125
+
126
+ await saveProfile.run("Ahror");
127
+
128
+ console.log(saveProfile.isLoading());
129
+ console.log(saveProfile.error);
130
+ ```
131
+
132
+ ### Keyed loading states
133
+
134
+ Use `runWithKey` when you want separate loading states for multiple actions.
135
+
136
+ ```ts
137
+ import { createAsync } from "@sveltebase/utils";
138
+
139
+ const removeItem = createAsync(async (id: string) => {
140
+ const response = await fetch(`/api/items/${id}`, {
141
+ method: "DELETE"
142
+ });
143
+
144
+ if (!response.ok) {
145
+ return { error: "Delete failed" };
146
+ }
147
+
148
+ return { success: "Item removed" };
149
+ });
150
+
151
+ await removeItem.runWithKey("item-42", "42");
152
+
153
+ const isDeleting = removeItem.isLoading("item-42");
154
+ ```
155
+
156
+ ### API
157
+
158
+ ```ts
159
+ const task = createAsync(asyncFn);
160
+
161
+ task.run(...args);
162
+ task.runWithKey(key, ...args);
163
+ task.isLoading(key?);
164
+ task.error;
165
+ ```
166
+
167
+ ### Notes
168
+
169
+ - Toasts are shown with `svelte-sonner` when available in the browser.
170
+ - In development, thrown errors are also logged to the console.
171
+ - On the server, toast behavior is skipped safely.
172
+
173
+ ---
174
+
175
+ ## `tryCatch`
176
+
177
+ Runs a task and handles success/error messages in a consistent way.
178
+
179
+ ### Example
180
+
181
+ ```ts
182
+ import { tryCatch } from "@sveltebase/utils";
183
+
184
+ await tryCatch(async () => {
185
+ const response = await fetch("/api/invite", { method: "POST" });
186
+
187
+ if (!response.ok) {
188
+ return { error: "Could not send invite" };
189
+ }
190
+
191
+ return { success: "Invite sent" };
192
+ });
193
+ ```
194
+
195
+ ### Throwing errors
196
+
197
+ ```ts
198
+ import { tryCatch } from "@sveltebase/utils";
199
+
200
+ await tryCatch(async () => {
201
+ const response = await fetch("/api/private");
202
+
203
+ if (response.status === 401) {
204
+ throw new Error("Unauthorized");
205
+ }
206
+
207
+ return { success: "Loaded" };
208
+ });
209
+ ```
210
+
211
+ ---
212
+
213
+ ## `timestamps`
214
+
215
+ Creates timestamp objects using `Date.now()`.
216
+
217
+ ### Example
218
+
219
+ ```ts
220
+ import { timestamps } from "@sveltebase/utils";
221
+
222
+ const created = timestamps(false);
223
+ // { createdAt: 1712345678901, updatedAt: 1712345678901 }
224
+
225
+ const updated = timestamps(true);
226
+ // { updatedAt: 1712345678901 }
227
+ ```
228
+
229
+ ### Common usage
230
+
231
+ ```ts
232
+ import { timestamps } from "@sveltebase/utils";
233
+
234
+ const post = {
235
+ id: crypto.randomUUID(),
236
+ title: "Hello",
237
+ ...timestamps(false)
238
+ };
239
+ ```
240
+
241
+ ---
242
+
243
+ ## `wait`
244
+
245
+ Returns a promise that resolves after the given number of milliseconds.
246
+
247
+ ### Example
248
+
249
+ ```ts
250
+ import { wait } from "@sveltebase/utils";
251
+
252
+ await wait(500);
253
+ console.log("Done");
254
+ ```
255
+
256
+ Useful for:
257
+
258
+ - delaying UI transitions
259
+ - retry flows
260
+ - testing async behavior
261
+
262
+ ---
263
+
264
+ ## `TryCatchReturn`
265
+
266
+ A shared type for functions used with `createAsync` and `tryCatch`.
267
+
268
+ ```ts
269
+ import type { TryCatchReturn } from "@sveltebase/utils";
270
+
271
+ async function submitForm(): Promise<TryCatchReturn> {
272
+ return { success: "Submitted" };
273
+ }
274
+ ```
275
+
276
+ Possible values:
277
+
278
+ ```ts
279
+ type TryCatchReturn =
280
+ | { success: string; error?: never }
281
+ | { error: string; success?: never }
282
+ | null
283
+ | void;
284
+ ```
285
+
286
+ ---
287
+
288
+ ## Svelte example
289
+
290
+ ```svelte
291
+ <script lang="ts">
292
+ import { createAsync } from "@sveltebase/utils";
293
+
294
+ let name = $state("");
295
+
296
+ const save = createAsync(async (value: string) => {
297
+ const response = await fetch("/api/profile", {
298
+ method: "POST",
299
+ headers: {
300
+ "Content-Type": "application/json"
301
+ },
302
+ body: JSON.stringify({ name: value })
303
+ });
304
+
305
+ if (!response.ok) {
306
+ return { error: "Could not save profile" };
307
+ }
308
+
309
+ return { success: "Profile saved" };
310
+ });
311
+ </script>
312
+
313
+ <input bind:value={name} placeholder="Your name" />
314
+
315
+ <button onclick={() => save.run(name)} disabled={save.isLoading()}>
316
+ {save.isLoading() ? "Saving..." : "Save"}
317
+ </button>
318
+
319
+ {#if save.error}
320
+ <p>{save.error.message}</p>
321
+ {/if}
322
+ ```
323
+
324
+ ## Notes
325
+
326
+ - `Cookies` works only in the browser.
327
+ - `createAsync` and `tryCatch` integrate with `svelte-sonner` if it is installed.
328
+ - The package is designed for Svelte 5 projects.
329
+
330
+ ## License
331
+
332
+ ISC
@@ -1 +1 @@
1
- {"version":3,"file":"async.svelte.d.ts","sourceRoot":"","sources":["../src/async.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GACtB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAClC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE,GAClC,IAAI,GACJ,IAAI,CAAC;AAqCT,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,EAC/F,OAAO,EAAE,CAAC;IAmDR;;;OAGG;oBACa,MAAM;;mBAhBI,UAAU,CAAC,CAAC,CAAC;sBAOV,MAAM,WAAW,UAAU,CAAC,CAAC,CAAC;EAkB9D"}
1
+ {"version":3,"file":"async.svelte.d.ts","sourceRoot":"","sources":["async.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GACtB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAClC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE,GAClC,IAAI,GACJ,IAAI,CAAC;AAqCT,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,EAC/F,OAAO,EAAE,CAAC;IAmDR;;;OAGG;oBACa,MAAM;;mBAhBI,UAAU,CAAC,CAAC,CAAC;sBAOV,MAAM,WAAW,UAAU,CAAC,CAAC,CAAC;EAkB9D"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAuCD,eAAO,MAAM,OAAO;cACR,MAAM,SAAS,MAAM,YAAW,aAAa,GAAQ,IAAI;cA6CzD,MAAM,GAAG,MAAM,GAAG,IAAI;iBAYnB,MAAM,YAAW,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAQ,IAAI;CAGjF,CAAC;AAEF,wBAAgB,UAAU,CAAC,CAAC,SAAS,OAAO,EAC1C,UAAU,EAAE,CAAC,GACZ,CAAC,SAAS,IAAI,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAInF;AAED,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,iBAkBlF;AAED,eAAO,MAAM,IAAI,GAAI,IAAI,MAAM,qBAAsD,CAAC;AAEtF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAuCD,eAAO,MAAM,OAAO;cACR,MAAM,SAAS,MAAM,YAAW,aAAa,GAAQ,IAAI;cA6CzD,MAAM,GAAG,MAAM,GAAG,IAAI;iBAYnB,MAAM,YAAW,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAQ,IAAI;CAGjF,CAAC;AAEF,wBAAgB,UAAU,CAAC,CAAC,SAAS,OAAO,EAC1C,UAAU,EAAE,CAAC,GACZ,CAAC,SAAS,IAAI,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAInF;AAED,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,iBAkBlF;AAED,eAAO,MAAM,IAAI,GAAI,IAAI,MAAM,qBAAsD,CAAC;AAEtF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltebase/utils",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"