@almadar/std 1.0.15 → 2.0.0

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.
@@ -4425,6 +4425,943 @@ var GAME_UI_BEHAVIORS = [
4425
4425
  LEVEL_PROGRESS_BEHAVIOR
4426
4426
  ];
4427
4427
 
4428
+ // behaviors/infrastructure.ts
4429
+ var CIRCUIT_BREAKER_BEHAVIOR = {
4430
+ name: "std-circuit-breaker",
4431
+ version: "1.0.0",
4432
+ description: "Circuit breaker pattern with automatic recovery",
4433
+ orbitals: [
4434
+ {
4435
+ name: "CircuitBreakerOrbital",
4436
+ entity: {
4437
+ name: "CircuitBreakerState",
4438
+ persistence: "runtime",
4439
+ fields: [
4440
+ { name: "id", type: "string", required: true },
4441
+ { name: "circuitState", type: "string", default: "closed" },
4442
+ { name: "errorCount", type: "number", default: 0 },
4443
+ { name: "errorRate", type: "number", default: 0 },
4444
+ { name: "successCount", type: "number", default: 0 },
4445
+ { name: "totalCount", type: "number", default: 0 },
4446
+ { name: "lastFailure", type: "number", default: null },
4447
+ { name: "lastSuccess", type: "number", default: null },
4448
+ { name: "errorThreshold", type: "number", default: 5 },
4449
+ { name: "errorRateThreshold", type: "number", default: 0.5 },
4450
+ { name: "resetAfterMs", type: "number", default: 6e4 },
4451
+ { name: "halfOpenMaxAttempts", type: "number", default: 3 },
4452
+ { name: "halfOpenAttempts", type: "number", default: 0 }
4453
+ ]
4454
+ },
4455
+ traits: [
4456
+ {
4457
+ name: "CircuitBreaker",
4458
+ linkedEntity: "CircuitBreakerState",
4459
+ category: "lifecycle",
4460
+ emits: [
4461
+ { event: "CIRCUIT_OPENED", scope: "external" },
4462
+ { event: "CIRCUIT_CLOSED", scope: "external" },
4463
+ { event: "CIRCUIT_HALF_OPEN", scope: "external" }
4464
+ ],
4465
+ stateMachine: {
4466
+ states: [
4467
+ { name: "Closed", isInitial: true },
4468
+ { name: "Open" },
4469
+ { name: "HalfOpen" }
4470
+ ],
4471
+ events: [
4472
+ { key: "RECORD_SUCCESS", name: "Record Success" },
4473
+ { key: "RECORD_FAILURE", name: "Record Failure" },
4474
+ { key: "PROBE", name: "Probe" },
4475
+ { key: "RESET", name: "Reset" }
4476
+ ],
4477
+ transitions: [
4478
+ // Closed: record success
4479
+ {
4480
+ from: "Closed",
4481
+ to: "Closed",
4482
+ event: "RECORD_SUCCESS",
4483
+ effects: [
4484
+ ["set", "@entity.successCount", ["+", "@entity.successCount", 1]],
4485
+ ["set", "@entity.totalCount", ["+", "@entity.totalCount", 1]],
4486
+ ["set", "@entity.lastSuccess", ["time/now"]],
4487
+ ["set", "@entity.errorRate", ["/", "@entity.errorCount", ["math/max", "@entity.totalCount", 1]]]
4488
+ ]
4489
+ },
4490
+ // Closed: record failure, stay closed if under threshold
4491
+ {
4492
+ from: "Closed",
4493
+ to: "Closed",
4494
+ event: "RECORD_FAILURE",
4495
+ guard: ["<", ["+", "@entity.errorCount", 1], "@entity.errorThreshold"],
4496
+ effects: [
4497
+ ["set", "@entity.errorCount", ["+", "@entity.errorCount", 1]],
4498
+ ["set", "@entity.totalCount", ["+", "@entity.totalCount", 1]],
4499
+ ["set", "@entity.lastFailure", ["time/now"]],
4500
+ ["set", "@entity.errorRate", ["/", ["+", "@entity.errorCount", 1], ["math/max", "@entity.totalCount", 1]]]
4501
+ ]
4502
+ },
4503
+ // Closed -> Open: threshold exceeded
4504
+ {
4505
+ from: "Closed",
4506
+ to: "Open",
4507
+ event: "RECORD_FAILURE",
4508
+ guard: [">=", ["+", "@entity.errorCount", 1], "@entity.errorThreshold"],
4509
+ effects: [
4510
+ ["set", "@entity.errorCount", ["+", "@entity.errorCount", 1]],
4511
+ ["set", "@entity.totalCount", ["+", "@entity.totalCount", 1]],
4512
+ ["set", "@entity.lastFailure", ["time/now"]],
4513
+ ["set", "@entity.errorRate", ["/", ["+", "@entity.errorCount", 1], ["math/max", "@entity.totalCount", 1]]],
4514
+ ["emit", "CIRCUIT_OPENED", { errorCount: "@entity.errorCount", errorRate: "@entity.errorRate" }]
4515
+ ]
4516
+ },
4517
+ // Open -> HalfOpen: probe after reset timeout
4518
+ {
4519
+ from: "Open",
4520
+ to: "HalfOpen",
4521
+ event: "PROBE",
4522
+ guard: [">", ["-", ["time/now"], "@entity.lastFailure"], "@entity.resetAfterMs"],
4523
+ effects: [
4524
+ ["set", "@entity.halfOpenAttempts", 0],
4525
+ ["emit", "CIRCUIT_HALF_OPEN", {}]
4526
+ ]
4527
+ },
4528
+ // HalfOpen: success -> close
4529
+ {
4530
+ from: "HalfOpen",
4531
+ to: "Closed",
4532
+ event: "RECORD_SUCCESS",
4533
+ effects: [
4534
+ ["set", "@entity.errorCount", 0],
4535
+ ["set", "@entity.errorRate", 0],
4536
+ ["set", "@entity.halfOpenAttempts", 0],
4537
+ ["set", "@entity.successCount", ["+", "@entity.successCount", 1]],
4538
+ ["set", "@entity.lastSuccess", ["time/now"]],
4539
+ ["emit", "CIRCUIT_CLOSED", {}]
4540
+ ]
4541
+ },
4542
+ // HalfOpen: failure -> back to open
4543
+ {
4544
+ from: "HalfOpen",
4545
+ to: "Open",
4546
+ event: "RECORD_FAILURE",
4547
+ effects: [
4548
+ ["set", "@entity.errorCount", ["+", "@entity.errorCount", 1]],
4549
+ ["set", "@entity.lastFailure", ["time/now"]],
4550
+ ["emit", "CIRCUIT_OPENED", { errorCount: "@entity.errorCount" }]
4551
+ ]
4552
+ },
4553
+ // Reset from any state
4554
+ {
4555
+ from: ["Closed", "Open", "HalfOpen"],
4556
+ to: "Closed",
4557
+ event: "RESET",
4558
+ effects: [
4559
+ ["set", "@entity.errorCount", 0],
4560
+ ["set", "@entity.successCount", 0],
4561
+ ["set", "@entity.totalCount", 0],
4562
+ ["set", "@entity.errorRate", 0],
4563
+ ["set", "@entity.halfOpenAttempts", 0],
4564
+ ["set", "@entity.circuitState", "closed"]
4565
+ ]
4566
+ }
4567
+ ]
4568
+ },
4569
+ ticks: [
4570
+ {
4571
+ name: "probe_half_open",
4572
+ interval: "30000",
4573
+ guard: ["=", "@entity.circuitState", "open"],
4574
+ effects: [["emit", "PROBE"]],
4575
+ description: "Periodically probe to transition from Open to HalfOpen"
4576
+ }
4577
+ ]
4578
+ }
4579
+ ],
4580
+ pages: []
4581
+ }
4582
+ ]
4583
+ };
4584
+ var HEALTH_CHECK_BEHAVIOR = {
4585
+ name: "std-health-check",
4586
+ version: "1.0.0",
4587
+ description: "Tick-based health monitoring with degradation detection",
4588
+ orbitals: [
4589
+ {
4590
+ name: "HealthCheckOrbital",
4591
+ entity: {
4592
+ name: "HealthCheckState",
4593
+ persistence: "runtime",
4594
+ fields: [
4595
+ { name: "id", type: "string", required: true },
4596
+ { name: "healthStatus", type: "string", default: "unknown" },
4597
+ { name: "lastCheck", type: "number", default: null },
4598
+ { name: "lastHealthy", type: "number", default: null },
4599
+ { name: "consecutiveFailures", type: "number", default: 0 },
4600
+ { name: "consecutiveSuccesses", type: "number", default: 0 },
4601
+ { name: "checkIntervalMs", type: "number", default: 3e4 },
4602
+ { name: "degradedThreshold", type: "number", default: 2 },
4603
+ { name: "unhealthyThreshold", type: "number", default: 5 },
4604
+ { name: "recoveryThreshold", type: "number", default: 3 },
4605
+ { name: "totalChecks", type: "number", default: 0 },
4606
+ { name: "totalFailures", type: "number", default: 0 }
4607
+ ]
4608
+ },
4609
+ traits: [
4610
+ {
4611
+ name: "HealthCheck",
4612
+ linkedEntity: "HealthCheckState",
4613
+ category: "lifecycle",
4614
+ emits: [
4615
+ { event: "SERVICE_HEALTHY", scope: "external" },
4616
+ { event: "SERVICE_DEGRADED", scope: "external" },
4617
+ { event: "SERVICE_UNHEALTHY", scope: "external" }
4618
+ ],
4619
+ stateMachine: {
4620
+ states: [
4621
+ { name: "Unknown", isInitial: true },
4622
+ { name: "Healthy" },
4623
+ { name: "Degraded" },
4624
+ { name: "Unhealthy" }
4625
+ ],
4626
+ events: [
4627
+ { key: "CHECK_SUCCESS", name: "Check Success" },
4628
+ { key: "CHECK_FAILURE", name: "Check Failure" },
4629
+ { key: "HEALTH_TICK", name: "Health Tick" },
4630
+ { key: "RESET", name: "Reset" }
4631
+ ],
4632
+ transitions: [
4633
+ // Unknown -> Healthy on first success
4634
+ {
4635
+ from: "Unknown",
4636
+ to: "Healthy",
4637
+ event: "CHECK_SUCCESS",
4638
+ effects: [
4639
+ ["set", "@entity.healthStatus", "healthy"],
4640
+ ["set", "@entity.consecutiveSuccesses", 1],
4641
+ ["set", "@entity.consecutiveFailures", 0],
4642
+ ["set", "@entity.lastCheck", ["time/now"]],
4643
+ ["set", "@entity.lastHealthy", ["time/now"]],
4644
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
4645
+ ["emit", "SERVICE_HEALTHY", {}]
4646
+ ]
4647
+ },
4648
+ // Unknown -> Degraded on first failure
4649
+ {
4650
+ from: "Unknown",
4651
+ to: "Degraded",
4652
+ event: "CHECK_FAILURE",
4653
+ effects: [
4654
+ ["set", "@entity.healthStatus", "degraded"],
4655
+ ["set", "@entity.consecutiveFailures", 1],
4656
+ ["set", "@entity.consecutiveSuccesses", 0],
4657
+ ["set", "@entity.lastCheck", ["time/now"]],
4658
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
4659
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]],
4660
+ ["emit", "SERVICE_DEGRADED", { consecutiveFailures: 1 }]
4661
+ ]
4662
+ },
4663
+ // Healthy: stay healthy on success
4664
+ {
4665
+ from: "Healthy",
4666
+ to: "Healthy",
4667
+ event: "CHECK_SUCCESS",
4668
+ effects: [
4669
+ ["set", "@entity.consecutiveSuccesses", ["+", "@entity.consecutiveSuccesses", 1]],
4670
+ ["set", "@entity.consecutiveFailures", 0],
4671
+ ["set", "@entity.lastCheck", ["time/now"]],
4672
+ ["set", "@entity.lastHealthy", ["time/now"]],
4673
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]]
4674
+ ]
4675
+ },
4676
+ // Healthy -> Degraded on failure
4677
+ {
4678
+ from: "Healthy",
4679
+ to: "Degraded",
4680
+ event: "CHECK_FAILURE",
4681
+ effects: [
4682
+ ["set", "@entity.healthStatus", "degraded"],
4683
+ ["set", "@entity.consecutiveFailures", 1],
4684
+ ["set", "@entity.consecutiveSuccesses", 0],
4685
+ ["set", "@entity.lastCheck", ["time/now"]],
4686
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
4687
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]],
4688
+ ["emit", "SERVICE_DEGRADED", { consecutiveFailures: 1 }]
4689
+ ]
4690
+ },
4691
+ // Degraded: stay degraded on failure (below unhealthy threshold)
4692
+ {
4693
+ from: "Degraded",
4694
+ to: "Degraded",
4695
+ event: "CHECK_FAILURE",
4696
+ guard: ["<", ["+", "@entity.consecutiveFailures", 1], "@entity.unhealthyThreshold"],
4697
+ effects: [
4698
+ ["set", "@entity.consecutiveFailures", ["+", "@entity.consecutiveFailures", 1]],
4699
+ ["set", "@entity.consecutiveSuccesses", 0],
4700
+ ["set", "@entity.lastCheck", ["time/now"]],
4701
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
4702
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]]
4703
+ ]
4704
+ },
4705
+ // Degraded -> Unhealthy when threshold exceeded
4706
+ {
4707
+ from: "Degraded",
4708
+ to: "Unhealthy",
4709
+ event: "CHECK_FAILURE",
4710
+ guard: [">=", ["+", "@entity.consecutiveFailures", 1], "@entity.unhealthyThreshold"],
4711
+ effects: [
4712
+ ["set", "@entity.healthStatus", "unhealthy"],
4713
+ ["set", "@entity.consecutiveFailures", ["+", "@entity.consecutiveFailures", 1]],
4714
+ ["set", "@entity.lastCheck", ["time/now"]],
4715
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
4716
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]],
4717
+ ["emit", "SERVICE_UNHEALTHY", { consecutiveFailures: ["+", "@entity.consecutiveFailures", 1] }]
4718
+ ]
4719
+ },
4720
+ // Degraded -> Healthy on enough successes
4721
+ {
4722
+ from: "Degraded",
4723
+ to: "Healthy",
4724
+ event: "CHECK_SUCCESS",
4725
+ guard: [">=", ["+", "@entity.consecutiveSuccesses", 1], "@entity.recoveryThreshold"],
4726
+ effects: [
4727
+ ["set", "@entity.healthStatus", "healthy"],
4728
+ ["set", "@entity.consecutiveSuccesses", ["+", "@entity.consecutiveSuccesses", 1]],
4729
+ ["set", "@entity.consecutiveFailures", 0],
4730
+ ["set", "@entity.lastCheck", ["time/now"]],
4731
+ ["set", "@entity.lastHealthy", ["time/now"]],
4732
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
4733
+ ["emit", "SERVICE_HEALTHY", {}]
4734
+ ]
4735
+ },
4736
+ // Degraded: stay degraded on success (not enough to recover)
4737
+ {
4738
+ from: "Degraded",
4739
+ to: "Degraded",
4740
+ event: "CHECK_SUCCESS",
4741
+ guard: ["<", ["+", "@entity.consecutiveSuccesses", 1], "@entity.recoveryThreshold"],
4742
+ effects: [
4743
+ ["set", "@entity.consecutiveSuccesses", ["+", "@entity.consecutiveSuccesses", 1]],
4744
+ ["set", "@entity.consecutiveFailures", 0],
4745
+ ["set", "@entity.lastCheck", ["time/now"]],
4746
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]]
4747
+ ]
4748
+ },
4749
+ // Unhealthy: stay unhealthy on failure
4750
+ {
4751
+ from: "Unhealthy",
4752
+ to: "Unhealthy",
4753
+ event: "CHECK_FAILURE",
4754
+ effects: [
4755
+ ["set", "@entity.consecutiveFailures", ["+", "@entity.consecutiveFailures", 1]],
4756
+ ["set", "@entity.lastCheck", ["time/now"]],
4757
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
4758
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]]
4759
+ ]
4760
+ },
4761
+ // Unhealthy -> Degraded on first success (recovery begins)
4762
+ {
4763
+ from: "Unhealthy",
4764
+ to: "Degraded",
4765
+ event: "CHECK_SUCCESS",
4766
+ effects: [
4767
+ ["set", "@entity.healthStatus", "degraded"],
4768
+ ["set", "@entity.consecutiveSuccesses", 1],
4769
+ ["set", "@entity.consecutiveFailures", 0],
4770
+ ["set", "@entity.lastCheck", ["time/now"]],
4771
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
4772
+ ["emit", "SERVICE_DEGRADED", { recovering: true }]
4773
+ ]
4774
+ },
4775
+ // Reset from any state
4776
+ {
4777
+ from: ["Unknown", "Healthy", "Degraded", "Unhealthy"],
4778
+ to: "Unknown",
4779
+ event: "RESET",
4780
+ effects: [
4781
+ ["set", "@entity.healthStatus", "unknown"],
4782
+ ["set", "@entity.consecutiveFailures", 0],
4783
+ ["set", "@entity.consecutiveSuccesses", 0],
4784
+ ["set", "@entity.totalChecks", 0],
4785
+ ["set", "@entity.totalFailures", 0]
4786
+ ]
4787
+ }
4788
+ ]
4789
+ },
4790
+ ticks: [
4791
+ {
4792
+ name: "periodic_health_check",
4793
+ interval: "@entity.checkIntervalMs",
4794
+ effects: [["emit", "HEALTH_TICK"]],
4795
+ description: "Periodically trigger health check"
4796
+ }
4797
+ ]
4798
+ }
4799
+ ],
4800
+ pages: []
4801
+ }
4802
+ ]
4803
+ };
4804
+ var RATE_LIMITER_BEHAVIOR = {
4805
+ name: "std-rate-limiter",
4806
+ version: "1.0.0",
4807
+ description: "Guard-based rate limiting with sliding window reset",
4808
+ orbitals: [
4809
+ {
4810
+ name: "RateLimiterOrbital",
4811
+ entity: {
4812
+ name: "RateLimiterState",
4813
+ persistence: "runtime",
4814
+ fields: [
4815
+ { name: "id", type: "string", required: true },
4816
+ { name: "requestCount", type: "number", default: 0 },
4817
+ { name: "windowStart", type: "number", default: 0 },
4818
+ { name: "rateLimit", type: "number", default: 60 },
4819
+ { name: "windowMs", type: "number", default: 6e4 },
4820
+ { name: "totalRequests", type: "number", default: 0 },
4821
+ { name: "rejectedRequests", type: "number", default: 0 }
4822
+ ]
4823
+ },
4824
+ traits: [
4825
+ {
4826
+ name: "RateLimiter",
4827
+ linkedEntity: "RateLimiterState",
4828
+ category: "lifecycle",
4829
+ emits: [
4830
+ { event: "RATE_LIMIT_EXCEEDED", scope: "external" }
4831
+ ],
4832
+ stateMachine: {
4833
+ states: [
4834
+ { name: "Active", isInitial: true }
4835
+ ],
4836
+ events: [
4837
+ { key: "REQUEST", name: "Record Request" },
4838
+ { key: "REQUEST_REJECTED", name: "Request Rejected" },
4839
+ { key: "WINDOW_RESET", name: "Window Reset" },
4840
+ { key: "RESET", name: "Full Reset" }
4841
+ ],
4842
+ transitions: [
4843
+ // Request allowed
4844
+ {
4845
+ from: "Active",
4846
+ to: "Active",
4847
+ event: "REQUEST",
4848
+ guard: ["<", "@entity.requestCount", "@entity.rateLimit"],
4849
+ effects: [
4850
+ ["set", "@entity.requestCount", ["+", "@entity.requestCount", 1]],
4851
+ ["set", "@entity.totalRequests", ["+", "@entity.totalRequests", 1]]
4852
+ ]
4853
+ },
4854
+ // Request rejected — over limit
4855
+ {
4856
+ from: "Active",
4857
+ to: "Active",
4858
+ event: "REQUEST",
4859
+ guard: [">=", "@entity.requestCount", "@entity.rateLimit"],
4860
+ effects: [
4861
+ ["set", "@entity.rejectedRequests", ["+", "@entity.rejectedRequests", 1]],
4862
+ ["emit", "RATE_LIMIT_EXCEEDED", {
4863
+ requestCount: "@entity.requestCount",
4864
+ rateLimit: "@entity.rateLimit"
4865
+ }]
4866
+ ]
4867
+ },
4868
+ // Sliding window reset
4869
+ {
4870
+ from: "Active",
4871
+ to: "Active",
4872
+ event: "WINDOW_RESET",
4873
+ effects: [
4874
+ ["set", "@entity.requestCount", 0],
4875
+ ["set", "@entity.windowStart", ["time/now"]]
4876
+ ]
4877
+ },
4878
+ // Full counter reset
4879
+ {
4880
+ from: "Active",
4881
+ to: "Active",
4882
+ event: "RESET",
4883
+ effects: [
4884
+ ["set", "@entity.requestCount", 0],
4885
+ ["set", "@entity.totalRequests", 0],
4886
+ ["set", "@entity.rejectedRequests", 0],
4887
+ ["set", "@entity.windowStart", ["time/now"]]
4888
+ ]
4889
+ }
4890
+ ]
4891
+ },
4892
+ ticks: [
4893
+ {
4894
+ name: "window_reset",
4895
+ interval: "@entity.windowMs",
4896
+ effects: [["emit", "WINDOW_RESET"]],
4897
+ description: "Reset request counter on sliding window expiry"
4898
+ }
4899
+ ]
4900
+ }
4901
+ ],
4902
+ pages: []
4903
+ }
4904
+ ]
4905
+ };
4906
+ var CACHE_ASIDE_BEHAVIOR = {
4907
+ name: "std-cache-aside",
4908
+ version: "1.0.0",
4909
+ description: "Cache-aside pattern with TTL-based freshness and eviction",
4910
+ orbitals: [
4911
+ {
4912
+ name: "CacheAsideOrbital",
4913
+ entity: {
4914
+ name: "CacheEntry",
4915
+ persistence: "runtime",
4916
+ fields: [
4917
+ { name: "id", type: "string", required: true },
4918
+ { name: "cacheKey", type: "string", default: "" },
4919
+ { name: "cachedValue", type: "object", default: null },
4920
+ { name: "cachedAt", type: "number", default: 0 },
4921
+ { name: "ttlMs", type: "number", default: 3e5 },
4922
+ { name: "cacheHits", type: "number", default: 0 },
4923
+ { name: "cacheMisses", type: "number", default: 0 },
4924
+ { name: "isFresh", type: "boolean", default: false },
4925
+ { name: "lastAccessed", type: "number", default: 0 }
4926
+ ]
4927
+ },
4928
+ traits: [
4929
+ {
4930
+ name: "CacheAside",
4931
+ linkedEntity: "CacheEntry",
4932
+ category: "lifecycle",
4933
+ emits: [
4934
+ { event: "CACHE_HIT", scope: "internal" },
4935
+ { event: "CACHE_MISS", scope: "internal" },
4936
+ { event: "CACHE_EVICTED", scope: "internal" }
4937
+ ],
4938
+ stateMachine: {
4939
+ states: [
4940
+ { name: "Empty", isInitial: true },
4941
+ { name: "Fresh" },
4942
+ { name: "Stale" }
4943
+ ],
4944
+ events: [
4945
+ { key: "LOOKUP", name: "Cache Lookup" },
4946
+ { key: "POPULATE", name: "Populate Cache" },
4947
+ { key: "INVALIDATE", name: "Invalidate" },
4948
+ { key: "EVICT", name: "Evict" },
4949
+ { key: "EVICTION_TICK", name: "Eviction Tick" }
4950
+ ],
4951
+ transitions: [
4952
+ // Empty: lookup is a miss
4953
+ {
4954
+ from: "Empty",
4955
+ to: "Empty",
4956
+ event: "LOOKUP",
4957
+ effects: [
4958
+ ["set", "@entity.cacheMisses", ["+", "@entity.cacheMisses", 1]],
4959
+ ["set", "@entity.lastAccessed", ["time/now"]],
4960
+ ["emit", "CACHE_MISS", { key: "@entity.cacheKey" }]
4961
+ ]
4962
+ },
4963
+ // Empty → Fresh: populate after fetch
4964
+ {
4965
+ from: "Empty",
4966
+ to: "Fresh",
4967
+ event: "POPULATE",
4968
+ effects: [
4969
+ ["set", "@entity.cachedValue", "@payload.value"],
4970
+ ["set", "@entity.cacheKey", "@payload.key"],
4971
+ ["set", "@entity.cachedAt", ["time/now"]],
4972
+ ["set", "@entity.isFresh", true]
4973
+ ]
4974
+ },
4975
+ // Fresh: lookup is a hit
4976
+ {
4977
+ from: "Fresh",
4978
+ to: "Fresh",
4979
+ event: "LOOKUP",
4980
+ guard: ["<", ["-", ["time/now"], "@entity.cachedAt"], "@entity.ttlMs"],
4981
+ effects: [
4982
+ ["set", "@entity.cacheHits", ["+", "@entity.cacheHits", 1]],
4983
+ ["set", "@entity.lastAccessed", ["time/now"]],
4984
+ ["emit", "CACHE_HIT", { key: "@entity.cacheKey" }]
4985
+ ]
4986
+ },
4987
+ // Fresh → Stale: TTL expired on lookup
4988
+ {
4989
+ from: "Fresh",
4990
+ to: "Stale",
4991
+ event: "LOOKUP",
4992
+ guard: [">=", ["-", ["time/now"], "@entity.cachedAt"], "@entity.ttlMs"],
4993
+ effects: [
4994
+ ["set", "@entity.isFresh", false],
4995
+ ["set", "@entity.cacheMisses", ["+", "@entity.cacheMisses", 1]],
4996
+ ["set", "@entity.lastAccessed", ["time/now"]],
4997
+ ["emit", "CACHE_MISS", { key: "@entity.cacheKey", reason: "ttl_expired" }]
4998
+ ]
4999
+ },
5000
+ // Stale: lookup is a miss
5001
+ {
5002
+ from: "Stale",
5003
+ to: "Stale",
5004
+ event: "LOOKUP",
5005
+ effects: [
5006
+ ["set", "@entity.cacheMisses", ["+", "@entity.cacheMisses", 1]],
5007
+ ["set", "@entity.lastAccessed", ["time/now"]],
5008
+ ["emit", "CACHE_MISS", { key: "@entity.cacheKey", reason: "stale" }]
5009
+ ]
5010
+ },
5011
+ // Stale → Fresh: re-populate
5012
+ {
5013
+ from: "Stale",
5014
+ to: "Fresh",
5015
+ event: "POPULATE",
5016
+ effects: [
5017
+ ["set", "@entity.cachedValue", "@payload.value"],
5018
+ ["set", "@entity.cachedAt", ["time/now"]],
5019
+ ["set", "@entity.isFresh", true]
5020
+ ]
5021
+ },
5022
+ // Fresh → Fresh: update cache
5023
+ {
5024
+ from: "Fresh",
5025
+ to: "Fresh",
5026
+ event: "POPULATE",
5027
+ effects: [
5028
+ ["set", "@entity.cachedValue", "@payload.value"],
5029
+ ["set", "@entity.cachedAt", ["time/now"]]
5030
+ ]
5031
+ },
5032
+ // Invalidate from any cached state
5033
+ {
5034
+ from: ["Fresh", "Stale"],
5035
+ to: "Empty",
5036
+ event: "INVALIDATE",
5037
+ effects: [
5038
+ ["set", "@entity.cachedValue", null],
5039
+ ["set", "@entity.isFresh", false],
5040
+ ["set", "@entity.cachedAt", 0]
5041
+ ]
5042
+ },
5043
+ // Evict (with event)
5044
+ {
5045
+ from: ["Fresh", "Stale"],
5046
+ to: "Empty",
5047
+ event: "EVICT",
5048
+ effects: [
5049
+ ["set", "@entity.cachedValue", null],
5050
+ ["set", "@entity.isFresh", false],
5051
+ ["set", "@entity.cachedAt", 0],
5052
+ ["emit", "CACHE_EVICTED", { key: "@entity.cacheKey" }]
5053
+ ]
5054
+ },
5055
+ // Eviction tick: evict if stale
5056
+ {
5057
+ from: "Stale",
5058
+ to: "Empty",
5059
+ event: "EVICTION_TICK",
5060
+ effects: [
5061
+ ["set", "@entity.cachedValue", null],
5062
+ ["set", "@entity.isFresh", false],
5063
+ ["set", "@entity.cachedAt", 0],
5064
+ ["emit", "CACHE_EVICTED", { key: "@entity.cacheKey", reason: "ttl_eviction" }]
5065
+ ]
5066
+ }
5067
+ ]
5068
+ },
5069
+ ticks: [
5070
+ {
5071
+ name: "eviction_sweep",
5072
+ interval: "60000",
5073
+ guard: ["and", ["!=", "@entity.cachedAt", 0], [">=", ["-", ["time/now"], "@entity.cachedAt"], "@entity.ttlMs"]],
5074
+ effects: [["emit", "EVICTION_TICK"]],
5075
+ description: "Periodically evict stale cache entries"
5076
+ }
5077
+ ]
5078
+ }
5079
+ ],
5080
+ pages: []
5081
+ }
5082
+ ]
5083
+ };
5084
+ var SAGA_BEHAVIOR = {
5085
+ name: "std-saga",
5086
+ version: "1.0.0",
5087
+ description: "Saga pattern with step-by-step execution and reverse compensation on failure",
5088
+ orbitals: [
5089
+ {
5090
+ name: "SagaOrbital",
5091
+ entity: {
5092
+ name: "SagaState",
5093
+ persistence: "runtime",
5094
+ fields: [
5095
+ { name: "id", type: "string", required: true },
5096
+ { name: "sagaName", type: "string", default: "" },
5097
+ { name: "currentStep", type: "number", default: 0 },
5098
+ { name: "totalSteps", type: "number", default: 0 },
5099
+ { name: "sagaStatus", type: "string", default: "idle" },
5100
+ { name: "completedSteps", type: "array", default: [] },
5101
+ { name: "compensatedSteps", type: "array", default: [] },
5102
+ { name: "failedStep", type: "number", default: -1 },
5103
+ { name: "failureReason", type: "string", default: "" },
5104
+ { name: "startedAt", type: "number", default: 0 },
5105
+ { name: "completedAt", type: "number", default: 0 }
5106
+ ]
5107
+ },
5108
+ traits: [
5109
+ {
5110
+ name: "Saga",
5111
+ linkedEntity: "SagaState",
5112
+ category: "lifecycle",
5113
+ emits: [
5114
+ { event: "SAGA_STARTED", scope: "external" },
5115
+ { event: "SAGA_STEP_COMPLETED", scope: "external" },
5116
+ { event: "SAGA_COMPLETED", scope: "external" },
5117
+ { event: "SAGA_COMPENSATING", scope: "external" },
5118
+ { event: "SAGA_COMPENSATION_DONE", scope: "external" },
5119
+ { event: "SAGA_FAILED", scope: "external" }
5120
+ ],
5121
+ stateMachine: {
5122
+ states: [
5123
+ { name: "Idle", isInitial: true },
5124
+ { name: "Running" },
5125
+ { name: "Compensating" },
5126
+ { name: "Completed" },
5127
+ { name: "Failed" }
5128
+ ],
5129
+ events: [
5130
+ { key: "START_SAGA", name: "Start Saga" },
5131
+ { key: "STEP_SUCCESS", name: "Step Success" },
5132
+ { key: "STEP_FAILURE", name: "Step Failure" },
5133
+ { key: "COMPENSATE_SUCCESS", name: "Compensate Success" },
5134
+ { key: "COMPENSATE_FAILURE", name: "Compensate Failure" },
5135
+ { key: "RESET", name: "Reset" }
5136
+ ],
5137
+ transitions: [
5138
+ // Idle → Running: start the saga
5139
+ {
5140
+ from: "Idle",
5141
+ to: "Running",
5142
+ event: "START_SAGA",
5143
+ effects: [
5144
+ ["set", "@entity.sagaStatus", "running"],
5145
+ ["set", "@entity.currentStep", 0],
5146
+ ["set", "@entity.completedSteps", []],
5147
+ ["set", "@entity.compensatedSteps", []],
5148
+ ["set", "@entity.failedStep", -1],
5149
+ ["set", "@entity.failureReason", ""],
5150
+ ["set", "@entity.startedAt", ["time/now"]],
5151
+ ["emit", "SAGA_STARTED", { sagaName: "@entity.sagaName" }]
5152
+ ]
5153
+ },
5154
+ // Running: step success, more steps remaining
5155
+ {
5156
+ from: "Running",
5157
+ to: "Running",
5158
+ event: "STEP_SUCCESS",
5159
+ guard: ["<", ["+", "@entity.currentStep", 1], "@entity.totalSteps"],
5160
+ effects: [
5161
+ ["set", "@entity.currentStep", ["+", "@entity.currentStep", 1]],
5162
+ ["emit", "SAGA_STEP_COMPLETED", {
5163
+ step: "@entity.currentStep",
5164
+ totalSteps: "@entity.totalSteps"
5165
+ }]
5166
+ ]
5167
+ },
5168
+ // Running → Completed: last step succeeded
5169
+ {
5170
+ from: "Running",
5171
+ to: "Completed",
5172
+ event: "STEP_SUCCESS",
5173
+ guard: [">=", ["+", "@entity.currentStep", 1], "@entity.totalSteps"],
5174
+ effects: [
5175
+ ["set", "@entity.sagaStatus", "completed"],
5176
+ ["set", "@entity.completedAt", ["time/now"]],
5177
+ ["emit", "SAGA_COMPLETED", { sagaName: "@entity.sagaName" }]
5178
+ ]
5179
+ },
5180
+ // Running → Compensating: a step failed
5181
+ {
5182
+ from: "Running",
5183
+ to: "Compensating",
5184
+ event: "STEP_FAILURE",
5185
+ effects: [
5186
+ ["set", "@entity.sagaStatus", "compensating"],
5187
+ ["set", "@entity.failedStep", "@entity.currentStep"],
5188
+ ["emit", "SAGA_COMPENSATING", {
5189
+ failedStep: "@entity.currentStep",
5190
+ sagaName: "@entity.sagaName"
5191
+ }]
5192
+ ]
5193
+ },
5194
+ // Compensating: compensation step succeeded, more to undo
5195
+ {
5196
+ from: "Compensating",
5197
+ to: "Compensating",
5198
+ event: "COMPENSATE_SUCCESS",
5199
+ guard: [">", "@entity.currentStep", 0],
5200
+ effects: [
5201
+ ["set", "@entity.currentStep", ["-", "@entity.currentStep", 1]]
5202
+ ]
5203
+ },
5204
+ // Compensating → Failed: all compensations done (reached step 0)
5205
+ {
5206
+ from: "Compensating",
5207
+ to: "Failed",
5208
+ event: "COMPENSATE_SUCCESS",
5209
+ guard: ["<=", "@entity.currentStep", 0],
5210
+ effects: [
5211
+ ["set", "@entity.sagaStatus", "failed"],
5212
+ ["set", "@entity.completedAt", ["time/now"]],
5213
+ ["emit", "SAGA_COMPENSATION_DONE", { sagaName: "@entity.sagaName" }]
5214
+ ]
5215
+ },
5216
+ // Compensating → Failed: compensation itself failed
5217
+ {
5218
+ from: "Compensating",
5219
+ to: "Failed",
5220
+ event: "COMPENSATE_FAILURE",
5221
+ effects: [
5222
+ ["set", "@entity.sagaStatus", "failed"],
5223
+ ["set", "@entity.completedAt", ["time/now"]],
5224
+ ["emit", "SAGA_FAILED", {
5225
+ sagaName: "@entity.sagaName",
5226
+ reason: "Compensation failed"
5227
+ }]
5228
+ ]
5229
+ },
5230
+ // Reset from terminal states
5231
+ {
5232
+ from: ["Completed", "Failed"],
5233
+ to: "Idle",
5234
+ event: "RESET",
5235
+ effects: [
5236
+ ["set", "@entity.sagaStatus", "idle"],
5237
+ ["set", "@entity.currentStep", 0],
5238
+ ["set", "@entity.completedSteps", []],
5239
+ ["set", "@entity.compensatedSteps", []],
5240
+ ["set", "@entity.failedStep", -1],
5241
+ ["set", "@entity.failureReason", ""]
5242
+ ]
5243
+ }
5244
+ ]
5245
+ },
5246
+ ticks: []
5247
+ }
5248
+ ],
5249
+ pages: []
5250
+ }
5251
+ ]
5252
+ };
5253
+ var METRICS_COLLECTOR_BEHAVIOR = {
5254
+ name: "std-metrics-collector",
5255
+ version: "1.0.0",
5256
+ description: "Tick-based metrics aggregation with periodic flush and reporting",
5257
+ orbitals: [
5258
+ {
5259
+ name: "MetricsCollectorOrbital",
5260
+ entity: {
5261
+ name: "MetricsState",
5262
+ persistence: "runtime",
5263
+ fields: [
5264
+ { name: "id", type: "string", required: true },
5265
+ { name: "counters", type: "object", default: {} },
5266
+ { name: "gauges", type: "object", default: {} },
5267
+ { name: "lastFlush", type: "number", default: 0 },
5268
+ { name: "flushIntervalMs", type: "number", default: 6e4 },
5269
+ { name: "totalFlushes", type: "number", default: 0 },
5270
+ { name: "totalRecorded", type: "number", default: 0 }
5271
+ ]
5272
+ },
5273
+ traits: [
5274
+ {
5275
+ name: "MetricsCollector",
5276
+ linkedEntity: "MetricsState",
5277
+ category: "lifecycle",
5278
+ emits: [
5279
+ { event: "METRICS_REPORT", scope: "external" }
5280
+ ],
5281
+ stateMachine: {
5282
+ states: [
5283
+ { name: "Collecting", isInitial: true }
5284
+ ],
5285
+ events: [
5286
+ { key: "RECORD_COUNTER", name: "Record Counter" },
5287
+ { key: "RECORD_GAUGE", name: "Record Gauge" },
5288
+ { key: "FLUSH", name: "Flush Metrics" },
5289
+ { key: "RESET", name: "Reset All" }
5290
+ ],
5291
+ transitions: [
5292
+ // Record a counter increment
5293
+ {
5294
+ from: "Collecting",
5295
+ to: "Collecting",
5296
+ event: "RECORD_COUNTER",
5297
+ effects: [
5298
+ ["set", "@entity.totalRecorded", ["+", "@entity.totalRecorded", 1]]
5299
+ ]
5300
+ },
5301
+ // Record a gauge value
5302
+ {
5303
+ from: "Collecting",
5304
+ to: "Collecting",
5305
+ event: "RECORD_GAUGE",
5306
+ effects: [
5307
+ ["set", "@entity.totalRecorded", ["+", "@entity.totalRecorded", 1]]
5308
+ ]
5309
+ },
5310
+ // Flush: emit report and reset counters
5311
+ {
5312
+ from: "Collecting",
5313
+ to: "Collecting",
5314
+ event: "FLUSH",
5315
+ effects: [
5316
+ ["emit", "METRICS_REPORT", {
5317
+ counters: "@entity.counters",
5318
+ gauges: "@entity.gauges",
5319
+ totalRecorded: "@entity.totalRecorded"
5320
+ }],
5321
+ ["set", "@entity.counters", {}],
5322
+ ["set", "@entity.lastFlush", ["time/now"]],
5323
+ ["set", "@entity.totalFlushes", ["+", "@entity.totalFlushes", 1]]
5324
+ ]
5325
+ },
5326
+ // Full reset
5327
+ {
5328
+ from: "Collecting",
5329
+ to: "Collecting",
5330
+ event: "RESET",
5331
+ effects: [
5332
+ ["set", "@entity.counters", {}],
5333
+ ["set", "@entity.gauges", {}],
5334
+ ["set", "@entity.totalRecorded", 0],
5335
+ ["set", "@entity.totalFlushes", 0],
5336
+ ["set", "@entity.lastFlush", 0]
5337
+ ]
5338
+ }
5339
+ ]
5340
+ },
5341
+ ticks: [
5342
+ {
5343
+ name: "periodic_flush",
5344
+ interval: "@entity.flushIntervalMs",
5345
+ guard: [">", "@entity.totalRecorded", 0],
5346
+ effects: [["emit", "FLUSH"]],
5347
+ description: "Periodically flush accumulated metrics"
5348
+ }
5349
+ ]
5350
+ }
5351
+ ],
5352
+ pages: []
5353
+ }
5354
+ ]
5355
+ };
5356
+ var INFRASTRUCTURE_BEHAVIORS = [
5357
+ CIRCUIT_BREAKER_BEHAVIOR,
5358
+ HEALTH_CHECK_BEHAVIOR,
5359
+ RATE_LIMITER_BEHAVIOR,
5360
+ CACHE_ASIDE_BEHAVIOR,
5361
+ SAGA_BEHAVIOR,
5362
+ METRICS_COLLECTOR_BEHAVIOR
5363
+ ];
5364
+
4428
5365
  // behaviors/registry.ts
