@vidyano-labs/virtual-service 0.1.0 → 0.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.
Files changed (3) hide show
  1. package/index.d.ts +68 -55
  2. package/index.js +38 -14
  3. package/package.json +2 -2
package/index.d.ts CHANGED
@@ -1,5 +1,58 @@
1
1
  import { Dto, ServiceHooks, Service, Application } from '@vidyano/core';
2
2
 
3
+ /**
4
+ * VirtualPersistentObjectAttribute combines a PersistentObjectAttributeDto with helper methods
5
+ * This allows clean syntax like attr.getValue() and attr.setValue() while keeping the underlying DTO unchanged
6
+ */
7
+ type VirtualPersistentObjectAttribute = Dto.PersistentObjectAttributeDto & {
8
+ /**
9
+ * Gets the converted value of this attribute (e.g., Boolean as boolean, Int32 as number)
10
+ */
11
+ getValue(): any;
12
+ /**
13
+ * Sets the value of this attribute with automatic type conversion
14
+ */
15
+ setValue(value: any): void;
16
+ /**
17
+ * Sets a validation error on this attribute
18
+ */
19
+ setValidationError(error: string): void;
20
+ /**
21
+ * Clears the validation error on this attribute
22
+ */
23
+ clearValidationError(): void;
24
+ };
25
+ /**
26
+ * VirtualPersistentObject combines a PersistentObjectDto with helper methods
27
+ * This allows clean syntax like obj.setAttributeValue() while keeping the underlying DTO unchanged
28
+ */
29
+ type VirtualPersistentObject = Dto.PersistentObjectDto & {
30
+ /**
31
+ * Gets an attribute by name, wrapped with getValue/setValue methods
32
+ */
33
+ getAttribute(name: string): VirtualPersistentObjectAttribute | undefined;
34
+ /**
35
+ * Gets the value of an attribute by name
36
+ */
37
+ getAttributeValue(name: string): any;
38
+ /**
39
+ * Sets the value of an attribute by name
40
+ */
41
+ setAttributeValue(name: string, value: any): void;
42
+ /**
43
+ * Sets a validation error for an attribute
44
+ */
45
+ setValidationError(name: string, error: string): void;
46
+ /**
47
+ * Clears a validation error for an attribute
48
+ */
49
+ clearValidationError(name: string): void;
50
+ /**
51
+ * Sets a notification message on the persistent object
52
+ */
53
+ setNotification(message: string, type: Dto.NotificationType, duration?: number): void;
54
+ };
55
+
3
56
  /**
4
57
  * Simplified attribute configuration - converted to PersistentObjectAttributeDto
5
58
  */
@@ -184,6 +237,19 @@ type ActionContext = {
184
237
  */
185
238
  setNotification: (message: string, type: Dto.NotificationType, duration?: number) => void;
186
239
  };
240
+ /**
241
+ * Context provided to business rule validators for accessing the persistent object
242
+ */
243
+ type RuleValidationContext = {
244
+ /**
245
+ * The persistent object being validated (wrapped with helper methods)
246
+ */
247
+ persistentObject: VirtualPersistentObject;
248
+ /**
249
+ * The attribute being validated (wrapped with helper methods)
250
+ */
251
+ attribute: VirtualPersistentObjectAttribute;
252
+ };
187
253
  /**
188
254
  * PersistentObject configuration - converted to PersistentObjectDto
189
255
  */
