@jwerre/vellum 1.0.1 → 1.1.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 +651 -146
- package/dist/Collection.svelte.d.ts +0 -12
- package/dist/Collection.svelte.js +0 -12
- package/dist/Model.svelte.d.ts +329 -9
- package/dist/Model.svelte.js +357 -27
- package/dist/config.svelte.d.ts +34 -1
- package/dist/config.svelte.js +34 -1
- package/dist/errors/validation_error.d.ts +8 -0
- package/dist/errors/validation_error.js +9 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +10 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vellum
|
|
2
2
|
|
|
3
|
-
Vellum is a lightweight, structural state management library for Svelte 5. Vellum provides a robust Model and Collection base powered by Svelte Runes.It bridges the gap between raw objects and complex state logic, offering a typed, class-based approach to managing data-heavy applications.
|
|
3
|
+
Vellum is a lightweight, structural state management library for Svelte 5. Vellum provides a robust Model and Collection base powered by Svelte Runes. It bridges the gap between raw objects and complex state logic, offering a typed, class-based approach to managing data-heavy applications.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -27,7 +27,7 @@ Modern Svelte development often moves away from stores and toward raw $state obj
|
|
|
27
27
|
npm install @jwerre/vellum
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
## Quick
|
|
30
|
+
## Quick start
|
|
31
31
|
|
|
32
32
|
### Configuration
|
|
33
33
|
|
|
@@ -50,30 +50,52 @@ Extend the Model class to define your data structure and any derived state or bu
|
|
|
50
50
|
|
|
51
51
|
```ts
|
|
52
52
|
import { Model } from '@jwerre/vellum';
|
|
53
|
-
interface
|
|
53
|
+
interface BookSchema {
|
|
54
54
|
id: number;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
author: string;
|
|
56
|
+
genre: 'literature', 'romance' | 'adventure' | 'fantasy' | 'sci-fi' | 'mystery';
|
|
57
|
+
summary: string;
|
|
58
|
+
title: string;
|
|
59
|
+
year: number;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
export class
|
|
62
|
+
export class Book extends Model<BookSchema> {
|
|
63
|
+
|
|
61
64
|
endpoint() {
|
|
62
|
-
return `/v1/
|
|
65
|
+
return `/v1/books`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
defaults() {
|
|
69
|
+
return {
|
|
70
|
+
title: '',
|
|
71
|
+
author: '',
|
|
72
|
+
genre: 'literature',
|
|
73
|
+
summary: '',
|
|
74
|
+
year: new Date().getFullYear()
|
|
75
|
+
};
|
|
63
76
|
}
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
fullName = $derived(`${this.get('firstName')} ${this.get('lastName')}`);
|
|
78
|
+
authorFirstName = $derived(`${this.get('author')?.split(' ')[0]}`);
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
authorLastName = $derived(`${this.get('author')?.split(' ')[1]}`);
|
|
81
|
+
|
|
82
|
+
isClassic() {
|
|
83
|
+
return this.get('year') < 1900;
|
|
70
84
|
}
|
|
71
85
|
}
|
|
72
86
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
87
|
+
const book = new Book({
|
|
88
|
+
title: 'Crime and Punishment',
|
|
89
|
+
author: 'Fyodor Dostoevsky',
|
|
90
|
+
year: 1866,
|
|
91
|
+
genre: 'literature',
|
|
92
|
+
summary: 'An exploration of the mental anguish and moral dilemmas...',
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
await book.sync(); // issues POST request to endpoint
|
|
96
|
+
console.log(book.id); // unique ID created by POST request
|
|
97
|
+
console.log(book.authorFirstName); // Fyodor
|
|
98
|
+
console.log(book.isClassic()); // true
|
|
77
99
|
```
|
|
78
100
|
|
|
79
101
|
### Define a Collection
|
|
@@ -82,292 +104,773 @@ Manage groups of models with built-in reactivity.
|
|
|
82
104
|
|
|
83
105
|
```ts
|
|
84
106
|
import { Collection } from '@jwerre/vellum';
|
|
85
|
-
import {
|
|
107
|
+
import { Book } from './Book.svelte.js';
|
|
86
108
|
|
|
87
|
-
export class
|
|
88
|
-
model =
|
|
109
|
+
export class Books extends Collection<Book, BookSchema> {
|
|
110
|
+
model = Book;
|
|
89
111
|
|
|
90
112
|
endpoint() {
|
|
91
|
-
return `/v1/
|
|
113
|
+
return `/v1/books`;
|
|
92
114
|
}
|
|
93
115
|
|
|
94
116
|
// Derived state for the entire collection
|
|
95
|
-
|
|
117
|
+
classicCount = $derived(this.items.filter((u) => u.isClassic()).length);
|
|
96
118
|
}
|
|
97
119
|
```
|
|
98
120
|
|
|
99
|
-
### Use in Svelte
|
|
121
|
+
### Use in Svelte components
|
|
100
122
|
|
|
101
123
|
Vellum works seamlessly with Svelte 5 components.
|
|
102
124
|
|
|
103
125
|
```svelte
|
|
104
126
|
<script lang="ts">
|
|
105
|
-
import {
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
127
|
+
import { Books } from './Books';
|
|
128
|
+
|
|
129
|
+
const books = new Books([
|
|
130
|
+
{
|
|
131
|
+
id: 1,
|
|
132
|
+
title: 'The Great Gatsby',
|
|
133
|
+
author: 'F. Scott Fitzgerald',
|
|
134
|
+
year: 1925,
|
|
135
|
+
genre: 'literature'
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: 2,
|
|
139
|
+
title: 'To Kill a Mockingbird',
|
|
140
|
+
author: 'Harper Lee',
|
|
141
|
+
year: 1960,
|
|
142
|
+
genre: 'literature'
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: 3,
|
|
146
|
+
title: 'The Pillars of the Earth',
|
|
147
|
+
author: 'Ken Follett',
|
|
148
|
+
year: 1989,
|
|
149
|
+
genre: 'literature'
|
|
150
|
+
}
|
|
151
|
+
]);
|
|
152
|
+
|
|
153
|
+
function addBook() {
|
|
154
|
+
books.add({
|
|
155
|
+
title: 'Moby Dick',
|
|
156
|
+
author: 'Herman Melville',
|
|
157
|
+
year: 1851,
|
|
158
|
+
genre: 'Adventure',
|
|
159
|
+
summary: 'The obsessive quest of Captain Ahab to seek revenge on the white whale.'
|
|
160
|
+
});
|
|
111
161
|
}
|
|
112
162
|
</script>
|
|
113
163
|
|
|
114
|
-
<h1>
|
|
164
|
+
<h1>Classic Books: {books.classicCount}</h1>
|
|
115
165
|
|
|
116
166
|
<ul>
|
|
117
|
-
{#each
|
|
118
|
-
{#if
|
|
119
|
-
<li>{
|
|
167
|
+
{#each books.items as book}
|
|
168
|
+
{#if book.isClassic()}
|
|
169
|
+
<li>{book.get('title')} ({book.get('year')}) - ({book.get('author')})</li>
|
|
120
170
|
{/if}
|
|
121
171
|
{/each}
|
|
122
172
|
</ul>
|
|
123
173
|
|
|
124
|
-
<button onclick={
|
|
174
|
+
<button onclick={addBook}>Add Moby Dick</button>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Working example
|
|
178
|
+
|
|
179
|
+
There is a working example of Vellum in the `routes` directory. To run it, clone the repository, install dependencies, and run the development server:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
git clone https://github.com/jwerre/vellum.git
|
|
183
|
+
cd vellum
|
|
184
|
+
npm install
|
|
185
|
+
npm run dev
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## API Documentation
|
|
189
|
+
|
|
190
|
+
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
|
191
|
+
|
|
192
|
+
#### Table of Contents
|
|
193
|
+
|
|
194
|
+
- [vellumConfig](#vellumconfig)
|
|
195
|
+
- [configureVellum](#configurevellum)
|
|
196
|
+
- [Parameters](#parameters)
|
|
197
|
+
- [Examples](#examples)
|
|
198
|
+
- [Model](#model)
|
|
199
|
+
- [Parameters](#parameters-1)
|
|
200
|
+
- [Examples](#examples-1)
|
|
201
|
+
- [validationError](#validationerror)
|
|
202
|
+
- [idAttribute](#idattribute)
|
|
203
|
+
- [get](#get)
|
|
204
|
+
- [Parameters](#parameters-2)
|
|
205
|
+
- [Examples](#examples-2)
|
|
206
|
+
- [has](#has)
|
|
207
|
+
- [Parameters](#parameters-3)
|
|
208
|
+
- [Examples](#examples-3)
|
|
209
|
+
- [unset](#unset)
|
|
210
|
+
- [Parameters](#parameters-4)
|
|
211
|
+
- [Examples](#examples-4)
|
|
212
|
+
- [clear](#clear)
|
|
213
|
+
- [Examples](#examples-5)
|
|
214
|
+
- [escape](#escape)
|
|
215
|
+
- [Parameters](#parameters-5)
|
|
216
|
+
- [Examples](#examples-6)
|
|
217
|
+
- [isNew](#isnew)
|
|
218
|
+
- [isValid](#isvalid)
|
|
219
|
+
- [Parameters](#parameters-6)
|
|
220
|
+
- [Examples](#examples-7)
|
|
221
|
+
- [validate](#validate)
|
|
222
|
+
- [Parameters](#parameters-7)
|
|
223
|
+
- [Examples](#examples-8)
|
|
224
|
+
- [sync](#sync)
|
|
225
|
+
- [Parameters](#parameters-8)
|
|
226
|
+
- [Examples](#examples-9)
|
|
227
|
+
- [fetch](#fetch)
|
|
228
|
+
- [Examples](#examples-10)
|
|
229
|
+
- [save](#save)
|
|
230
|
+
- [Parameters](#parameters-9)
|
|
231
|
+
- [Examples](#examples-11)
|
|
232
|
+
- [destroy](#destroy)
|
|
233
|
+
- [Examples](#examples-12)
|
|
234
|
+
- [toJSON](#tojson)
|
|
235
|
+
- [Examples](#examples-13)
|
|
236
|
+
- [Collection](#collection)
|
|
237
|
+
- [Parameters](#parameters-10)
|
|
238
|
+
- [Examples](#examples-14)
|
|
239
|
+
- [items](#items)
|
|
240
|
+
- [length](#length)
|
|
241
|
+
- [add](#add)
|
|
242
|
+
- [Parameters](#parameters-11)
|
|
243
|
+
- [Examples](#examples-15)
|
|
244
|
+
- [reset](#reset)
|
|
245
|
+
- [Parameters](#parameters-12)
|
|
246
|
+
- [Examples](#examples-16)
|
|
247
|
+
- [find](#find)
|
|
248
|
+
- [Parameters](#parameters-13)
|
|
249
|
+
- [Examples](#examples-17)
|
|
250
|
+
- [fetch](#fetch-1)
|
|
251
|
+
- [Parameters](#parameters-14)
|
|
252
|
+
- [Examples](#examples-18)
|
|
253
|
+
|
|
254
|
+
### vellumConfig
|
|
255
|
+
|
|
256
|
+
Global reactive state for Vellum configuration. Uses Svelte's $state rune to
|
|
257
|
+
create a reactive configuration object that automatically triggers updates when modified.
|
|
258
|
+
|
|
259
|
+
### configureVellum
|
|
260
|
+
|
|
261
|
+
Helper function to update global Vellum configuration
|
|
262
|
+
|
|
263
|
+
Allows partial updates to the global configuration state. Only provided
|
|
264
|
+
properties will be updated, leaving others unchanged. Headers are merged
|
|
265
|
+
with existing headers rather than replaced entirely.
|
|
266
|
+
|
|
267
|
+
#### Parameters
|
|
268
|
+
|
|
269
|
+
- `config` **Partial\<VellumConfig>** Partial configuration object with properties to update
|
|
270
|
+
- `config.origin` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** New origin URL to set
|
|
271
|
+
- `config.headers` **Record<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>?** Headers to merge with existing headers
|
|
272
|
+
|
|
273
|
+
#### Examples
|
|
274
|
+
|
|
275
|
+
```javascript
|
|
276
|
+
// Set the API origin
|
|
277
|
+
configureVellum({ origin: 'https://api.vellum.ai' });
|
|
278
|
+
|
|
279
|
+
// Add custom headers
|
|
280
|
+
configureVellum({
|
|
281
|
+
headers: {
|
|
282
|
+
Authorization: 'Bearer token123',
|
|
283
|
+
'X-Custom-Header': 'value'
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Update both origin and headers
|
|
288
|
+
configureVellum({
|
|
289
|
+
origin: 'https://api.vellum.ai',
|
|
290
|
+
headers: { Authorization: 'Bearer token123' }
|
|
291
|
+
});
|
|
125
292
|
```
|
|
126
293
|
|
|
127
|
-
|
|
294
|
+
### Model
|
|
295
|
+
|
|
296
|
+
Abstract base class for creating model instances that interact with RESTful APIs.
|
|
297
|
+
|
|
298
|
+
The Model class provides a structured way to manage data objects with full CRUD
|
|
299
|
+
(Create, Read, Update, Delete) capabilities. It includes built-in HTTP synchronization,
|
|
300
|
+
attribute management, and data validation features. This class is designed to work
|
|
301
|
+
with Svelte's reactivity system using the `$state` rune for automatic UI updates.
|
|
302
|
+
|
|
303
|
+
Key features:
|
|
304
|
+
|
|
305
|
+
- Type-safe attribute access and manipulation
|
|
306
|
+
- Automatic HTTP synchronization with RESTful APIs
|
|
307
|
+
- Built-in HTML escaping for XSS prevention
|
|
308
|
+
- Configurable ID attributes for different database schemas
|
|
309
|
+
- Reactive attributes that integrate with Svelte's state management
|
|
310
|
+
- Support for both single attribute and bulk attribute operations
|
|
128
311
|
|
|
129
|
-
|
|
312
|
+
#### Parameters
|
|
130
313
|
|
|
131
|
-
|
|
314
|
+
- `data` (optional, default `{}`)
|
|
315
|
+
- `options` (optional, default `{}`)
|
|
132
316
|
|
|
133
|
-
####
|
|
317
|
+
#### Examples
|
|
134
318
|
|
|
135
319
|
```javascript
|
|
136
|
-
|
|
320
|
+
// Define a User model
|
|
321
|
+
interface UserAttributes {
|
|
322
|
+
id?: number;
|
|
323
|
+
name: string;
|
|
324
|
+
email: string;
|
|
325
|
+
createdAt?: Date;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
class User extends Model<UserAttributes> {
|
|
329
|
+
endpoint(): string {
|
|
330
|
+
return '/users';
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Create and use a model instance
|
|
335
|
+
const user = new User({ name: 'John Doe', email: 'john@example.com' });
|
|
336
|
+
await user.save(); // Creates new user on server
|
|
337
|
+
user.set('name', 'Jane Doe');
|
|
338
|
+
await user.save(); // Updates existing user
|
|
137
339
|
```
|
|
138
340
|
|
|
139
|
-
|
|
341
|
+
```javascript
|
|
342
|
+
// Using custom ID attribute (e.g., MongoDB _id)
|
|
343
|
+
interface MongoUserAttributes {
|
|
344
|
+
_id?: string;
|
|
345
|
+
username: string;
|
|
346
|
+
profile: {
|
|
347
|
+
firstName: string;
|
|
348
|
+
lastName: string;
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
class MongoUser extends Model<MongoUserAttributes> {
|
|
353
|
+
constructor(data?: Partial<MongoUserAttributes>) {
|
|
354
|
+
super(data, { idAttribute: '_id' });
|
|
355
|
+
}
|
|
140
356
|
|
|
141
|
-
|
|
357
|
+
endpoint(): string {
|
|
358
|
+
return '/api/users';
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
142
362
|
|
|
143
|
-
|
|
363
|
+
#### validationError
|
|
144
364
|
|
|
145
|
-
|
|
365
|
+
Validation error property that gets set when validation fails.
|
|
366
|
+
This property contains the error returned by the validate method.
|
|
146
367
|
|
|
147
|
-
|
|
368
|
+
#### idAttribute
|
|
148
369
|
|
|
149
|
-
|
|
370
|
+
Gets the current ID attribute name used by this model instance.
|
|
150
371
|
|
|
151
|
-
|
|
372
|
+
Returns **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the attribute used as the ID field
|
|
152
373
|
|
|
153
|
-
|
|
374
|
+
#### get
|
|
154
375
|
|
|
155
376
|
Retrieves the value of a specific attribute from the model.
|
|
156
377
|
|
|
157
|
-
|
|
378
|
+
This method provides type-safe access to model attributes, ensuring that the
|
|
379
|
+
returned value matches the expected type for the given key. It acts as a
|
|
380
|
+
getter for the internal attributes stored in the model instance.
|
|
158
381
|
|
|
159
|
-
|
|
382
|
+
##### Parameters
|
|
160
383
|
|
|
161
|
-
**
|
|
384
|
+
- `key` **K** The attribute key to retrieve the value for
|
|
385
|
+
|
|
386
|
+
##### Examples
|
|
162
387
|
|
|
163
388
|
```javascript
|
|
389
|
+
// Assuming a User model with attributes { id: number, name: string }
|
|
164
390
|
const user = new User({ id: 1, name: 'John Doe' });
|
|
165
|
-
const name = user.get('name'); // Returns 'John Doe'
|
|
391
|
+
const name = user.get('name'); // Returns 'John Doe' (string)
|
|
392
|
+
const id = user.get('id'); // Returns 1 (number)
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
#### has
|
|
396
|
+
|
|
397
|
+
Checks whether a specific attribute has a non-null, non-undefined value.
|
|
398
|
+
|
|
399
|
+
This method provides a way to determine if an attribute exists and has a
|
|
400
|
+
meaningful value. It returns true if the attribute is set to any value
|
|
401
|
+
other than null or undefined, including falsy values like false, 0, or
|
|
402
|
+
empty strings, which are considered valid values.
|
|
403
|
+
|
|
404
|
+
##### Parameters
|
|
405
|
+
|
|
406
|
+
- `key` **K** The attribute key to check
|
|
407
|
+
|
|
408
|
+
##### Examples
|
|
409
|
+
|
|
410
|
+
```javascript
|
|
411
|
+
// Assuming a User model with attributes { id: number, name: string, email?: string }
|
|
412
|
+
const user = new User({ id: 1, name: 'John', email: null });
|
|
413
|
+
|
|
414
|
+
user.has('id'); // Returns true (value is 1)
|
|
415
|
+
user.has('name'); // Returns true (value is 'John')
|
|
416
|
+
user.has('email'); // Returns false (value is null)
|
|
417
|
+
|
|
418
|
+
// Even falsy values are considered "set"
|
|
419
|
+
user.set({ name: '' });
|
|
420
|
+
user.has('name'); // Returns true (empty string is a valid value)
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** True if the attribute has a non-null, non-undefined value
|
|
424
|
+
|
|
425
|
+
#### unset
|
|
426
|
+
|
|
427
|
+
Removes a specific attribute from the model by deleting it from the internal attributes hash.
|
|
428
|
+
|
|
429
|
+
This method permanently removes an attribute from the model instance. Once unset,
|
|
430
|
+
the attribute will no longer exist on the model and subsequent calls to get() for
|
|
431
|
+
that key will return undefined. This is different from setting an attribute to
|
|
432
|
+
null or undefined, as the property is completely removed from the attributes object.
|
|
433
|
+
|
|
434
|
+
##### Parameters
|
|
435
|
+
|
|
436
|
+
- `key` **K** The attribute key to remove from the model
|
|
437
|
+
|
|
438
|
+
##### Examples
|
|
439
|
+
|
|
440
|
+
```javascript
|
|
441
|
+
// Assuming a User model with attributes { id: number, name: string, email: string }
|
|
442
|
+
const user = new User({ id: 1, name: 'John', email: 'john@example.com' });
|
|
443
|
+
|
|
444
|
+
user.has('email'); // Returns true
|
|
445
|
+
user.unset('email'); // Remove the email attribute
|
|
446
|
+
user.has('email'); // Returns false
|
|
447
|
+
user.get('email'); // Returns undefined
|
|
448
|
+
|
|
449
|
+
// The attribute is completely removed, not just set to undefined
|
|
450
|
+
const userData = user.toJSON(); // { id: 1, name: 'John' }
|
|
166
451
|
```
|
|
167
452
|
|
|
168
|
-
|
|
453
|
+
Returns **void** 
|
|
169
454
|
|
|
170
|
-
|
|
455
|
+
#### clear
|
|
171
456
|
|
|
172
|
-
|
|
457
|
+
Removes all attributes from the model, including the id attribute.
|
|
173
458
|
|
|
174
|
-
|
|
459
|
+
This method completely clears the model instance by removing all stored attributes,
|
|
460
|
+
effectively resetting it to an empty state. After calling clear(), the model will
|
|
461
|
+
behave as if it were newly instantiated with no data. This includes removing the
|
|
462
|
+
ID attribute, which means the model will be considered "new" after clearing.
|
|
463
|
+
|
|
464
|
+
This is useful when you want to reuse a model instance for different data or
|
|
465
|
+
reset a model to its initial state without creating a new instance.
|
|
466
|
+
|
|
467
|
+
##### Examples
|
|
175
468
|
|
|
176
469
|
```javascript
|
|
470
|
+
// Clear all data from a user model
|
|
471
|
+
const user = new User({ id: 1, name: 'John', email: 'john@example.com' });
|
|
472
|
+
user.clear();
|
|
473
|
+
|
|
474
|
+
user.has('id'); // Returns false
|
|
475
|
+
user.has('name'); // Returns false
|
|
476
|
+
user.isNew(); // Returns true
|
|
477
|
+
user.toJSON(); // Returns {}
|
|
478
|
+
|
|
479
|
+
// Model can be reused with new data
|
|
177
480
|
user.set({ name: 'Jane', email: 'jane@example.com' });
|
|
178
481
|
```
|
|
179
482
|
|
|
180
|
-
|
|
483
|
+
Returns **void** 
|
|
484
|
+
|
|
485
|
+
#### escape
|
|
486
|
+
|
|
487
|
+
Retrieves and escapes the HTML content of a specific attribute from the model.
|
|
488
|
+
|
|
489
|
+
This method provides a safe way to access model attributes that may contain
|
|
490
|
+
user-generated content or data that will be rendered in HTML contexts. It
|
|
491
|
+
automatically applies HTML escaping to prevent XSS attacks and ensure safe
|
|
492
|
+
rendering of potentially dangerous content.
|
|
493
|
+
|
|
494
|
+
The method uses the escapeHTML utility function to convert special HTML
|
|
495
|
+
characters (such as <, >, &, ", and ') into their corresponding HTML entities,
|
|
496
|
+
making the content safe for direct insertion into HTML templates.
|
|
497
|
+
|
|
498
|
+
##### Parameters
|
|
499
|
+
|
|
500
|
+
- `key` **K** The attribute key to retrieve and escape the value for
|
|
501
|
+
|
|
502
|
+
##### Examples
|
|
503
|
+
|
|
504
|
+
```javascript
|
|
505
|
+
// Assuming a Post model with attributes { id: number, title: string, content: string }
|
|
506
|
+
const post = new Post({
|
|
507
|
+
id: 1,
|
|
508
|
+
title: 'Hello <script>alert("XSS")</script>',
|
|
509
|
+
content: 'This is "safe" & secure content'
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
const safeTitle = post.escape('title');
|
|
513
|
+
// Returns: 'Hello <script>alert("XSS")</script>'
|
|
514
|
+
|
|
515
|
+
const safeContent = post.escape('content');
|
|
516
|
+
// Returns: 'This is "safe" & secure content'
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
#### isNew
|
|
181
520
|
|
|
182
521
|
Determines whether this model instance is new (not yet persisted).
|
|
522
|
+
A model is considered new if it doesn't have an 'id' or '\_id' attribute.
|
|
523
|
+
|
|
524
|
+
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** true if the model is new, false if it has been persisted
|
|
525
|
+
|
|
526
|
+
#### isValid
|
|
527
|
+
|
|
528
|
+
Validates the current model instance and returns whether it passes validation.
|
|
529
|
+
|
|
530
|
+
This method performs validation on the model's current attributes using the
|
|
531
|
+
validate() method defined by the subclass. It's a convenience method that
|
|
532
|
+
allows you to check if a model is valid without having to manually call
|
|
533
|
+
the validation logic.
|
|
534
|
+
|
|
535
|
+
If validation fails, the validationError property will be set with details
|
|
536
|
+
about what went wrong. If validation passes, validationError will be cleared.
|
|
537
|
+
|
|
538
|
+
##### Parameters
|
|
539
|
+
|
|
540
|
+
- `options` **ValidationOptions?** Optional validation configuration
|
|
541
|
+
- `options.silent` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** If true, suppresses validation error setting
|
|
542
|
+
|
|
543
|
+
##### Examples
|
|
544
|
+
|
|
545
|
+
```javascript
|
|
546
|
+
// Check if a user model is valid
|
|
547
|
+
const user = new User({ name: '', email: 'invalid-email' });
|
|
548
|
+
|
|
549
|
+
if (!user.isValid()) {
|
|
550
|
+
console.log('Validation failed:', user.validationError);
|
|
551
|
+
// Handle validation errors
|
|
552
|
+
} else {
|
|
553
|
+
// Proceed with saving or other operations
|
|
554
|
+
await user.save();
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
```javascript
|
|
559
|
+
// Validate silently without setting validationError
|
|
560
|
+
const isValid = user.isValid({ silent: true });
|
|
561
|
+
// user.validationError remains unchanged
|
|
562
|
+
```
|
|
183
563
|
|
|
184
|
-
|
|
564
|
+
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** True if the model passes validation, false otherwise
|
|
565
|
+
|
|
566
|
+
#### validate
|
|
567
|
+
|
|
568
|
+
Validates the model's attributes using custom validation logic.
|
|
569
|
+
|
|
570
|
+
This method is intended to be overridden by subclasses to implement custom
|
|
571
|
+
validation rules. By default, it returns undefined (no validation errors).
|
|
572
|
+
If validation fails, this method should return an error - either a simple
|
|
573
|
+
string message or a complete error object.
|
|
574
|
+
|
|
575
|
+
The validate method is automatically called by save() before persisting data,
|
|
576
|
+
and can also be explicitly called by set() when the {validate: true} option
|
|
577
|
+
is passed. If validation fails, the save operation is aborted and model
|
|
578
|
+
attributes are not modified.
|
|
579
|
+
|
|
580
|
+
##### Parameters
|
|
581
|
+
|
|
582
|
+
- `attributes` **Partial\<T>** The attributes to validate
|
|
583
|
+
- `options` **any?** Additional options passed from set() or save()
|
|
584
|
+
|
|
585
|
+
##### Examples
|
|
185
586
|
|
|
186
587
|
```javascript
|
|
187
|
-
|
|
188
|
-
|
|
588
|
+
// Override in a User model subclass
|
|
589
|
+
validate(attributes: Partial<UserAttributes>) {
|
|
590
|
+
if (!attributes.email) {
|
|
591
|
+
return 'Email is required';
|
|
592
|
+
}
|
|
593
|
+
if (!attributes.email.includes('@')) {
|
|
594
|
+
return { email: 'Invalid email format' };
|
|
595
|
+
}
|
|
596
|
+
// Return undefined if validation passes
|
|
597
|
+
}
|
|
189
598
|
```
|
|
190
599
|
|
|
191
|
-
|
|
600
|
+
Returns **any** Returns undefined if valid, or an error (string/object) if invalid
|
|
601
|
+
|
|
602
|
+
#### sync
|
|
192
603
|
|
|
193
604
|
Performs HTTP synchronization with the server for CRUD operations.
|
|
194
605
|
|
|
195
|
-
|
|
606
|
+
This method handles all HTTP communication between the model and the server,
|
|
607
|
+
automatically constructing the appropriate URL based on the model's ID and
|
|
608
|
+
endpoint(). It supports all standard REST operations and provides type-safe
|
|
609
|
+
response handling.
|
|
610
|
+
|
|
611
|
+
The URL construction follows REST conventions:
|
|
196
612
|
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
- `options` - Optional configuration overrides
|
|
613
|
+
- For new models (no ID): uses collection endpoint `${baseUrl}${endpoint()}`
|
|
614
|
+
- For existing models (with ID): uses resource endpoint `${baseUrl}${endpoint()}/${id}`
|
|
200
615
|
|
|
201
|
-
|
|
616
|
+
##### Parameters
|
|
617
|
+
|
|
618
|
+
- `method` **(`"GET"` | `"POST"` | `"PUT"` | `"PATCH"` | `"DELETE"`)** The HTTP method to use (defaults to 'GET') (optional, default `'GET'`)
|
|
619
|
+
- `body` **(Record<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), unknown> | T)?** Optional request body data to send
|
|
620
|
+
- `options` (optional, default `{}`)
|
|
621
|
+
|
|
622
|
+
##### Examples
|
|
202
623
|
|
|
203
624
|
```javascript
|
|
204
|
-
// Fetch user
|
|
625
|
+
// Fetch a user by ID (default 'GET' request)
|
|
205
626
|
const userData = await user.sync();
|
|
206
627
|
|
|
207
|
-
// Create new user
|
|
208
|
-
const newUser = await user.sync('POST', { name: 'John' });
|
|
628
|
+
// Create a new user (POST request)
|
|
629
|
+
const newUser = await user.sync('POST', { name: 'John', email: 'john@example.com' });
|
|
630
|
+
|
|
631
|
+
// Update an existing user (PUT request)
|
|
632
|
+
const updatedUser = await user.sync('PUT', user.toJSON());
|
|
209
633
|
|
|
210
|
-
//
|
|
211
|
-
|
|
634
|
+
// Delete a user (DELETE request)
|
|
635
|
+
await user.sync('DELETE'); // Returns null for 204 responses
|
|
212
636
|
```
|
|
213
637
|
|
|
214
|
-
|
|
638
|
+
- Throws **[Error](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error)** Throws an error if the HTTP response is not successful
|
|
639
|
+
|
|
640
|
+
Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<(R | null)>** The server response data, or null for 204 No Content responses
|
|
641
|
+
|
|
642
|
+
#### fetch
|
|
215
643
|
|
|
216
644
|
Fetches data from the server and updates the model's attributes.
|
|
217
645
|
|
|
218
|
-
|
|
646
|
+
This method performs a GET request to retrieve the latest data for this model
|
|
647
|
+
instance from the server. If the model has an ID, it will fetch the specific
|
|
648
|
+
resource; if it's a new model without an ID, it will make a request to the
|
|
649
|
+
collection endpoint.
|
|
650
|
+
|
|
651
|
+
Upon successful retrieval, the model's attributes are automatically updated
|
|
652
|
+
with the server response data. This method is useful for refreshing a model's
|
|
653
|
+
state or loading data after creating a model instance with just an ID.
|
|
654
|
+
|
|
655
|
+
##### Examples
|
|
219
656
|
|
|
220
657
|
```javascript
|
|
658
|
+
// Fetch data for an existing user
|
|
221
659
|
const user = new User({ id: 1 });
|
|
222
|
-
await user.fetch(); // Model now contains full user data
|
|
660
|
+
await user.fetch(); // Model now contains full user data from server
|
|
661
|
+
|
|
662
|
+
// Refresh a model's data
|
|
663
|
+
await existingUser.fetch(); // Updates with latest server data
|
|
223
664
|
```
|
|
224
665
|
|
|
225
|
-
|
|
666
|
+
- Throws **[Error](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error)** Throws an error if the HTTP request fails or server returns an error
|
|
226
667
|
|
|
227
|
-
|
|
668
|
+
Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<void>** A promise that resolves when the fetch operation completes
|
|
228
669
|
|
|
229
|
-
|
|
670
|
+
#### save
|
|
230
671
|
|
|
231
|
-
|
|
232
|
-
// Create new user
|
|
233
|
-
const newUser = new User({ name: 'John' });
|
|
234
|
-
await newUser.save(); // POST request
|
|
672
|
+
Saves the model to the server by creating a new resource or updating an existing one.
|
|
235
673
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
674
|
+
This method automatically determines whether to create or update based on the model's
|
|
675
|
+
state. If the model is new (has no ID), it performs a POST request to create a new
|
|
676
|
+
resource. If the model already exists (has an ID), it performs a PUT request to
|
|
677
|
+
update the existing resource.
|
|
240
678
|
|
|
241
|
-
|
|
679
|
+
After a successful save operation, the model's attributes are updated with any
|
|
680
|
+
data returned from the server. This is particularly useful when the server
|
|
681
|
+
generates additional fields (like timestamps, computed values, or normalized data)
|
|
682
|
+
during the save process.
|
|
242
683
|
|
|
243
|
-
|
|
684
|
+
##### Parameters
|
|
685
|
+
|
|
686
|
+
- `options`  
|
|
244
687
|
|
|
245
|
-
|
|
688
|
+
##### Examples
|
|
246
689
|
|
|
247
690
|
```javascript
|
|
248
|
-
|
|
691
|
+
// Create a new user
|
|
692
|
+
const newUser = new User({ name: 'John', email: 'john@example.com' });
|
|
693
|
+
await newUser.save(); // POST request, user now has ID from server
|
|
694
|
+
|
|
695
|
+
// Update an existing user
|
|
696
|
+
existingUser.set({ name: 'Jane' });
|
|
697
|
+
await existingUser.save(); // PUT request with updated data
|
|
698
|
+
|
|
699
|
+
// Save without validation
|
|
700
|
+
await user.save({ validate: false });
|
|
701
|
+
|
|
702
|
+
// Save with custom endpoint and headers
|
|
703
|
+
await user.save({
|
|
704
|
+
endpoint: '/api/v2/users',
|
|
705
|
+
headers: { 'Custom-Header': 'value' }
|
|
706
|
+
});
|
|
249
707
|
```
|
|
250
708
|
|
|
251
|
-
|
|
709
|
+
- Throws **[Error](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error)** Throws an error if the HTTP request fails or server returns an error
|
|
252
710
|
|
|
253
|
-
Returns
|
|
711
|
+
Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)>** A promise that resolves to true if save succeeds, false if validation fails
|
|
254
712
|
|
|
255
|
-
|
|
713
|
+
#### destroy
|
|
714
|
+
|
|
715
|
+
Deletes the model from the server.
|
|
716
|
+
|
|
717
|
+
This method performs a DELETE request to remove the model's corresponding resource
|
|
718
|
+
from the server. The method only executes if the model has an ID (i.e., it exists
|
|
719
|
+
on the server). If the model is new and has no ID, the method will return without
|
|
720
|
+
performing any operation.
|
|
721
|
+
|
|
722
|
+
The DELETE request is sent to the model's specific resource endpoint using the
|
|
723
|
+
pattern `${baseUrl}${endpoint()}/${id}`. After successful deletion, the model
|
|
724
|
+
instance remains in memory but the corresponding server resource is removed.
|
|
725
|
+
|
|
726
|
+
##### Examples
|
|
256
727
|
|
|
257
728
|
```javascript
|
|
729
|
+
// Delete an existing user
|
|
258
730
|
const user = new User({ id: 1, name: 'John' });
|
|
259
|
-
|
|
260
|
-
|
|
731
|
+
await user.destroy(); // DELETE request to /users/1
|
|
732
|
+
|
|
733
|
+
// Attempting to destroy a new model (no operation performed)
|
|
734
|
+
const newUser = new User({ name: 'Jane' }); // No ID
|
|
735
|
+
await newUser.destroy(); // Returns immediately, no HTTP request
|
|
261
736
|
```
|
|
262
737
|
|
|
263
|
-
|
|
738
|
+
- Throws **[Error](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error)** Throws an error if the HTTP request fails or server returns an error
|
|
264
739
|
|
|
265
|
-
|
|
266
|
-
class User extends Model {
|
|
267
|
-
endpoint() {
|
|
268
|
-
return '/users';
|
|
269
|
-
}
|
|
270
|
-
}
|
|
740
|
+
Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<void>** A promise that resolves when the delete operation completes
|
|
271
741
|
|
|
272
|
-
|
|
273
|
-
const user = new User({ name: 'John', email: 'john@example.com' });
|
|
274
|
-
await user.save();
|
|
742
|
+
#### toJSON
|
|
275
743
|
|
|
276
|
-
|
|
277
|
-
const existingUser = new User({ id: 1 });
|
|
278
|
-
await existingUser.fetch();
|
|
744
|
+
Returns a plain JavaScript object representation of the model's attributes.
|
|
279
745
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
746
|
+
This method creates a shallow copy of the model's internal attributes, returning
|
|
747
|
+
them as a plain object. This is useful for serialization, debugging, or when you
|
|
748
|
+
need to pass the model's data to functions that expect plain objects rather than
|
|
749
|
+
model instances.
|
|
750
|
+
|
|
751
|
+
The returned object is a copy, so modifications to it will not affect the original
|
|
752
|
+
model's attributes. This method is commonly used internally by other model methods
|
|
753
|
+
(like save()) when preparing data for HTTP requests.
|
|
754
|
+
|
|
755
|
+
##### Examples
|
|
283
756
|
|
|
284
|
-
|
|
285
|
-
|
|
757
|
+
```javascript
|
|
758
|
+
// Get plain object representation
|
|
759
|
+
const user = new User({ id: 1, name: 'John', email: 'john@example.com' });
|
|
760
|
+
const userData = user.toJSON();
|
|
761
|
+
// Returns: { id: 1, name: 'John', email: 'john@example.com' }
|
|
762
|
+
|
|
763
|
+
// Useful for serialization
|
|
764
|
+
const jsonString = JSON.stringify(user.toJSON());
|
|
286
765
|
```
|
|
287
766
|
|
|
288
|
-
|
|
767
|
+
Returns **T** A plain object containing all of the model's attributes
|
|
289
768
|
|
|
290
|
-
|
|
769
|
+
### Collection
|
|
291
770
|
|
|
292
|
-
|
|
771
|
+
Abstract base class for managing collections of Model instances.
|
|
293
772
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
773
|
+
Provides a reactive collection that can be populated with data, fetched from a server,
|
|
774
|
+
and manipulated with type-safe operations. The collection is backed by Svelte's reactivity
|
|
775
|
+
system for automatic UI updates.
|
|
297
776
|
|
|
298
|
-
|
|
777
|
+
#### Parameters
|
|
299
778
|
|
|
300
|
-
|
|
779
|
+
- `models` Optional array of data objects to initialize the collection with (optional, default `[]`)
|
|
301
780
|
|
|
302
|
-
|
|
781
|
+
#### Examples
|
|
303
782
|
|
|
304
|
-
|
|
783
|
+
```javascript
|
|
784
|
+
class UserCollection extends Collection<UserModel, User> {
|
|
785
|
+
model = UserModel;
|
|
786
|
+
endpoint = () => '/api/users';
|
|
787
|
+
}
|
|
305
788
|
|
|
306
|
-
|
|
307
|
-
|
|
789
|
+
const users = new UserCollection();
|
|
790
|
+
await users.fetch(); // Loads users from API
|
|
791
|
+
users.add({ name: 'John', email: 'john@example.com' }); // Adds new user
|
|
792
|
+
```
|
|
308
793
|
|
|
309
|
-
####
|
|
794
|
+
#### items
|
|
310
795
|
|
|
311
|
-
|
|
796
|
+
Reactive array of model instances in the collection
|
|
312
797
|
|
|
313
|
-
|
|
314
|
-
- `endpoint()` - Function that returns the API endpoint URL
|
|
798
|
+
#### length
|
|
315
799
|
|
|
316
|
-
|
|
800
|
+
Gets the number of items in the collection
|
|
317
801
|
|
|
318
|
-
|
|
802
|
+
#### add
|
|
319
803
|
|
|
320
804
|
Adds a new item to the collection.
|
|
321
805
|
|
|
322
|
-
|
|
806
|
+
##### Parameters
|
|
323
807
|
|
|
324
|
-
- `data`
|
|
808
|
+
- `data` Either raw data of type T or an existing model instance of type M
|
|
325
809
|
|
|
326
|
-
|
|
810
|
+
##### Examples
|
|
327
811
|
|
|
328
812
|
```javascript
|
|
813
|
+
// Add raw data
|
|
329
814
|
const user = collection.add({ name: 'John', email: 'john@example.com' });
|
|
815
|
+
|
|
816
|
+
// Add existing model instance
|
|
817
|
+
const existingUser = new UserModel({ name: 'Jane' });
|
|
818
|
+
collection.add(existingUser);
|
|
330
819
|
```
|
|
331
820
|
|
|
332
|
-
|
|
821
|
+
Returns **any** The model instance that was added to the collection
|
|
822
|
+
|
|
823
|
+
#### reset
|
|
333
824
|
|
|
334
|
-
|
|
825
|
+
Resets the collection with new data, replacing all existing items.
|
|
335
826
|
|
|
336
|
-
|
|
827
|
+
##### Parameters
|
|
337
828
|
|
|
338
|
-
- `data`
|
|
829
|
+
- `data` An array of raw data objects to populate the collection with
|
|
830
|
+
|
|
831
|
+
##### Examples
|
|
339
832
|
|
|
340
833
|
```javascript
|
|
834
|
+
// Reset collection with new user data
|
|
341
835
|
collection.reset([
|
|
342
|
-
{ id: 1, name: 'John' },
|
|
343
|
-
{ id: 2, name: 'Jane' }
|
|
836
|
+
{ id: 1, name: 'John', email: 'john@example.com' },
|
|
837
|
+
{ id: 2, name: 'Jane', email: 'jane@example.com' }
|
|
344
838
|
]);
|
|
345
839
|
```
|
|
346
840
|
|
|
347
|
-
|
|
841
|
+
#### find
|
|
348
842
|
|
|
349
|
-
Finds the first item
|
|
843
|
+
Finds the first item in the collection that matches the given query.
|
|
350
844
|
|
|
351
|
-
|
|
845
|
+
##### Parameters
|
|
352
846
|
|
|
353
|
-
- `query`
|
|
847
|
+
- `query` An object containing key-value pairs to match against items in the collection.
|
|
848
|
+
Only items that match all specified properties will be returned.
|
|
354
849
|
|
|
355
|
-
|
|
850
|
+
##### Examples
|
|
356
851
|
|
|
357
852
|
```javascript
|
|
853
|
+
// Find a user by ID
|
|
358
854
|
const user = collection.find({ id: 123 });
|
|
855
|
+
|
|
856
|
+
// Find by multiple properties
|
|
359
857
|
const activeAdmin = collection.find({ role: 'admin', status: 'active' });
|
|
360
858
|
```
|
|
361
859
|
|
|
362
|
-
|
|
860
|
+
Returns **any** The first matching item, or undefined if no match is found.
|
|
861
|
+
|
|
862
|
+
#### fetch
|
|
363
863
|
|
|
364
864
|
Fetches data from the server and populates the collection.
|
|
365
865
|
|
|
366
|
-
|
|
866
|
+
##### Parameters
|
|
367
867
|
|
|
368
|
-
- `options
|
|
868
|
+
- `options` Configuration options for the fetch request (optional, default `{}`)
|
|
869
|
+
- `options.endpoint` Optional endpoint to use if different than this.endpoint()
|
|
870
|
+
- `options.search` Optional search parameters to include in the query string.
|
|
871
|
+
Keys and values will be converted to strings and URL-encoded.
|
|
369
872
|
|
|
370
|
-
|
|
873
|
+
##### Examples
|
|
371
874
|
|
|
372
875
|
```javascript
|
|
373
876
|
// Fetch all items
|
|
@@ -378,3 +881,5 @@ await collection.fetch({
|
|
|
378
881
|
search: { limit: 30, after: 29 }
|
|
379
882
|
});
|
|
380
883
|
```
|
|
884
|
+
|
|
885
|
+
- Throws **[Error](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error)** Throws an error if the HTTP request fails or returns a non-ok status
|