@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.
Files changed (59) hide show
  1. package/build/src/modeling/DomainEntity.d.ts +6 -1
  2. package/build/src/modeling/DomainEntity.d.ts.map +1 -1
  3. package/build/src/modeling/DomainEntity.js +24 -5
  4. package/build/src/modeling/DomainEntity.js.map +1 -1
  5. package/build/src/modeling/Semantics.d.ts +254 -0
  6. package/build/src/modeling/Semantics.d.ts.map +1 -1
  7. package/build/src/modeling/Semantics.js +328 -0
  8. package/build/src/modeling/Semantics.js.map +1 -1
  9. package/build/src/modeling/definitions/Email.js +1 -1
  10. package/build/src/modeling/definitions/Email.js.map +1 -1
  11. package/build/src/modeling/definitions/Password.d.ts.map +1 -1
  12. package/build/src/modeling/definitions/Password.js +1 -3
  13. package/build/src/modeling/definitions/Password.js.map +1 -1
  14. package/build/src/modeling/helpers/Intelisense.d.ts +7 -7
  15. package/build/src/modeling/helpers/Intelisense.d.ts.map +1 -1
  16. package/build/src/modeling/helpers/Intelisense.js +24 -58
  17. package/build/src/modeling/helpers/Intelisense.js.map +1 -1
  18. package/build/src/modeling/templates/meta/blog-publishing-platform.json +1 -1
  19. package/build/src/modeling/templates/meta/financial-services-platform.json +1 -1
  20. package/build/src/modeling/templates/meta/index.d.ts +1 -1
  21. package/build/src/modeling/templates/meta/index.js +1 -1
  22. package/build/src/modeling/templates/meta/index.js.map +1 -1
  23. package/build/src/modeling/templates/meta/iot-smart-home-platform.json +1 -1
  24. package/build/src/modeling/templates/verticals/business-services/financial-services-domain.d.ts.map +1 -1
  25. package/build/src/modeling/templates/verticals/business-services/financial-services-domain.js +248 -63
  26. package/build/src/modeling/templates/verticals/business-services/financial-services-domain.js.map +1 -1
  27. package/build/src/modeling/templates/verticals/technology-media/blog-domain.js +5 -5
  28. package/build/src/modeling/templates/verticals/technology-media/blog-domain.js.map +1 -1
  29. package/build/src/modeling/templates/verticals/technology-media/iot-smart-home-domain.d.ts.map +1 -1
  30. package/build/src/modeling/templates/verticals/technology-media/iot-smart-home-domain.js +2 -0
  31. package/build/src/modeling/templates/verticals/technology-media/iot-smart-home-domain.js.map +1 -1
  32. package/build/src/modeling/validation/postgresql.d.ts.map +1 -1
  33. package/build/src/modeling/validation/postgresql.js +0 -1
  34. package/build/src/modeling/validation/postgresql.js.map +1 -1
  35. package/build/src/runtime/modeling/Semantics.d.ts +84 -0
  36. package/build/src/runtime/modeling/Semantics.d.ts.map +1 -0
  37. package/build/src/runtime/modeling/Semantics.js +124 -0
  38. package/build/src/runtime/modeling/Semantics.js.map +1 -0
  39. package/build/tsconfig.tsbuildinfo +1 -1
  40. package/data/models/example-generator-api.json +8 -8
  41. package/package.json +1 -1
  42. package/src/modeling/DomainEntity.ts +27 -5
  43. package/src/modeling/Semantics.ts +493 -0
  44. package/src/modeling/definitions/Email.ts +1 -1
  45. package/src/modeling/definitions/Password.ts +1 -3
  46. package/src/modeling/helpers/Intelisense.ts +33 -65
  47. package/src/modeling/templates/meta/blog-publishing-platform.json +1 -1
  48. package/src/modeling/templates/meta/financial-services-platform.json +1 -1
  49. package/src/modeling/templates/meta/iot-smart-home-platform.json +1 -1
  50. package/src/modeling/templates/verticals/business-services/financial-services-domain.ts +285 -65
  51. package/src/modeling/templates/verticals/technology-media/blog-domain.ts +5 -5
  52. package/src/modeling/templates/verticals/technology-media/iot-smart-home-domain.ts +2 -0
  53. package/src/modeling/validation/postgresql.ts +0 -1
  54. package/src/runtime/modeling/Semantics.ts +196 -0
  55. package/tests/unit/modeling/client_ip_address_semantic.spec.ts +71 -0
  56. package/tests/unit/modeling/definitions/password.spec.ts +0 -2
  57. package/tests/unit/modeling/domain_entity_parents.spec.ts +243 -0
  58. package/tests/unit/modeling/semantic_runtime.spec.ts +113 -0
  59. 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.