@@ -286,60 +352,7 @@ type VirtualQueryConfig = {
286
352
  /**
287
353
  * Rule validator function that throws an error if invalid, or returns nothing if valid
288
354
  */
289
- type RuleValidatorFn = (value: any, ...params: any[]) => void;
290
-
291
- /**
292
- * VirtualPersistentObjectAttribute combines a PersistentObjectAttributeDto with helper methods
293
- * This allows clean syntax like attr.getValue() and attr.setValue() while keeping the underlying DTO unchanged
294
- */
295
- type VirtualPersistentObjectAttribute = Dto.PersistentObjectAttributeDto & {
296
- /**
297
- * Gets the converted value of this attribute (e.g., Boolean as boolean, Int32 as number)
298
- */
299
- getValue(): any;
300
- /**
301
- * Sets the value of this attribute with automatic type conversion
302
- */
303
- setValue(value: any): void;
304
- /**
305
- * Sets a validation error on this attribute
306
- */
307
- setValidationError(error: string): void;
308
- /**
309
- * Clears the validation error on this attribute
310
- */
311
- clearValidationError(): void;
312
- };
313
- /**
314
- * VirtualPersistentObject combines a PersistentObjectDto with helper methods
315
- * This allows clean syntax like obj.setAttributeValue() while keeping the underlying DTO unchanged
316
- */
317
- type VirtualPersistentObject = Dto.PersistentObjectDto & {
318
- /**
319
- * Gets an attribute by name, wrapped with getValue/setValue methods
320
- */
321
- getAttribute(name: string): VirtualPersistentObjectAttribute | undefined;
322
- /**
323
- * Gets the value of an attribute by name
324
- */
325
- getAttributeValue(name: string): any;
326
- /**
327
- * Sets the value of an attribute by name
328
- */
329
- setAttributeValue(name: string, value: any): void;
330
- /**
331
- * Sets a validation error for an attribute
332
- */
333
- setValidationError(name: string, error: string): void;
334
- /**
335
- * Clears a validation error for an attribute
336
- */
337
- clearValidationError(name: string): void;
338
- /**
339
- * Sets a notification message on the persistent object
340
- */
341
- setNotification(message: string, type: Dto.NotificationType, duration?: number): void;
342
- };
355
+ type RuleValidatorFn = (value: any, context: RuleValidationContext, ...params: any[]) => void;
343
356
 
344
357
  /**
345
358
  * Base class for PersistentObject lifecycle methods
@@ -556,4 +569,4 @@ declare class VirtualService extends Service {
556
569
  }
557
570
 
558
571
  export { VirtualPersistentObjectActions, VirtualService, VirtualServiceHooks };
559
- export type { ActionArgs, ActionConfig, ActionContext, ActionHandler, RuleValidatorFn, VirtualPersistentObject, VirtualPersistentObjectAttribute, VirtualPersistentObjectAttributeConfig, VirtualPersistentObjectConfig, VirtualQueryConfig, VirtualQueryExecuteResult };
572
+ export type { ActionArgs, ActionConfig, ActionContext, ActionHandler, RuleValidationContext, RuleValidatorFn, VirtualPersistentObject, VirtualPersistentObjectAttribute, VirtualPersistentObjectAttributeConfig, VirtualPersistentObjectConfig, VirtualQueryConfig, VirtualQueryExecuteResult };
package/index.js CHANGED
@@ -226,7 +226,7 @@ class VirtualPersistentObjectRegistry {
226
226
  isRequired: attrConfig.isRequired || false
227
227
  };
228
228
  // Validate the attribute
229
- const error = this.#validator.validateAttribute(attrWithRules);
229
+ const error = this.#validator.validateAttribute(attrWithRules, po);
230
230
  if (error) {
231
231
  attr.validationError = error;
232
232
  hasErrors = true;
@@ -1234,13 +1234,33 @@ class BusinessRuleValidator {
1234
1234
  }
1235
1235
  /**
1236
1236
  * Validate an attribute against its rules
1237
+ * @param attr - The attribute to validate
1238
+ * @param po - The persistent object containing the attribute
1237
1239
  * @returns Error message if validation fails, null if valid
1238
1240
  */
1239
- validateAttribute(attr) {
1241
+ validateAttribute(attr, po) {
1242
+ // Create conversion context for wrappers
1243
+ const conversionContext = {
1244
+ getConvertedValue: (attribute) => this.#getConvertedValue(attribute),
1245
+ setConvertedValue: (attribute, value) => {
1246
+ attribute.value = toServiceValue(value, attribute.type);
1247
+ attribute.isValueChanged = true;
1248
+ }
1249
+ };
1250
+ // Create wrapped objects for the validation context
1251
+ const wrappedPo = createVirtualPersistentObject(po, conversionContext);
1252
+ const wrappedAttr = createVirtualPersistentObjectAttribute(attr, conversionContext);
1253
+ // Create validation context
1254
+ const context = {
1255
+ persistentObject: wrappedPo,
1256
+ attribute: wrappedAttr
1257
+ };
1258
+ // Get the converted value (e.g., boolean from "True"/"False", number from string)
1259
+ const convertedValue = this.#getConvertedValue(attr);
1240
1260
  // Check isRequired first
1241
1261
  if (attr.isRequired) {
1242
1262
  try {
1243
- this.#validateNotEmpty(attr.value);
1263
+ this.#validateNotEmpty(convertedValue, context);
1244
1264
  }
1245
1265
  catch (error) {
1246
1266
  return error instanceof Error ? error.message : String(error);
@@ -1255,7 +1275,7 @@ class BusinessRuleValidator {
1255
1275
  if (!validator)
1256
1276
  throw new Error(`Unknown business rule: ${rule.name}`);
1257
1277
  try {
1258
- validator(attr.value, ...rule.params);
1278
+ validator(convertedValue, context, ...rule.params);
1259
1279
  }
1260
1280
  catch (error) {
1261
1281
  return error instanceof Error ? error.message : String(error);
@@ -1308,15 +1328,19 @@ class BusinessRuleValidator {
1308
1328
  });
1309
1329
  return { name, params };
1310
1330
  }
1331
+ // Helper to convert attribute values based on type
1332
+ #getConvertedValue(attr) {
1333
+ return fromServiceValue(attr.value, attr.type);
1334
+ }
1311
1335
  // Built-in validators - throw errors instead of returning strings
1312
- #validateIsBase64(value) {
1336
+ #validateIsBase64(value, context) {
1313
1337
  if (value == null || value === "")
1314
1338
  return;
1315
1339
  const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
1316
1340
  if (!base64Regex.test(String(value)))
1317
1341
  throw new Error("Value must be a valid base64 string");
1318
1342
  }
1319
- #validateIsEmail(value) {
1343
+ #validateIsEmail(value, context) {
1320
1344
  if (value == null || value === "")
1321
1345
  return;
1322
1346
  // Only allow ASCII characters in email addresses
@@ -1324,7 +1348,7 @@ class BusinessRuleValidator {
1324
1348
  if (!emailRegex.test(String(value)))
1325
1349
  throw new Error("Email format is invalid");
1326
1350
  }
1327
- #validateIsRegex(value) {
1351
+ #validateIsRegex(value, context) {
1328
1352
  if (value == null || value === "")
1329
1353
  return;
1330
1354
  try {
@@ -1334,7 +1358,7 @@ class BusinessRuleValidator {
1334
1358
  throw new Error("Value must be a valid regular expression");
1335
1359
  }
1336
1360
  }
1337
- #validateIsUrl(value) {
1361
+ #validateIsUrl(value, context) {
1338
1362
  if (value == null || value === "")
1339
1363
  return;
1340
1364
  try {
@@ -1344,21 +1368,21 @@ class BusinessRuleValidator {
1344
1368
  throw new Error("Value must be a valid URL");
1345
1369
  }
1346
1370
  }
1347
- #validateIsWord(value) {
1371
+ #validateIsWord(value, context) {
1348
1372
  if (value == null || value === "")
1349
1373
  return;
1350
1374
  const wordRegex = /^\w+$/;
1351
1375
  if (!wordRegex.test(String(value)))
1352
1376
  throw new Error("Value must contain only word characters");
1353
1377
  }
1354
- #validateMaxLength(value, maxLength) {
1378
+ #validateMaxLength(value, context, maxLength) {
1355
1379
  if (value == null || value === "")
1356
1380
  return;
1357
1381
  const length = String(value).length;
1358
1382
  if (length > maxLength)
1359
1383
  throw new Error(`Maximum length is ${maxLength} characters`);
1360
1384
  }
1361
- #validateMaxValue(value, maximum) {
1385
+ #validateMaxValue(value, context, maximum) {
1362
1386
  if (value == null || value === "")
1363
1387
  return;
1364
1388
  const num = Number(value);
@@ -1367,14 +1391,14 @@ class BusinessRuleValidator {
1367
1391
  if (num > maximum)
1368
1392
  throw new Error(`Maximum value is ${maximum}`);
1369
1393
  }
1370
- #validateMinLength(value, minLength) {
1394
+ #validateMinLength(value, context, minLength) {
1371
1395
  if (value == null || value === "")
1372
1396
  return;
1373
1397
  const length = String(value).length;
1374
1398
  if (length < minLength)
1375
1399
  throw new Error(`Minimum length is ${minLength} characters`);
1376
1400
  }
1377
- #validateMinValue(value, minimum) {
1401
+ #validateMinValue(value, context, minimum) {
1378
1402
  if (value == null || value === "")
1379
1403
  return;
1380
1404
  const num = Number(value);
@@ -1383,7 +1407,7 @@ class BusinessRuleValidator {
1383
1407
  if (num < minimum)
1384
1408
  throw new Error(`Minimum value is ${minimum}`);
1385
1409
  }
1386
- #validateNotEmpty(value) {
1410
+ #validateNotEmpty(value, context) {
1387
1411
  if (value == null || value === "" || (typeof value === "string" && value.trim() === ""))
1388
1412
  throw new Error("This field is required");
1389
1413
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vidyano-labs/virtual-service",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Virtual service implementation for testing Vidyano applications",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -20,5 +20,5 @@
20
20
  "publishConfig": {
21
21
  "access": "public"
22
22
  },
23
- "gitHash": "d6564e9eb23cc8e31609a91945e4ae852ad0b2d9"
23
+ "gitHash": "c69d76d2dd9e0289838ca50f1cc89a81fa9a89c3"
24
24
  }