4429
5366
  var STANDARD_BEHAVIORS = [
4430
5367
  ...UI_INTERACTION_BEHAVIORS,
@@ -4433,7 +5370,8 @@ var STANDARD_BEHAVIORS = [
4433
5370
  ...FEEDBACK_BEHAVIORS,
4434
5371
  ...GAME_CORE_BEHAVIORS,
4435
5372
  ...GAME_ENTITY_BEHAVIORS,
4436
- ...GAME_UI_BEHAVIORS
5373
+ ...GAME_UI_BEHAVIORS,
5374
+ ...INFRASTRUCTURE_BEHAVIORS
4437
5375
  ];
4438
5376
  var BEHAVIOR_REGISTRY = STANDARD_BEHAVIORS.reduce(
4439
5377
  (acc, behavior) => {
@@ -4567,6 +5505,6 @@ function getBehaviorLibraryStats() {
4567
5505
  };
4568
5506
  }
4569
5507
 
4570
- export { ACTION_AFFINITY, ASYNC_BEHAVIORS, BEHAVIOR_REGISTRY, COLLISION_BEHAVIOR, COMBAT_BEHAVIOR, CONFIRMATION_BEHAVIOR, DATA_MANAGEMENT_BEHAVIORS, DETAIL_BEHAVIOR, DIALOGUE_BEHAVIOR, DRAWER_BEHAVIOR, FEEDBACK_BEHAVIORS, FETCH_BEHAVIOR, FILTER_BEHAVIOR2 as FILTER_BEHAVIOR, FORM_BEHAVIOR, GAME_CORE_BEHAVIORS, GAME_ENTITY_BEHAVIORS, GAME_FLOW_BEHAVIOR, GAME_LOOP_BEHAVIOR, GAME_UI_BEHAVIORS, HEALTH_BEHAVIOR, INPUT_BEHAVIOR, INVENTORY_BEHAVIOR, LEVEL_PROGRESS_BEHAVIOR, LIST_BEHAVIOR, LOADING_BEHAVIOR, MASTER_DETAIL_BEHAVIOR, MODAL_BEHAVIOR, MOVEMENT_BEHAVIOR, NOTIFICATION_BEHAVIOR, PAGINATION_BEHAVIOR, PHYSICS_2D_BEHAVIOR, POLL_BEHAVIOR, RETRY_BEHAVIOR, SCORE_BEHAVIOR, SEARCH_BEHAVIOR, SELECTION_BEHAVIOR, SORT_BEHAVIOR, STANDARD_BEHAVIORS, SUBMIT_BEHAVIOR, TABS_BEHAVIOR, UI_EVENTS, UI_INTERACTION_BEHAVIORS, UNDO_BEHAVIOR, WIZARD_BEHAVIOR, findBehaviorsForUseCase, getAllBehaviorMetadata, getAllBehaviorNames, getAllBehaviors, getAllKnownComponents, getBehavior, getBehaviorLibraryStats, getBehaviorMetadata, getBehaviorsForEvent, getBehaviorsWithState, getComponentsByCategory, getComponentsForEvent, getInvalidActionsForComponent, getValidActionsForComponent, isActionInvalidForComponent, isActionValidForComponent, isKnownBehavior, validateActionsForComponent, validateBehaviorEvents, validateBehaviorReference, validateBehaviorStates, validateBehaviorStructure };
5508
+ export { ACTION_AFFINITY, ASYNC_BEHAVIORS, BEHAVIOR_REGISTRY, CACHE_ASIDE_BEHAVIOR, CIRCUIT_BREAKER_BEHAVIOR, COLLISION_BEHAVIOR, COMBAT_BEHAVIOR, CONFIRMATION_BEHAVIOR, DATA_MANAGEMENT_BEHAVIORS, DETAIL_BEHAVIOR, DIALOGUE_BEHAVIOR, DRAWER_BEHAVIOR, FEEDBACK_BEHAVIORS, FETCH_BEHAVIOR, FILTER_BEHAVIOR2 as FILTER_BEHAVIOR, FORM_BEHAVIOR, GAME_CORE_BEHAVIORS, GAME_ENTITY_BEHAVIORS, GAME_FLOW_BEHAVIOR, GAME_LOOP_BEHAVIOR, GAME_UI_BEHAVIORS, HEALTH_BEHAVIOR, HEALTH_CHECK_BEHAVIOR, INFRASTRUCTURE_BEHAVIORS, INPUT_BEHAVIOR, INVENTORY_BEHAVIOR, LEVEL_PROGRESS_BEHAVIOR, LIST_BEHAVIOR, LOADING_BEHAVIOR, MASTER_DETAIL_BEHAVIOR, METRICS_COLLECTOR_BEHAVIOR, MODAL_BEHAVIOR, MOVEMENT_BEHAVIOR, NOTIFICATION_BEHAVIOR, PAGINATION_BEHAVIOR, PHYSICS_2D_BEHAVIOR, POLL_BEHAVIOR, RATE_LIMITER_BEHAVIOR, RETRY_BEHAVIOR, SAGA_BEHAVIOR, SCORE_BEHAVIOR, SEARCH_BEHAVIOR, SELECTION_BEHAVIOR, SORT_BEHAVIOR, STANDARD_BEHAVIORS, SUBMIT_BEHAVIOR, TABS_BEHAVIOR, UI_EVENTS, UI_INTERACTION_BEHAVIORS, UNDO_BEHAVIOR, WIZARD_BEHAVIOR, findBehaviorsForUseCase, getAllBehaviorMetadata, getAllBehaviorNames, getAllBehaviors, getAllKnownComponents, getBehavior, getBehaviorLibraryStats, getBehaviorMetadata, getBehaviorsForEvent, getBehaviorsWithState, getComponentsByCategory, getComponentsForEvent, getInvalidActionsForComponent, getValidActionsForComponent, isActionInvalidForComponent, isActionValidForComponent, isKnownBehavior, validateActionsForComponent, validateBehaviorEvents, validateBehaviorReference, validateBehaviorStates, validateBehaviorStructure };
4571
5509
  //# sourceMappingURL=index.js.map
4572
5510
  //# sourceMappingURL=index.js.map