@api-client/core 0.18.24 → 0.18.26
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/build/src/modeling/DomainEntity.d.ts +6 -1
- package/build/src/modeling/DomainEntity.d.ts.map +1 -1
- package/build/src/modeling/DomainEntity.js +24 -5
- package/build/src/modeling/DomainEntity.js.map +1 -1
- package/build/src/modeling/Semantics.d.ts +254 -0
- package/build/src/modeling/Semantics.d.ts.map +1 -1
- package/build/src/modeling/Semantics.js +328 -0
- package/build/src/modeling/Semantics.js.map +1 -1
- package/build/src/modeling/definitions/Email.js +1 -1
- package/build/src/modeling/definitions/Email.js.map +1 -1
- package/build/src/modeling/definitions/Password.d.ts.map +1 -1
- package/build/src/modeling/definitions/Password.js +1 -3
- package/build/src/modeling/definitions/Password.js.map +1 -1
- package/build/src/modeling/helpers/Intelisense.d.ts +7 -7
- package/build/src/modeling/helpers/Intelisense.d.ts.map +1 -1
- package/build/src/modeling/helpers/Intelisense.js +24 -58
- package/build/src/modeling/helpers/Intelisense.js.map +1 -1
- package/build/src/modeling/templates/meta/blog-publishing-platform.json +1 -1
- package/build/src/modeling/templates/meta/financial-services-platform.json +1 -1
- package/build/src/modeling/templates/meta/index.d.ts +1 -1
- package/build/src/modeling/templates/meta/index.js +1 -1
- package/build/src/modeling/templates/meta/index.js.map +1 -1
- package/build/src/modeling/templates/meta/iot-smart-home-platform.json +1 -1
- package/build/src/modeling/templates/verticals/business-services/financial-services-domain.d.ts.map +1 -1
- package/build/src/modeling/templates/verticals/business-services/financial-services-domain.js +248 -63
- package/build/src/modeling/templates/verticals/business-services/financial-services-domain.js.map +1 -1
- package/build/src/modeling/templates/verticals/technology-media/blog-domain.js +5 -5
- package/build/src/modeling/templates/verticals/technology-media/blog-domain.js.map +1 -1
- package/build/src/modeling/templates/verticals/technology-media/iot-smart-home-domain.d.ts.map +1 -1
- package/build/src/modeling/templates/verticals/technology-media/iot-smart-home-domain.js +2 -0
- package/build/src/modeling/templates/verticals/technology-media/iot-smart-home-domain.js.map +1 -1
- package/build/src/modeling/validation/postgresql.d.ts.map +1 -1
- package/build/src/modeling/validation/postgresql.js +0 -1
- package/build/src/modeling/validation/postgresql.js.map +1 -1
- package/build/src/runtime/modeling/Semantics.d.ts +84 -0
- package/build/src/runtime/modeling/Semantics.d.ts.map +1 -0
- package/build/src/runtime/modeling/Semantics.js +124 -0
- package/build/src/runtime/modeling/Semantics.js.map +1 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +8 -8
- package/package.json +1 -1
- package/src/modeling/DomainEntity.ts +27 -5
- package/src/modeling/Semantics.ts +493 -0
- package/src/modeling/definitions/Email.ts +1 -1
- package/src/modeling/definitions/Password.ts +1 -3
- package/src/modeling/helpers/Intelisense.ts +33 -65
- package/src/modeling/templates/meta/blog-publishing-platform.json +1 -1
- package/src/modeling/templates/meta/financial-services-platform.json +1 -1
- package/src/modeling/templates/meta/iot-smart-home-platform.json +1 -1
- package/src/modeling/templates/verticals/business-services/financial-services-domain.ts +285 -65
- package/src/modeling/templates/verticals/technology-media/blog-domain.ts +5 -5
- package/src/modeling/templates/verticals/technology-media/iot-smart-home-domain.ts +2 -0
- package/src/modeling/validation/postgresql.ts +0 -1
- package/src/runtime/modeling/Semantics.ts +196 -0
- package/tests/unit/modeling/client_ip_address_semantic.spec.ts +71 -0
- package/tests/unit/modeling/definitions/password.spec.ts +0 -2
- package/tests/unit/modeling/domain_entity_parents.spec.ts +243 -0
- package/tests/unit/modeling/semantic_runtime.spec.ts +113 -0
- package/tests/unit/modeling/semantics.spec.ts +68 -0
|
@@ -169,6 +169,12 @@ export var SemanticType;
|
|
|
169
169
|
* Annotates a field as derived from other fields.
|
|
170
170
|
*/
|
|
171
171
|
SemanticType["Derived"] = "Semantic#Derived";
|
|
172
|
+
/**
|
|
173
|
+
* Annotates a field that should automatically receive the client's IP address.
|
|
174
|
+
* The runtime automatically populates this field with the request's IP address
|
|
175
|
+
* when creating or updating records, providing audit trail and geolocation capabilities.
|
|
176
|
+
*/
|
|
177
|
+
SemanticType["ClientIPAddress"] = "Semantic#ClientIPAddress";
|
|
172
178
|
//
|
|
173
179
|
// Association-Level Semantics
|
|
174
180
|
//
|
|
@@ -254,6 +260,100 @@ export var SemanticCategory;
|
|
|
254
260
|
*/
|
|
255
261
|
SemanticCategory["Computed"] = "Computed Values";
|
|
256
262
|
})(SemanticCategory || (SemanticCategory = {}));
|
|
263
|
+
/**
|
|
264
|
+
* Defines when a semantic should execute in relation to database operations.
|
|
265
|
+
*/
|
|
266
|
+
export var SemanticTiming;
|
|
267
|
+
(function (SemanticTiming) {
|
|
268
|
+
/**
|
|
269
|
+
* Execute before the database operation (validation, preprocessing)
|
|
270
|
+
*/
|
|
271
|
+
SemanticTiming["Before"] = "Before";
|
|
272
|
+
/**
|
|
273
|
+
* Execute after the database operation (cleanup, notifications, derived values)
|
|
274
|
+
*/
|
|
275
|
+
SemanticTiming["After"] = "After";
|
|
276
|
+
/**
|
|
277
|
+
* Execute both before and after the operation
|
|
278
|
+
*/
|
|
279
|
+
SemanticTiming["Both"] = "Both";
|
|
280
|
+
/**
|
|
281
|
+
* No automatic execution (manual/on-demand only)
|
|
282
|
+
*/
|
|
283
|
+
SemanticTiming["None"] = "None";
|
|
284
|
+
})(SemanticTiming || (SemanticTiming = {}));
|
|
285
|
+
/**
|
|
286
|
+
* Defines which database operations can trigger a semantic.
|
|
287
|
+
*/
|
|
288
|
+
export var SemanticOperation;
|
|
289
|
+
(function (SemanticOperation) {
|
|
290
|
+
SemanticOperation["Create"] = "Create";
|
|
291
|
+
SemanticOperation["Read"] = "Read";
|
|
292
|
+
SemanticOperation["Update"] = "Update";
|
|
293
|
+
SemanticOperation["Delete"] = "Delete";
|
|
294
|
+
/**
|
|
295
|
+
* Special operation for list/query operations
|
|
296
|
+
*/
|
|
297
|
+
SemanticOperation["List"] = "List";
|
|
298
|
+
})(SemanticOperation || (SemanticOperation = {}));
|
|
299
|
+
/**
|
|
300
|
+
* Defines the execution mode for a semantic.
|
|
301
|
+
*/
|
|
302
|
+
export var SemanticExecutionMode;
|
|
303
|
+
(function (SemanticExecutionMode) {
|
|
304
|
+
/**
|
|
305
|
+
* Execute synchronously as part of the main operation
|
|
306
|
+
*/
|
|
307
|
+
SemanticExecutionMode["Synchronous"] = "Synchronous";
|
|
308
|
+
/**
|
|
309
|
+
* Execute asynchronously after the main operation
|
|
310
|
+
*/
|
|
311
|
+
SemanticExecutionMode["Asynchronous"] = "Asynchronous";
|
|
312
|
+
/**
|
|
313
|
+
* Execute in background/queue (fire and forget)
|
|
314
|
+
*/
|
|
315
|
+
SemanticExecutionMode["Background"] = "Background";
|
|
316
|
+
})(SemanticExecutionMode || (SemanticExecutionMode = {}));
|
|
317
|
+
/**
|
|
318
|
+
* Defines validation strategies for semantics.
|
|
319
|
+
*/
|
|
320
|
+
export var SemanticValidationStrategy;
|
|
321
|
+
(function (SemanticValidationStrategy) {
|
|
322
|
+
/**
|
|
323
|
+
* Fail the operation if semantic validation fails
|
|
324
|
+
*/
|
|
325
|
+
SemanticValidationStrategy["Strict"] = "Strict";
|
|
326
|
+
/**
|
|
327
|
+
* Log warnings but continue operation
|
|
328
|
+
*/
|
|
329
|
+
SemanticValidationStrategy["Warning"] = "Warning";
|
|
330
|
+
/**
|
|
331
|
+
* Skip validation entirely
|
|
332
|
+
*/
|
|
333
|
+
SemanticValidationStrategy["Skip"] = "Skip";
|
|
334
|
+
})(SemanticValidationStrategy || (SemanticValidationStrategy = {}));
|
|
335
|
+
/**
|
|
336
|
+
* Defines caching strategies for computed semantics.
|
|
337
|
+
*/
|
|
338
|
+
export var SemanticCacheStrategy;
|
|
339
|
+
(function (SemanticCacheStrategy) {
|
|
340
|
+
/**
|
|
341
|
+
* No caching - always compute
|
|
342
|
+
*/
|
|
343
|
+
SemanticCacheStrategy["None"] = "None";
|
|
344
|
+
/**
|
|
345
|
+
* Cache until dependent fields change
|
|
346
|
+
*/
|
|
347
|
+
SemanticCacheStrategy["Dependency"] = "Dependency";
|
|
348
|
+
/**
|
|
349
|
+
* Cache with TTL expiration
|
|
350
|
+
*/
|
|
351
|
+
SemanticCacheStrategy["TimeToLive"] = "TimeToLive";
|
|
352
|
+
/**
|
|
353
|
+
* Cache until manually invalidated
|
|
354
|
+
*/
|
|
355
|
+
SemanticCacheStrategy["Manual"] = "Manual";
|
|
356
|
+
})(SemanticCacheStrategy || (SemanticCacheStrategy = {}));
|
|
257
357
|
/**
|
|
258
358
|
* A type guard to check if a semantic is an EntitySemantic.
|
|
259
359
|
*/
|
|
@@ -281,6 +381,10 @@ export const DataSemantics = {
|
|
|
281
381
|
description: 'System users and accounts',
|
|
282
382
|
category: SemanticCategory.Identity,
|
|
283
383
|
hasConfig: false,
|
|
384
|
+
runtime: {
|
|
385
|
+
timing: SemanticTiming.None,
|
|
386
|
+
operations: [],
|
|
387
|
+
},
|
|
284
388
|
},
|
|
285
389
|
[SemanticType.Password]: {
|
|
286
390
|
id: SemanticType.Password,
|
|
@@ -290,6 +394,19 @@ export const DataSemantics = {
|
|
|
290
394
|
category: SemanticCategory.Identity,
|
|
291
395
|
applicableDataTypes: ['string'],
|
|
292
396
|
hasConfig: true,
|
|
397
|
+
runtime: {
|
|
398
|
+
timing: SemanticTiming.Before,
|
|
399
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
400
|
+
priority: 10, // High priority for security
|
|
401
|
+
canDisable: false, // Security semantics cannot be disabled
|
|
402
|
+
timeoutMs: 2000, // Allow time for hashing
|
|
403
|
+
conditions: [
|
|
404
|
+
{
|
|
405
|
+
expression: 'entity[semantics.Password] != null && entity[semantics.Password].length > 0',
|
|
406
|
+
description: 'Only process when password field has a value',
|
|
407
|
+
},
|
|
408
|
+
],
|
|
409
|
+
},
|
|
293
410
|
},
|
|
294
411
|
[SemanticType.UserRole]: {
|
|
295
412
|
id: SemanticType.UserRole,
|
|
@@ -299,6 +416,17 @@ export const DataSemantics = {
|
|
|
299
416
|
category: SemanticCategory.Identity,
|
|
300
417
|
applicableDataTypes: ['string'],
|
|
301
418
|
hasConfig: false,
|
|
419
|
+
runtime: {
|
|
420
|
+
timing: SemanticTiming.Before,
|
|
421
|
+
operations: [
|
|
422
|
+
SemanticOperation.Create,
|
|
423
|
+
SemanticOperation.Read,
|
|
424
|
+
SemanticOperation.Update,
|
|
425
|
+
SemanticOperation.Delete,
|
|
426
|
+
SemanticOperation.List,
|
|
427
|
+
],
|
|
428
|
+
priority: 20,
|
|
429
|
+
},
|
|
302
430
|
},
|
|
303
431
|
[SemanticType.ResourceOwnerIdentifier]: {
|
|
304
432
|
id: SemanticType.ResourceOwnerIdentifier,
|
|
@@ -307,6 +435,18 @@ export const DataSemantics = {
|
|
|
307
435
|
description: 'Links record to owner user',
|
|
308
436
|
category: SemanticCategory.Identity,
|
|
309
437
|
hasConfig: false,
|
|
438
|
+
runtime: {
|
|
439
|
+
timing: SemanticTiming.Before,
|
|
440
|
+
operations: [
|
|
441
|
+
SemanticOperation.Create,
|
|
442
|
+
SemanticOperation.Read,
|
|
443
|
+
SemanticOperation.Update,
|
|
444
|
+
SemanticOperation.Delete,
|
|
445
|
+
SemanticOperation.List,
|
|
446
|
+
],
|
|
447
|
+
priority: 5, // Very high priority for access control
|
|
448
|
+
canDisable: false,
|
|
449
|
+
},
|
|
310
450
|
},
|
|
311
451
|
//
|
|
312
452
|
// Timestamps & Versioning
|
|
@@ -319,6 +459,18 @@ export const DataSemantics = {
|
|
|
319
459
|
category: SemanticCategory.Lifecycle,
|
|
320
460
|
applicableDataTypes: ['datetime'],
|
|
321
461
|
hasConfig: false,
|
|
462
|
+
runtime: {
|
|
463
|
+
timing: SemanticTiming.Before,
|
|
464
|
+
operations: [SemanticOperation.Create],
|
|
465
|
+
priority: 90,
|
|
466
|
+
timeoutMs: 100, // Very fast operation
|
|
467
|
+
conditions: [
|
|
468
|
+
{
|
|
469
|
+
expression: 'entity[semantics.CreatedTimestamp] == null',
|
|
470
|
+
description: 'Only set timestamp if not already provided',
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
},
|
|
322
474
|
},
|
|
323
475
|
[SemanticType.UpdatedTimestamp]: {
|
|
324
476
|
id: SemanticType.UpdatedTimestamp,
|
|
@@ -328,6 +480,11 @@ export const DataSemantics = {
|
|
|
328
480
|
category: SemanticCategory.Lifecycle,
|
|
329
481
|
applicableDataTypes: ['datetime'],
|
|
330
482
|
hasConfig: false,
|
|
483
|
+
runtime: {
|
|
484
|
+
timing: SemanticTiming.Before,
|
|
485
|
+
operations: [SemanticOperation.Update],
|
|
486
|
+
priority: 90,
|
|
487
|
+
},
|
|
331
488
|
},
|
|
332
489
|
[SemanticType.DeletedTimestamp]: {
|
|
333
490
|
id: SemanticType.DeletedTimestamp,
|
|
@@ -337,6 +494,11 @@ export const DataSemantics = {
|
|
|
337
494
|
category: SemanticCategory.Lifecycle,
|
|
338
495
|
applicableDataTypes: ['datetime'],
|
|
339
496
|
hasConfig: false,
|
|
497
|
+
runtime: {
|
|
498
|
+
timing: SemanticTiming.Before,
|
|
499
|
+
operations: [SemanticOperation.Delete],
|
|
500
|
+
priority: 80,
|
|
501
|
+
},
|
|
340
502
|
},
|
|
341
503
|
[SemanticType.DeletedFlag]: {
|
|
342
504
|
id: SemanticType.DeletedFlag,
|
|
@@ -346,6 +508,11 @@ export const DataSemantics = {
|
|
|
346
508
|
category: SemanticCategory.Lifecycle,
|
|
347
509
|
applicableDataTypes: ['boolean'],
|
|
348
510
|
hasConfig: false,
|
|
511
|
+
runtime: {
|
|
512
|
+
timing: SemanticTiming.Before,
|
|
513
|
+
operations: [SemanticOperation.Delete, SemanticOperation.Read, SemanticOperation.List],
|
|
514
|
+
priority: 80,
|
|
515
|
+
},
|
|
349
516
|
},
|
|
350
517
|
[SemanticType.Version]: {
|
|
351
518
|
id: SemanticType.Version,
|
|
@@ -355,6 +522,11 @@ export const DataSemantics = {
|
|
|
355
522
|
category: SemanticCategory.Lifecycle,
|
|
356
523
|
applicableDataTypes: ['number'],
|
|
357
524
|
hasConfig: false,
|
|
525
|
+
runtime: {
|
|
526
|
+
timing: SemanticTiming.Before,
|
|
527
|
+
operations: [SemanticOperation.Update],
|
|
528
|
+
priority: 85,
|
|
529
|
+
},
|
|
358
530
|
},
|
|
359
531
|
//
|
|
360
532
|
// Content & Media
|
|
@@ -367,6 +539,10 @@ export const DataSemantics = {
|
|
|
367
539
|
category: SemanticCategory.Content,
|
|
368
540
|
applicableDataTypes: ['string'],
|
|
369
541
|
hasConfig: false,
|
|
542
|
+
runtime: {
|
|
543
|
+
timing: SemanticTiming.None,
|
|
544
|
+
operations: [],
|
|
545
|
+
},
|
|
370
546
|
},
|
|
371
547
|
[SemanticType.Description]: {
|
|
372
548
|
id: SemanticType.Description,
|
|
@@ -376,6 +552,10 @@ export const DataSemantics = {
|
|
|
376
552
|
category: SemanticCategory.Content,
|
|
377
553
|
applicableDataTypes: ['string'],
|
|
378
554
|
hasConfig: false,
|
|
555
|
+
runtime: {
|
|
556
|
+
timing: SemanticTiming.None,
|
|
557
|
+
operations: [],
|
|
558
|
+
},
|
|
379
559
|
},
|
|
380
560
|
[SemanticType.Summary]: {
|
|
381
561
|
id: SemanticType.Summary,
|
|
@@ -385,6 +565,10 @@ export const DataSemantics = {
|
|
|
385
565
|
category: SemanticCategory.Content,
|
|
386
566
|
applicableDataTypes: ['string'],
|
|
387
567
|
hasConfig: false,
|
|
568
|
+
runtime: {
|
|
569
|
+
timing: SemanticTiming.None,
|
|
570
|
+
operations: [],
|
|
571
|
+
},
|
|
388
572
|
},
|
|
389
573
|
[SemanticType.Markdown]: {
|
|
390
574
|
id: SemanticType.Markdown,
|
|
@@ -394,6 +578,11 @@ export const DataSemantics = {
|
|
|
394
578
|
category: SemanticCategory.Content,
|
|
395
579
|
applicableDataTypes: ['string'],
|
|
396
580
|
hasConfig: true,
|
|
581
|
+
runtime: {
|
|
582
|
+
timing: SemanticTiming.Before,
|
|
583
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
584
|
+
priority: 50, // Process before storage
|
|
585
|
+
},
|
|
397
586
|
},
|
|
398
587
|
[SemanticType.HTML]: {
|
|
399
588
|
id: SemanticType.HTML,
|
|
@@ -403,6 +592,11 @@ export const DataSemantics = {
|
|
|
403
592
|
category: SemanticCategory.Content,
|
|
404
593
|
applicableDataTypes: ['string'],
|
|
405
594
|
hasConfig: true,
|
|
595
|
+
runtime: {
|
|
596
|
+
timing: SemanticTiming.Before,
|
|
597
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
598
|
+
priority: 50, // Process before storage for sanitization
|
|
599
|
+
},
|
|
406
600
|
},
|
|
407
601
|
[SemanticType.ImageURL]: {
|
|
408
602
|
id: SemanticType.ImageURL,
|
|
@@ -412,6 +606,11 @@ export const DataSemantics = {
|
|
|
412
606
|
category: SemanticCategory.Content,
|
|
413
607
|
applicableDataTypes: ['string'],
|
|
414
608
|
hasConfig: false,
|
|
609
|
+
runtime: {
|
|
610
|
+
timing: SemanticTiming.Before,
|
|
611
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
612
|
+
priority: 60, // Validate URLs before storage
|
|
613
|
+
},
|
|
415
614
|
},
|
|
416
615
|
[SemanticType.FileURL]: {
|
|
417
616
|
id: SemanticType.FileURL,
|
|
@@ -421,6 +620,11 @@ export const DataSemantics = {
|
|
|
421
620
|
category: SemanticCategory.Content,
|
|
422
621
|
applicableDataTypes: ['string'],
|
|
423
622
|
hasConfig: false,
|
|
623
|
+
runtime: {
|
|
624
|
+
timing: SemanticTiming.Before,
|
|
625
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
626
|
+
priority: 60, // Validate URLs before storage
|
|
627
|
+
},
|
|
424
628
|
},
|
|
425
629
|
//
|
|
426
630
|
// Business Data
|
|
@@ -433,6 +637,11 @@ export const DataSemantics = {
|
|
|
433
637
|
category: SemanticCategory.Business,
|
|
434
638
|
applicableDataTypes: ['string'],
|
|
435
639
|
hasConfig: true,
|
|
640
|
+
runtime: {
|
|
641
|
+
timing: SemanticTiming.Both,
|
|
642
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update, SemanticOperation.Read, SemanticOperation.List],
|
|
643
|
+
priority: 30, // Validate state transitions before, filter by state after
|
|
644
|
+
},
|
|
436
645
|
},
|
|
437
646
|
[SemanticType.Currency]: {
|
|
438
647
|
id: SemanticType.Currency,
|
|
@@ -442,6 +651,11 @@ export const DataSemantics = {
|
|
|
442
651
|
category: SemanticCategory.Business,
|
|
443
652
|
applicableDataTypes: ['number', 'string'],
|
|
444
653
|
hasConfig: true,
|
|
654
|
+
runtime: {
|
|
655
|
+
timing: SemanticTiming.Before,
|
|
656
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
657
|
+
priority: 70, // Validate currency format and precision
|
|
658
|
+
},
|
|
445
659
|
},
|
|
446
660
|
[SemanticType.SKU]: {
|
|
447
661
|
id: SemanticType.SKU,
|
|
@@ -451,6 +665,11 @@ export const DataSemantics = {
|
|
|
451
665
|
category: SemanticCategory.Business,
|
|
452
666
|
applicableDataTypes: ['string'],
|
|
453
667
|
hasConfig: true,
|
|
668
|
+
runtime: {
|
|
669
|
+
timing: SemanticTiming.Before,
|
|
670
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
671
|
+
priority: 25, // High priority for uniqueness validation
|
|
672
|
+
},
|
|
454
673
|
},
|
|
455
674
|
//
|
|
456
675
|
// Contact Information
|
|
@@ -463,6 +682,11 @@ export const DataSemantics = {
|
|
|
463
682
|
category: SemanticCategory.Contact,
|
|
464
683
|
applicableDataTypes: ['string'],
|
|
465
684
|
hasConfig: true,
|
|
685
|
+
runtime: {
|
|
686
|
+
timing: SemanticTiming.Before,
|
|
687
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
688
|
+
priority: 40, // Validate email format
|
|
689
|
+
},
|
|
466
690
|
},
|
|
467
691
|
[SemanticType.Phone]: {
|
|
468
692
|
id: SemanticType.Phone,
|
|
@@ -472,6 +696,11 @@ export const DataSemantics = {
|
|
|
472
696
|
category: SemanticCategory.Contact,
|
|
473
697
|
applicableDataTypes: ['string'],
|
|
474
698
|
hasConfig: true,
|
|
699
|
+
runtime: {
|
|
700
|
+
timing: SemanticTiming.Before,
|
|
701
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
702
|
+
priority: 40, // Validate phone format
|
|
703
|
+
},
|
|
475
704
|
},
|
|
476
705
|
[SemanticType.URL]: {
|
|
477
706
|
id: SemanticType.URL,
|
|
@@ -481,6 +710,32 @@ export const DataSemantics = {
|
|
|
481
710
|
category: SemanticCategory.Contact,
|
|
482
711
|
applicableDataTypes: ['string'],
|
|
483
712
|
hasConfig: true,
|
|
713
|
+
runtime: {
|
|
714
|
+
timing: SemanticTiming.Before,
|
|
715
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
716
|
+
priority: 40, // Validate URL format
|
|
717
|
+
},
|
|
718
|
+
},
|
|
719
|
+
[SemanticType.ClientIPAddress]: {
|
|
720
|
+
id: SemanticType.ClientIPAddress,
|
|
721
|
+
displayName: 'Client IP Address',
|
|
722
|
+
scope: SemanticScope.Property,
|
|
723
|
+
description: 'Automatically populated client IP address',
|
|
724
|
+
category: SemanticCategory.Contact,
|
|
725
|
+
applicableDataTypes: ['string'],
|
|
726
|
+
hasConfig: false,
|
|
727
|
+
runtime: {
|
|
728
|
+
timing: SemanticTiming.Before,
|
|
729
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
730
|
+
priority: 95, // Low priority, populate after other validations
|
|
731
|
+
timeoutMs: 100, // Very fast operation
|
|
732
|
+
conditions: [
|
|
733
|
+
{
|
|
734
|
+
expression: 'entity[semantics.ClientIPAddress] == null',
|
|
735
|
+
description: 'Only set IP address if not already provided',
|
|
736
|
+
},
|
|
737
|
+
],
|
|
738
|
+
},
|
|
484
739
|
},
|
|
485
740
|
//
|
|
486
741
|
// Classification & Organization
|
|
@@ -493,6 +748,23 @@ export const DataSemantics = {
|
|
|
493
748
|
category: SemanticCategory.Organization,
|
|
494
749
|
applicableDataTypes: ['string'],
|
|
495
750
|
hasConfig: true,
|
|
751
|
+
runtime: {
|
|
752
|
+
timing: SemanticTiming.Before,
|
|
753
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
754
|
+
priority: 30, // Generate slug from title, validate uniqueness
|
|
755
|
+
timeoutMs: 1000,
|
|
756
|
+
conditions: [
|
|
757
|
+
{
|
|
758
|
+
expression: 'entity[semantics.PublicUniqueName] == null || entity[semantics.PublicUniqueName].length == 0',
|
|
759
|
+
description: 'Only generate slug if not already provided',
|
|
760
|
+
},
|
|
761
|
+
// Let's not guess which field is marked as slug source in the `PublicUniqueName` configuration.
|
|
762
|
+
// {
|
|
763
|
+
// expression: 'entity[semantics.Title] != null && entity[semantics.Title].length > 0',
|
|
764
|
+
// description: 'Only generate slug if title field exists and has content',
|
|
765
|
+
// },
|
|
766
|
+
],
|
|
767
|
+
},
|
|
496
768
|
},
|
|
497
769
|
[SemanticType.Tags]: {
|
|
498
770
|
id: SemanticType.Tags,
|
|
@@ -501,6 +773,11 @@ export const DataSemantics = {
|
|
|
501
773
|
description: 'Enable tagging functionality',
|
|
502
774
|
category: SemanticCategory.Organization,
|
|
503
775
|
hasConfig: true,
|
|
776
|
+
runtime: {
|
|
777
|
+
timing: SemanticTiming.After,
|
|
778
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update, SemanticOperation.Delete],
|
|
779
|
+
priority: 200, // Process after main operation
|
|
780
|
+
},
|
|
504
781
|
},
|
|
505
782
|
[SemanticType.Categories]: {
|
|
506
783
|
id: SemanticType.Categories,
|
|
@@ -509,6 +786,11 @@ export const DataSemantics = {
|
|
|
509
786
|
description: 'Enable categorization functionality',
|
|
510
787
|
category: SemanticCategory.Organization,
|
|
511
788
|
hasConfig: true,
|
|
789
|
+
runtime: {
|
|
790
|
+
timing: SemanticTiming.After,
|
|
791
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update, SemanticOperation.Delete],
|
|
792
|
+
priority: 200, // Process after main operation
|
|
793
|
+
},
|
|
512
794
|
},
|
|
513
795
|
//
|
|
514
796
|
// Location & Geography
|
|
@@ -521,6 +803,11 @@ export const DataSemantics = {
|
|
|
521
803
|
category: SemanticCategory.Location,
|
|
522
804
|
applicableDataTypes: ['string'],
|
|
523
805
|
hasConfig: true,
|
|
806
|
+
runtime: {
|
|
807
|
+
timing: SemanticTiming.Both,
|
|
808
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update, SemanticOperation.Read, SemanticOperation.List],
|
|
809
|
+
priority: 60, // Validate coordinates before, enable spatial queries after
|
|
810
|
+
},
|
|
524
811
|
},
|
|
525
812
|
//
|
|
526
813
|
// Computed Values
|
|
@@ -534,6 +821,11 @@ export const DataSemantics = {
|
|
|
534
821
|
category: SemanticCategory.Computed,
|
|
535
822
|
applicableDataTypes: ['string', 'number', 'boolean', 'date', 'datetime', 'time', 'binary'],
|
|
536
823
|
hasConfig: true,
|
|
824
|
+
runtime: {
|
|
825
|
+
timing: SemanticTiming.Both,
|
|
826
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update, SemanticOperation.Read],
|
|
827
|
+
priority: 150, // Calculate after other validations, recalculate on read if needed
|
|
828
|
+
},
|
|
537
829
|
},
|
|
538
830
|
[SemanticType.Derived]: {
|
|
539
831
|
id: SemanticType.Derived,
|
|
@@ -543,8 +835,44 @@ export const DataSemantics = {
|
|
|
543
835
|
category: SemanticCategory.Computed,
|
|
544
836
|
applicableDataTypes: ['string'],
|
|
545
837
|
hasConfig: true,
|
|
838
|
+
runtime: {
|
|
839
|
+
timing: SemanticTiming.After,
|
|
840
|
+
operations: [SemanticOperation.Create, SemanticOperation.Update],
|
|
841
|
+
priority: 180, // Derive after all other processing
|
|
842
|
+
},
|
|
546
843
|
},
|
|
547
844
|
};
|
|
845
|
+
/**
|
|
846
|
+
* Get all semantics that should run for a specific operation and timing
|
|
847
|
+
*/
|
|
848
|
+
export function getSemanticsForOperation(semantics, operation, timing) {
|
|
849
|
+
return semantics
|
|
850
|
+
.filter((semantic) => {
|
|
851
|
+
const definition = DataSemantics[semantic.id];
|
|
852
|
+
if (!definition?.runtime) {
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
const { timing: semanticTiming, operations } = definition.runtime;
|
|
856
|
+
// Check if timing matches
|
|
857
|
+
const timingMatches = semanticTiming === timing || semanticTiming === SemanticTiming.Both;
|
|
858
|
+
// Check if operation is included
|
|
859
|
+
const operationMatches = operations.includes(operation);
|
|
860
|
+
return timingMatches && operationMatches;
|
|
861
|
+
})
|
|
862
|
+
.sort((a, b) => {
|
|
863
|
+
// Sort by priority (lower number = higher priority)
|
|
864
|
+
const priorityA = DataSemantics[a.id]?.runtime?.priority ?? 100;
|
|
865
|
+
const priorityB = DataSemantics[b.id]?.runtime?.priority ?? 100;
|
|
866
|
+
return priorityA - priorityB;
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Check if a specific semantic can be disabled at runtime
|
|
871
|
+
*/
|
|
872
|
+
export function canSemanticBeDisabled(semanticType) {
|
|
873
|
+
const definition = DataSemantics[semanticType];
|
|
874
|
+
return definition?.runtime?.canDisable !== false; // Default to true if not specified
|
|
875
|
+
}
|
|
548
876
|
/**
|
|
549
877
|
* Helper function to get all semantics grouped by category.
|
|
550
878
|
* Useful for organizing semantics in UI dropdowns and forms.
|