@statezero/core 0.1.37 → 0.1.38

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.
@@ -35,6 +35,14 @@ export class Model {
35
35
  * @throws {ValidationError} If an unknown key is found.
36
36
  */
37
37
  static validateFields(data: Object): void;
38
+ /**
39
+ * Static method to validate data without creating an instance
40
+ * @param {Object} data - Data to validate
41
+ * @param {string} validateType - 'create' or 'update'
42
+ * @param {boolean} partial - Whether to allow partial validation
43
+ * @returns {Promise<boolean>} Promise that resolves to true if valid, throws error if invalid
44
+ */
45
+ static validate(data: Object, validateType?: string, partial?: boolean): Promise<boolean>;
38
46
  constructor(data?: {});
39
47
  _data: {};
40
48
  _pk: any;
@@ -105,6 +113,13 @@ export class Model {
105
113
  * @throws {Error} If the instance has not been saved (no primary key).
106
114
  */
107
115
  refreshFromDb(): Promise<void>;
116
+ /**
117
+ * Validates the model instance using the same serialize behavior as save()
118
+ * @param {string} validateType - 'create' or 'update' (defaults to auto-detect)
119
+ * @param {boolean} partial - Whether to allow partial validation
120
+ * @returns {Promise<boolean>} Promise that resolves to true if valid, throws error if invalid
121
+ */
122
+ validate(validateType?: string, partial?: boolean): Promise<boolean>;
108
123
  }
109
124
  /**
110
125
  * A constructor for a Model.
@@ -10,6 +10,9 @@ import { QueryExecutor } from "./queryExecutor";
10
10
  import { wrapReactiveModel } from "../../reactiveAdaptor.js";
11
11
  import { DateParsingHelpers } from "./dates.js";
12
12
  import { FileObject } from './files.js';
13
+ import { configInstance } from "../../config.js";
14
+ import { parseStateZeroError, MultipleObjectsReturned, DoesNotExist, } from "./errors.js";
15
+ import axios from "axios";
13
16
  /**
14
17
  * A constructor for a Model.
15
18
  *
@@ -292,6 +295,74 @@ export class Model {
292
295
  // clear the current data and fresh data will flow
293
296
  this._data = {};
294
297
  }
298
+ /**
299
+ * Validates the model instance using the same serialize behavior as save()
300
+ * @param {string} validateType - 'create' or 'update' (defaults to auto-detect)
301
+ * @param {boolean} partial - Whether to allow partial validation
302
+ * @returns {Promise<boolean>} Promise that resolves to true if valid, throws error if invalid
303
+ */
304
+ async validate(validateType = null, partial = false) {
305
+ const ModelClass = this.constructor;
306
+ if (!validateType) {
307
+ validateType = this.pk ? "update" : "create";
308
+ }
309
+ // Validate the validateType parameter
310
+ if (!["update", "create"].includes(validateType)) {
311
+ throw new Error(`Validation type must be 'update' or 'create', not '${validateType}'`);
312
+ }
313
+ // Use the same serialize logic as save()
314
+ const data = this.serialize();
315
+ // Delegate to static method
316
+ return ModelClass.validate(data, validateType, partial);
317
+ }
318
+ /**
319
+ * Static method to validate data without creating an instance
320
+ * @param {Object} data - Data to validate
321
+ * @param {string} validateType - 'create' or 'update'
322
+ * @param {boolean} partial - Whether to allow partial validation
323
+ * @returns {Promise<boolean>} Promise that resolves to true if valid, throws error if invalid
324
+ */
325
+ static async validate(data, validateType = "create", partial = false) {
326
+ const ModelClass = this;
327
+ // Validate the validateType parameter
328
+ if (!["update", "create"].includes(validateType)) {
329
+ throw new Error(`Validation type must be 'update' or 'create', not '${validateType}'`);
330
+ }
331
+ // Get backend config and check if it exists
332
+ const config = configInstance.getConfig();
333
+ const backend = config.backendConfigs[ModelClass.configKey];
334
+ if (!backend) {
335
+ throw new Error(`No backend configuration found for key: ${ModelClass.configKey}`);
336
+ }
337
+ // Build URL for validate endpoint
338
+ const baseUrl = backend.API_URL.replace(/\/+$/, "");
339
+ const url = `${baseUrl}/${ModelClass.modelName}/validate/`;
340
+ // Prepare headers
341
+ const headers = {
342
+ "Content-Type": "application/json",
343
+ ...(backend.getAuthHeaders ? backend.getAuthHeaders() : {}),
344
+ };
345
+ // Make direct API call to validate endpoint
346
+ try {
347
+ const response = await axios.post(url, {
348
+ data: data,
349
+ validate_type: validateType,
350
+ partial: partial,
351
+ }, { headers });
352
+ // Backend returns {"valid": true} on success
353
+ return response.data.valid === true;
354
+ }
355
+ catch (error) {
356
+ if (error.response && error.response.data) {
357
+ const parsedError = parseStateZeroError(error.response.data);
358
+ if (Error.captureStackTrace) {
359
+ Error.captureStackTrace(parsedError, ModelClass.validate);
360
+ }
361
+ throw parsedError;
362
+ }
363
+ throw new Error(`Validation failed: ${error.message}`);
364
+ }
365
+ }
295
366
  }
296
367
  /**
297
368
  * Creates a new Model instance.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statezero/core",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "type": "module",
5
5
  "module": "ESNext",
6
6
  "description": "The type-safe frontend client for StateZero - connect directly to your backend models with zero boilerplate",