@jwerre/vellum 1.0.1 → 1.1.1
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 +694 -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 +37 -1
- package/dist/config.svelte.js +43 -3
- 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
|
@@ -15,7 +15,6 @@ export interface FetchOptions extends Partial<VellumConfig> {
|
|
|
15
15
|
* @template T - The data object type that the models represent
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
|
-
* ```typescript
|
|
19
18
|
* class UserCollection extends Collection<UserModel, User> {
|
|
20
19
|
* model = UserModel;
|
|
21
20
|
* endpoint = () => '/api/users';
|
|
@@ -24,7 +23,6 @@ export interface FetchOptions extends Partial<VellumConfig> {
|
|
|
24
23
|
* const users = new UserCollection();
|
|
25
24
|
* await users.fetch(); // Loads users from API
|
|
26
25
|
* users.add({ name: 'John', email: 'john@example.com' }); // Adds new user
|
|
27
|
-
* ```
|
|
28
26
|
*/
|
|
29
27
|
export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
30
28
|
/** Reactive array of model instances in the collection */
|
|
@@ -41,7 +39,6 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
|
41
39
|
* @param models - Optional array of data objects to initialize the collection with
|
|
42
40
|
*
|
|
43
41
|
* @example
|
|
44
|
-
* ```typescript
|
|
45
42
|
* // Create empty collection
|
|
46
43
|
* const collection = new UserCollection();
|
|
47
44
|
*
|
|
@@ -50,7 +47,6 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
|
50
47
|
* { id: 1, name: 'John' },
|
|
51
48
|
* { id: 2, name: 'Jane' }
|
|
52
49
|
* ]);
|
|
53
|
-
* ```
|
|
54
50
|
*/
|
|
55
51
|
constructor(models?: T[]);
|
|
56
52
|
/** Gets the number of items in the collection */
|
|
@@ -62,14 +58,12 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
|
62
58
|
* @returns The model instance that was added to the collection
|
|
63
59
|
*
|
|
64
60
|
* @example
|
|
65
|
-
* ```typescript
|
|
66
61
|
* // Add raw data
|
|
67
62
|
* const user = collection.add({ name: 'John', email: 'john@example.com' });
|
|
68
63
|
*
|
|
69
64
|
* // Add existing model instance
|
|
70
65
|
* const existingUser = new UserModel({ name: 'Jane' });
|
|
71
66
|
* collection.add(existingUser);
|
|
72
|
-
* ```
|
|
73
67
|
*/
|
|
74
68
|
add(data: T | M): M;
|
|
75
69
|
/**
|
|
@@ -78,13 +72,11 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
|
78
72
|
* @param data - An array of raw data objects to populate the collection with
|
|
79
73
|
*
|
|
80
74
|
* @example
|
|
81
|
-
* ```typescript
|
|
82
75
|
* // Reset collection with new user data
|
|
83
76
|
* collection.reset([
|
|
84
77
|
* { id: 1, name: 'John', email: 'john@example.com' },
|
|
85
78
|
* { id: 2, name: 'Jane', email: 'jane@example.com' }
|
|
86
79
|
* ]);
|
|
87
|
-
* ```
|
|
88
80
|
*/
|
|
89
81
|
reset(data: T[]): void;
|
|
90
82
|
/**
|
|
@@ -95,13 +87,11 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
|
95
87
|
* @returns The first matching item, or undefined if no match is found.
|
|
96
88
|
*
|
|
97
89
|
* @example
|
|
98
|
-
* ```typescript
|
|
99
90
|
* // Find a user by ID
|
|
100
91
|
* const user = collection.find({ id: 123 });
|
|
101
92
|
*
|
|
102
93
|
* // Find by multiple properties
|
|
103
94
|
* const activeAdmin = collection.find({ role: 'admin', status: 'active' });
|
|
104
|
-
* ```
|
|
105
95
|
*/
|
|
106
96
|
find(query: Partial<T>): M | undefined;
|
|
107
97
|
/**
|
|
@@ -115,7 +105,6 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
|
115
105
|
* @throws {Error} Throws an error if the HTTP request fails or returns a non-ok status
|
|
116
106
|
*
|
|
117
107
|
* @example
|
|
118
|
-
* ```typescript
|
|
119
108
|
* // Fetch all items
|
|
120
109
|
* await collection.fetch();
|
|
121
110
|
*
|
|
@@ -123,7 +112,6 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
|
|
|
123
112
|
* await collection.fetch({
|
|
124
113
|
* search: { limit: 30, after: 29 }
|
|
125
114
|
* });
|
|
126
|
-
* ```
|
|
127
115
|
*/
|
|
128
116
|
fetch(options?: FetchOptions): Promise<void>;
|
|
129
117
|
}
|
|
@@ -12,7 +12,6 @@ import { vellumConfig } from './config.svelte';
|
|
|
12
12
|
* @template T - The data object type that the models represent
|
|
13
13
|
*
|
|
14
14
|
* @example
|
|
15
|
-
* ```typescript
|
|
16
15
|
* class UserCollection extends Collection<UserModel, User> {
|
|
17
16
|
* model = UserModel;
|
|
18
17
|
* endpoint = () => '/api/users';
|
|
@@ -21,7 +20,6 @@ import { vellumConfig } from './config.svelte';
|
|
|
21
20
|
* const users = new UserCollection();
|
|
22
21
|
* await users.fetch(); // Loads users from API
|
|
23
22
|
* users.add({ name: 'John', email: 'john@example.com' }); // Adds new user
|
|
24
|
-
* ```
|
|
25
23
|
*/
|
|
26
24
|
export class Collection {
|
|
27
25
|
/** Reactive array of model instances in the collection */
|
|
@@ -32,7 +30,6 @@ export class Collection {
|
|
|
32
30
|
* @param models - Optional array of data objects to initialize the collection with
|
|
33
31
|
*
|
|
34
32
|
* @example
|
|
35
|
-
* ```typescript
|
|
36
33
|
* // Create empty collection
|
|
37
34
|
* const collection = new UserCollection();
|
|
38
35
|
*
|
|
@@ -41,7 +38,6 @@ export class Collection {
|
|
|
41
38
|
* { id: 1, name: 'John' },
|
|
42
39
|
* { id: 2, name: 'Jane' }
|
|
43
40
|
* ]);
|
|
44
|
-
* ```
|
|
45
41
|
*/
|
|
46
42
|
constructor(models = []) {
|
|
47
43
|
if (models.length > 0) {
|
|
@@ -59,14 +55,12 @@ export class Collection {
|
|
|
59
55
|
* @returns The model instance that was added to the collection
|
|
60
56
|
*
|
|
61
57
|
* @example
|
|
62
|
-
* ```typescript
|
|
63
58
|
* // Add raw data
|
|
64
59
|
* const user = collection.add({ name: 'John', email: 'john@example.com' });
|
|
65
60
|
*
|
|
66
61
|
* // Add existing model instance
|
|
67
62
|
* const existingUser = new UserModel({ name: 'Jane' });
|
|
68
63
|
* collection.add(existingUser);
|
|
69
|
-
* ```
|
|
70
64
|
*/
|
|
71
65
|
add(data) {
|
|
72
66
|
const instance = data instanceof Model ? data : new this.model(data);
|
|
@@ -79,13 +73,11 @@ export class Collection {
|
|
|
79
73
|
* @param data - An array of raw data objects to populate the collection with
|
|
80
74
|
*
|
|
81
75
|
* @example
|
|
82
|
-
* ```typescript
|
|
83
76
|
* // Reset collection with new user data
|
|
84
77
|
* collection.reset([
|
|
85
78
|
* { id: 1, name: 'John', email: 'john@example.com' },
|
|
86
79
|
* { id: 2, name: 'Jane', email: 'jane@example.com' }
|
|
87
80
|
* ]);
|
|
88
|
-
* ```
|
|
89
81
|
*/
|
|
90
82
|
reset(data) {
|
|
91
83
|
this.items = data.map((attrs) => new this.model(attrs));
|
|
@@ -98,13 +90,11 @@ export class Collection {
|
|
|
98
90
|
* @returns The first matching item, or undefined if no match is found.
|
|
99
91
|
*
|
|
100
92
|
* @example
|
|
101
|
-
* ```typescript
|
|
102
93
|
* // Find a user by ID
|
|
103
94
|
* const user = collection.find({ id: 123 });
|
|
104
95
|
*
|
|
105
96
|
* // Find by multiple properties
|
|
106
97
|
* const activeAdmin = collection.find({ role: 'admin', status: 'active' });
|
|
107
|
-
* ```
|
|
108
98
|
*/
|
|
109
99
|
find(query) {
|
|
110
100
|
return this.items.find((item) => {
|
|
@@ -124,7 +114,6 @@ export class Collection {
|
|
|
124
114
|
* @throws {Error} Throws an error if the HTTP request fails or returns a non-ok status
|
|
125
115
|
*
|
|
126
116
|
* @example
|
|
127
|
-
* ```typescript
|
|
128
117
|
* // Fetch all items
|
|
129
118
|
* await collection.fetch();
|
|
130
119
|
*
|
|
@@ -132,7 +121,6 @@ export class Collection {
|
|
|
132
121
|
* await collection.fetch({
|
|
133
122
|
* search: { limit: 30, after: 29 }
|
|
134
123
|
* });
|
|
135
|
-
* ```
|
|
136
124
|
*/
|
|
137
125
|
async fetch(options = {}) {
|
|
138
126
|
let query = '';
|
package/dist/Model.svelte.d.ts
CHANGED
|
@@ -1,7 +1,57 @@
|
|
|
1
1
|
import { type VellumConfig } from './config.svelte';
|
|
2
|
+
import { ValidationError } from './errors/validation_error.js';
|
|
2
3
|
export interface SyncOptions extends Partial<VellumConfig> {
|
|
3
4
|
endpoint?: string;
|
|
4
5
|
}
|
|
6
|
+
export interface ValidationOptions {
|
|
7
|
+
validate?: boolean;
|
|
8
|
+
silent?: boolean;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Abstract base class for creating model instances that interact with RESTful APIs.
|
|
13
|
+
*
|
|
14
|
+
* The Model class provides a structured way to manage data objects with full CRUD
|
|
15
|
+
* (Create, Read, Update, Delete) capabilities. It includes built-in HTTP synchronization,
|
|
16
|
+
* attribute management, and data validation features. This class is designed to work
|
|
17
|
+
* with Svelte's reactivity system using the `$state` rune for automatic UI updates.
|
|
18
|
+
*
|
|
19
|
+
* Key features:
|
|
20
|
+
* - Type-safe attribute access and manipulation
|
|
21
|
+
* - Automatic HTTP synchronization with RESTful APIs
|
|
22
|
+
* - Built-in HTML escaping for XSS prevention
|
|
23
|
+
* - Configurable ID attributes for different database schemas
|
|
24
|
+
* - Reactive attributes that integrate with Svelte's state management
|
|
25
|
+
* - Support for both single attribute and bulk attribute operations
|
|
26
|
+
*
|
|
27
|
+
* @template T - The type definition for the model's attributes, must extend object
|
|
28
|
+
* @abstract This class must be extended by concrete model implementations
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Define a User model
|
|
32
|
+
* interface UserAttributes {
|
|
33
|
+
* id?: number;
|
|
34
|
+
* name: string;
|
|
35
|
+
* email: string;
|
|
36
|
+
* createdAt?: Date;
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* class User extends Model<UserAttributes> {
|
|
40
|
+
* endpoint() {
|
|
41
|
+
* return '/users';
|
|
42
|
+
* }
|
|
43
|
+
* defaults() {
|
|
44
|
+
* return { name: '', createdAt: new Date() };
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* // Create and use a model instance
|
|
49
|
+
* const user = new User({ name: 'John Doe', email: 'john@example.com' });
|
|
50
|
+
* await user.save(); // Creates new user on server
|
|
51
|
+
* user.set('name', 'Jane Doe');
|
|
52
|
+
* await user.save(); // Updates existing user
|
|
53
|
+
* await user.destroy(); // Deletes user
|
|
54
|
+
*/
|
|
5
55
|
export declare abstract class Model<T extends object> {
|
|
6
56
|
#private;
|
|
7
57
|
/**
|
|
@@ -20,8 +70,73 @@ export declare abstract class Model<T extends object> {
|
|
|
20
70
|
* return '/users';
|
|
21
71
|
* }
|
|
22
72
|
*/
|
|
23
|
-
abstract endpoint(): string;
|
|
73
|
+
protected abstract endpoint(): string;
|
|
74
|
+
/**
|
|
75
|
+
* The name of the attribute that serves as the unique identifier for this model instance.
|
|
76
|
+
*
|
|
77
|
+
* This private field stores the attribute name that will be used to identify the model's
|
|
78
|
+
* primary key when performing operations like determining if the model is new, constructing
|
|
79
|
+
* URLs for API requests, and managing model identity. The default value is 'id', but it
|
|
80
|
+
* can be customized through the ModelOptions parameter in the constructor.
|
|
81
|
+
*
|
|
82
|
+
* @protected
|
|
83
|
+
* @type {string}
|
|
84
|
+
* @default 'id'
|
|
85
|
+
* @example
|
|
86
|
+
* // Default behavior uses 'id' as the identifier
|
|
87
|
+
* const user = new User({ id: 1, name: 'John' });
|
|
88
|
+
*
|
|
89
|
+
* // Custom ID attribute can be specified in constructor options
|
|
90
|
+
* class User extends Model<UserSchema> {
|
|
91
|
+
* idAttribute = '_id
|
|
92
|
+
* endpoint(): string {
|
|
93
|
+
* return '/users';
|
|
94
|
+
* }
|
|
95
|
+
* }
|
|
96
|
+
* const user = new User({ _id: '507f1f77bcf86cd799439011', name: 'John' });
|
|
97
|
+
*/
|
|
98
|
+
protected idAttribute: string;
|
|
99
|
+
/**
|
|
100
|
+
* Creates a new instance of Model.
|
|
101
|
+
*/
|
|
24
102
|
constructor(data?: Partial<T>);
|
|
103
|
+
/**
|
|
104
|
+
* Gets the latest validation error.
|
|
105
|
+
*
|
|
106
|
+
* @returns {ValidationError || undefined} An instance of ValidationError if validation failed, otherwise undefined
|
|
107
|
+
*/
|
|
108
|
+
get validationError(): ValidationError | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Provides default attribute values for new model instances.
|
|
111
|
+
*
|
|
112
|
+
* This method is called during model construction to establish initial attribute
|
|
113
|
+
* values before applying any user-provided data. Subclasses can override this
|
|
114
|
+
* method to define default values for their specific attributes, ensuring that
|
|
115
|
+
* models always have sensible initial state.
|
|
116
|
+
*
|
|
117
|
+
* The defaults are applied first, then any data passed to the constructor will
|
|
118
|
+
* override these default values. This allows for flexible model initialization
|
|
119
|
+
* where some attributes have fallback values while others can be explicitly set.
|
|
120
|
+
*
|
|
121
|
+
* @protected
|
|
122
|
+
* @returns {Partial<T>} A partial object containing default attribute values
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* // Override in a User model subclass
|
|
126
|
+
* protected defaults(): Partial<UserAttributes> {
|
|
127
|
+
* return {
|
|
128
|
+
* role: 'user',
|
|
129
|
+
* isActive: true,
|
|
130
|
+
* createdAt: new Date()
|
|
131
|
+
* };
|
|
132
|
+
* }
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Creating a model with defaults
|
|
136
|
+
* const user = new User({ name: 'John' });
|
|
137
|
+
* // Resulting attributes: { role: 'user', isActive: true, createdAt: Date, name: 'John' }
|
|
138
|
+
*/
|
|
139
|
+
protected defaults(): Partial<T>;
|
|
25
140
|
/**
|
|
26
141
|
* Retrieves the value of a specific attribute from the model.
|
|
27
142
|
*
|
|
@@ -47,21 +162,148 @@ export declare abstract class Model<T extends object> {
|
|
|
47
162
|
* shallow merge, meaning that only the top-level properties specified in the attrs
|
|
48
163
|
* parameter will be updated, while other existing attributes remain unchanged.
|
|
49
164
|
*
|
|
165
|
+
* The method supports optional validation through the ValidationOptions parameter.
|
|
166
|
+
* If validation is enabled and fails, the attributes will not be updated and the
|
|
167
|
+
* method will return false. The validationError property will be set with details
|
|
168
|
+
* about the validation failure.
|
|
169
|
+
*
|
|
170
|
+
* @overload
|
|
171
|
+
* @param {K} key - The attribute key to set
|
|
172
|
+
* @param {T[K]} value - The value to set for the specified key
|
|
173
|
+
* @param {ValidationOptions} [options] - Optional validation and behavior settings
|
|
174
|
+
* @param {boolean} [options.validate] - If true, validates attributes before setting them
|
|
175
|
+
* @param {boolean} [options.silent] - If true, suppresses validation error setting
|
|
176
|
+
* @returns {boolean} True if attributes were set successfully, false if validation failed
|
|
177
|
+
*
|
|
178
|
+
* @overload
|
|
50
179
|
* @param {Partial<T>} attrs - A partial object containing the attributes to update
|
|
180
|
+
* @param {ValidationOptions} [options] - Optional validation and behavior settings
|
|
181
|
+
* @param {boolean} [options.validate] - If true, validates attributes before setting them
|
|
182
|
+
* @param {boolean} [options.silent] - If true, suppresses validation error setting
|
|
183
|
+
* @returns {boolean} True if attributes were set successfully, false if validation failed
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* // Set a single attribute
|
|
187
|
+
* user.set('name', 'Jane');
|
|
188
|
+
*
|
|
189
|
+
* // Set multiple attributes
|
|
190
|
+
* user.set({ name: 'Jane', email: 'jane@example.com' });
|
|
191
|
+
*
|
|
192
|
+
* // Set with validation enabled
|
|
193
|
+
* const success = user.set({ email: 'invalid-email' }, { validate: true });
|
|
194
|
+
* if (!success) {
|
|
195
|
+
* console.log('Validation failed:', user.validationError);
|
|
196
|
+
* }
|
|
197
|
+
*
|
|
198
|
+
* // Set attributes silently without validation errors
|
|
199
|
+
* user.set({ name: '' }, { validate: true, silent: true });
|
|
200
|
+
*/
|
|
201
|
+
set<K extends keyof T>(key: K, value: T[K], options?: ValidationOptions): boolean;
|
|
202
|
+
set(attrs: Partial<T>, options?: ValidationOptions): boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Checks whether a specific attribute has a non-null, non-undefined value.
|
|
205
|
+
*
|
|
206
|
+
* This method provides a way to determine if an attribute exists and has a
|
|
207
|
+
* meaningful value. It returns true if the attribute is set to any value
|
|
208
|
+
* other than null or undefined, including falsy values like false, 0, or
|
|
209
|
+
* empty strings, which are considered valid values.
|
|
210
|
+
*
|
|
211
|
+
* @template K - The key type, constrained to keys of T
|
|
212
|
+
* @param {K} key - The attribute key to check
|
|
213
|
+
* @returns {boolean} True if the attribute has a non-null, non-undefined value
|
|
214
|
+
* @example
|
|
215
|
+
* // Assuming a User model with attributes { id: number, name: string, email?: string }
|
|
216
|
+
* const user = new User({ id: 1, name: 'John', email: null });
|
|
217
|
+
*
|
|
218
|
+
* user.has('id'); // Returns true (value is 1)
|
|
219
|
+
* user.has('name'); // Returns true (value is 'John')
|
|
220
|
+
* user.has('email'); // Returns false (value is null)
|
|
221
|
+
*
|
|
222
|
+
* // Even falsy values are considered "set"
|
|
223
|
+
* user.set({ name: '' });
|
|
224
|
+
* user.has('name'); // Returns true (empty string is a valid value)
|
|
225
|
+
*/
|
|
226
|
+
has<K extends keyof T>(key: K): boolean;
|
|
227
|
+
/**
|
|
228
|
+
* Removes a specific attribute from the model by deleting it from the internal attributes hash.
|
|
229
|
+
*
|
|
230
|
+
* This method permanently removes an attribute from the model instance. Once unset,
|
|
231
|
+
* the attribute will no longer exist on the model and subsequent calls to get() for
|
|
232
|
+
* that key will return undefined. This is different from setting an attribute to
|
|
233
|
+
* null or undefined, as the property is completely removed from the attributes object.
|
|
234
|
+
*
|
|
235
|
+
* @template K - The key type, constrained to keys of T
|
|
236
|
+
* @param {K} key - The attribute key to remove from the model
|
|
51
237
|
* @returns {void}
|
|
52
238
|
* @example
|
|
53
239
|
* // Assuming a User model with attributes { id: number, name: string, email: string }
|
|
54
240
|
* const user = new User({ id: 1, name: 'John', email: 'john@example.com' });
|
|
55
241
|
*
|
|
56
|
-
* //
|
|
242
|
+
* user.has('email'); // Returns true
|
|
243
|
+
* user.unset('email'); // Remove the email attribute
|
|
244
|
+
* user.has('email'); // Returns false
|
|
245
|
+
* user.get('email'); // Returns undefined
|
|
246
|
+
*
|
|
247
|
+
* // The attribute is completely removed, not just set to undefined
|
|
248
|
+
* const userData = user.toJSON(); // { id: 1, name: 'John' }
|
|
249
|
+
*/
|
|
250
|
+
unset<K extends keyof T>(key: K): void;
|
|
251
|
+
/**
|
|
252
|
+
* Removes all attributes from the model, including the id attribute.
|
|
253
|
+
*
|
|
254
|
+
* This method completely clears the model instance by removing all stored attributes,
|
|
255
|
+
* effectively resetting it to an empty state. After calling clear(), the model will
|
|
256
|
+
* behave as if it were newly instantiated with no data. This includes removing the
|
|
257
|
+
* ID attribute, which means the model will be considered "new" after clearing.
|
|
258
|
+
*
|
|
259
|
+
* This is useful when you want to reuse a model instance for different data or
|
|
260
|
+
* reset a model to its initial state without creating a new instance.
|
|
261
|
+
*
|
|
262
|
+
* @returns {void}
|
|
263
|
+
* @example
|
|
264
|
+
* // Clear all data from a user model
|
|
265
|
+
* const user = new User({ id: 1, name: 'John', email: 'john@example.com' });
|
|
266
|
+
* user.clear();
|
|
267
|
+
*
|
|
268
|
+
* user.has('id'); // Returns false
|
|
269
|
+
* user.has('name'); // Returns false
|
|
270
|
+
* user.isNew(); // Returns true
|
|
271
|
+
* user.toJSON(); // Returns {}
|
|
272
|
+
*
|
|
273
|
+
* // Model can be reused with new data
|
|
57
274
|
* user.set({ name: 'Jane', email: 'jane@example.com' });
|
|
58
|
-
|
|
275
|
+
*/
|
|
276
|
+
clear(): void;
|
|
277
|
+
/**
|
|
278
|
+
* Retrieves and escapes the HTML content of a specific attribute from the model.
|
|
279
|
+
*
|
|
280
|
+
* This method provides a safe way to access model attributes that may contain
|
|
281
|
+
* user-generated content or data that will be rendered in HTML contexts. It
|
|
282
|
+
* automatically applies HTML escaping to prevent XSS attacks and ensure safe
|
|
283
|
+
* rendering of potentially dangerous content.
|
|
284
|
+
*
|
|
285
|
+
* The method uses the escapeHTML utility function to convert special HTML
|
|
286
|
+
* characters (such as <, >, &, ", and ') into their corresponding HTML entities,
|
|
287
|
+
* making the content safe for direct insertion into HTML templates.
|
|
59
288
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
289
|
+
* @template K - The key type, constrained to keys of T
|
|
290
|
+
* @param {K} key - The attribute key to retrieve and escape the value for
|
|
291
|
+
* @returns {T[K]} The HTML-escaped value associated with the specified key
|
|
292
|
+
* @example
|
|
293
|
+
* // Assuming a Post model with attributes { id: number, title: string, content: string }
|
|
294
|
+
* const post = new Post({
|
|
295
|
+
* id: 1,
|
|
296
|
+
* title: 'Hello <script>alert("XSS")</script>',
|
|
297
|
+
* content: 'This is "safe" & secure content'
|
|
298
|
+
* });
|
|
299
|
+
*
|
|
300
|
+
* const safeTitle = post.escape('title');
|
|
301
|
+
* // Returns: 'Hello <script>alert("XSS")</script>'
|
|
302
|
+
*
|
|
303
|
+
* const safeContent = post.escape('content');
|
|
304
|
+
* // Returns: 'This is "safe" & secure content'
|
|
63
305
|
*/
|
|
64
|
-
|
|
306
|
+
escape<K extends keyof T>(key: K): string;
|
|
65
307
|
/**
|
|
66
308
|
* Determines whether this model instance is new (not yet persisted).
|
|
67
309
|
* A model is considered new if it doesn't have an 'id' or '_id' attribute.
|
|
@@ -69,6 +311,69 @@ export declare abstract class Model<T extends object> {
|
|
|
69
311
|
* @returns {boolean} true if the model is new, false if it has been persisted
|
|
70
312
|
*/
|
|
71
313
|
isNew(): boolean;
|
|
314
|
+
/**
|
|
315
|
+
* Validates the current model instance and returns whether it passes validation.
|
|
316
|
+
*
|
|
317
|
+
* This method performs validation on the model's current attributes using the
|
|
318
|
+
* validate() method defined by the subclass. It's a convenience method that
|
|
319
|
+
* allows you to check if a model is valid without having to manually call
|
|
320
|
+
* the validation logic.
|
|
321
|
+
*
|
|
322
|
+
* If validation fails, the validationError property will be set with details
|
|
323
|
+
* about what went wrong. If validation passes, validationError will be cleared.
|
|
324
|
+
*
|
|
325
|
+
* @param {ValidationOptions} [options] - Optional validation configuration
|
|
326
|
+
* @param {boolean} [options.silent] - If true, suppresses validation error setting
|
|
327
|
+
* @returns {boolean} True if the model passes validation, false otherwise
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* // Check if a user model is valid
|
|
331
|
+
* const user = new User({ name: '', email: 'invalid-email' });
|
|
332
|
+
*
|
|
333
|
+
* if (!user.isValid()) {
|
|
334
|
+
* console.log('Validation failed:', user.validationError);
|
|
335
|
+
* // Handle validation errors
|
|
336
|
+
* } else {
|
|
337
|
+
* // Proceed with saving or other operations
|
|
338
|
+
* await user.save();
|
|
339
|
+
* }
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* // Validate silently without setting validationError
|
|
343
|
+
* const isValid = user.isValid({ silent: true });
|
|
344
|
+
* // user.validationError remains unchanged
|
|
345
|
+
*/
|
|
346
|
+
isValid(options?: ValidationOptions): boolean;
|
|
347
|
+
/**
|
|
348
|
+
* Validates the model's attributes using custom validation logic.
|
|
349
|
+
*
|
|
350
|
+
* This method is intended to be overridden by subclasses to implement custom
|
|
351
|
+
* validation rules. By default, it returns undefined (no validation errors).
|
|
352
|
+
* If validation fails, this method should return an error - either a simple
|
|
353
|
+
* string message or a complete error object.
|
|
354
|
+
*
|
|
355
|
+
* The validate method is automatically called by save() before persisting data,
|
|
356
|
+
* and can also be explicitly called by set() when the {validate: true} option
|
|
357
|
+
* is passed. If validation fails, the save operation is aborted and model
|
|
358
|
+
* attributes are not modified.
|
|
359
|
+
*
|
|
360
|
+
* @param {Partial<T>} attributes - The attributes to validate
|
|
361
|
+
* @param {any} [options] - Additional options passed from set() or save()
|
|
362
|
+
* @returns {any} Returns undefined if valid, or an error (string/object) if invalid
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* // Override in a User model subclass
|
|
366
|
+
* validate(attributes: Partial<UserAttributes>) {
|
|
367
|
+
* if (!attributes.email) {
|
|
368
|
+
* return 'Email is required';
|
|
369
|
+
* }
|
|
370
|
+
* if (!attributes.email.includes('@')) {
|
|
371
|
+
* return { email: 'Invalid email format' };
|
|
372
|
+
* }
|
|
373
|
+
* // Return undefined if validation passes
|
|
374
|
+
* }
|
|
375
|
+
*/
|
|
376
|
+
validate(attributes: Partial<T>, options?: ValidationOptions): string | undefined;
|
|
72
377
|
/**
|
|
73
378
|
* Performs HTTP synchronization with the server for CRUD operations.
|
|
74
379
|
*
|
|
@@ -138,7 +443,13 @@ export declare abstract class Model<T extends object> {
|
|
|
138
443
|
* generates additional fields (like timestamps, computed values, or normalized data)
|
|
139
444
|
* during the save process.
|
|
140
445
|
*
|
|
141
|
-
* @
|
|
446
|
+
* @param {ValidationOptions & SyncOptions} [options] - Optional configuration for save behavior
|
|
447
|
+
* @param {boolean} [options.validate] - Whether to validate before saving (defaults to true)
|
|
448
|
+
* @param {boolean} [options.silent] - If true, suppresses validation error setting
|
|
449
|
+
* @param {string} [options.endpoint] - Override the default endpoint for this save operation
|
|
450
|
+
* @param {Record<string, string>} [options.headers] - Additional headers to include in the request
|
|
451
|
+
* @param {string} [options.origin] - Override the base URL origin for this request
|
|
452
|
+
* @returns {Promise<boolean>} A promise that resolves to true if save succeeds, false if validation fails
|
|
142
453
|
* @throws {Error} Throws an error if the HTTP request fails or server returns an error
|
|
143
454
|
*
|
|
144
455
|
* @example
|
|
@@ -149,8 +460,17 @@ export declare abstract class Model<T extends object> {
|
|
|
149
460
|
* // Update an existing user
|
|
150
461
|
* existingUser.set({ name: 'Jane' });
|
|
151
462
|
* await existingUser.save(); // PUT request with updated data
|
|
463
|
+
*
|
|
464
|
+
* // Save without validation
|
|
465
|
+
* await user.save({ validate: false });
|
|
466
|
+
*
|
|
467
|
+
* // Save with custom endpoint and headers
|
|
468
|
+
* await user.save({
|
|
469
|
+
* endpoint: '/api/v2/users',
|
|
470
|
+
* headers: { 'Custom-Header': 'value' }
|
|
471
|
+
* });
|
|
152
472
|
*/
|
|
153
|
-
save(): Promise<
|
|
473
|
+
save(options?: ValidationOptions & SyncOptions): Promise<boolean>;
|
|
154
474
|
/**
|
|
155
475
|
* Deletes the model from the server.
|
|
156
476
|
*
|