@carrierllc/mcp 0.10.7 → 0.11.4

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/dist/index.js CHANGED
@@ -27,12 +27,14 @@ import {
27
27
  generateStorefrontLogo,
28
28
  getLimitForEndpoint,
29
29
  getRateLimitWindowCounts,
30
+ gyCountryHistoryFromResponse,
30
31
  imsiFromSubscriberRecord,
31
32
  isActivePackage,
32
33
  isTargetId,
33
34
  lastNDaysPeriod,
34
35
  loadStorefrontBrand,
35
36
  locationParams,
37
+ mccToIso,
36
38
  mergeEnvLocal,
37
39
  networkEventRows,
38
40
  networkEventsOverPeriodParams,
@@ -54,6 +56,7 @@ import {
54
56
  recurringPackageParams,
55
57
  renderHtml,
56
58
  repairPlanFor,
59
+ staleActivePackages,
57
60
  storefrontClerkUrls,
58
61
  subscriberIdParams,
59
62
  subscriberRows,
@@ -62,7 +65,7 @@ import {
62
65
  usageOverPeriodParams,
63
66
  verifyStorefront,
64
67
  withOcsListSummary
65
- } from "./chunk-KYS5GHJV.js";
68
+ } from "./chunk-625SBKRG.js";
66
69
  import "./chunk-SHKKVIIA.js";
67
70
 
68
71
  // src/index.ts
@@ -3507,506 +3510,44 @@ var ocs_methods_default = {
3507
3510
  ui_resource_uri: "ui://balance-topup-form",
3508
3511
  verified_against_server: false,
3509
3512
  verified_against_live_docs: false
3513
+ },
3514
+ {
3515
+ name: "subscriber_investigator_app",
3516
+ category: "apps",
3517
+ scope: "read",
3518
+ description: "MCP App: Subscriber Investigator \u2014 single-subscriber drill-down panel (identity, packages, usage, network events). Read-only, no destructive ops.",
3519
+ min_tier: "free",
3520
+ destructive: false,
3521
+ ui_resource_uri: "ui://apps/subscriber-investigator",
3522
+ verified_against_server: false,
3523
+ verified_against_live_docs: false
3524
+ },
3525
+ {
3526
+ name: "template_zone_builder_app",
3527
+ category: "apps",
3528
+ scope: "write",
3529
+ description: "MCP App: Template & Zone Builder \u2014 multi-step builder for a package template or location zone, with a preview step before the confirm write. Pro tier minimum; refused for managed sessions at the OCS scope layer.",
3530
+ min_tier: "pro",
3531
+ destructive: true,
3532
+ destructive_step: 4,
3533
+ ui_resource_uri: "ui://apps/template-builder",
3534
+ verified_against_server: false,
3535
+ verified_against_live_docs: false
3536
+ },
3537
+ {
3538
+ name: "action_receipt_app",
3539
+ category: "apps",
3540
+ scope: "write",
3541
+ description: "MCP App: Action Receipt & Rollback Viewer \u2014 ledger of recorded write actions with verification evidence and rollback where a rollback method was recorded. Viewing/recording needs no OCS write; rollback requires write scope.",
3542
+ min_tier: "free",
3543
+ destructive: true,
3544
+ ui_resource_uri: "ui://apps/action-receipt",
3545
+ verified_against_server: false,
3546
+ verified_against_live_docs: false
3510
3547
  }
3511
3548
  ]
3512
3549
  };
3513
3550
 
3514
- // ../../packages/ocs-spec/src/mcc-iso.ts
3515
- var MCC_TO_ISO = {
3516
- // Europe
3517
- 202: "GR",
3518
- // Greece
3519
- 204: "NL",
3520
- // Netherlands
3521
- 206: "BE",
3522
- // Belgium
3523
- 208: "FR",
3524
- // France
3525
- 212: "MC",
3526
- // Monaco
3527
- 213: "AD",
3528
- // Andorra
3529
- 214: "ES",
3530
- // Spain
3531
- 216: "HU",
3532
- // Hungary
3533
- 218: "BA",
3534
- // Bosnia and Herzegovina
3535
- 219: "HR",
3536
- // Croatia
3537
- 220: "RS",
3538
- // Serbia
3539
- 221: "XK",
3540
- // Kosovo
3541
- 222: "IT",
3542
- // Italy
3543
- 225: "VA",
3544
- // Vatican City
3545
- 226: "RO",
3546
- // Romania
3547
- 228: "CH",
3548
- // Switzerland
3549
- 230: "CZ",
3550
- // Czech Republic
3551
- 231: "SK",
3552
- // Slovakia
3553
- 232: "AT",
3554
- // Austria
3555
- 234: "GB",
3556
- // United Kingdom
3557
- 235: "GB",
3558
- // United Kingdom
3559
- 238: "DK",
3560
- // Denmark
3561
- 240: "SE",
3562
- // Sweden
3563
- 242: "NO",
3564
- // Norway
3565
- 244: "FI",
3566
- // Finland
3567
- 246: "LT",
3568
- // Lithuania
3569
- 247: "LV",
3570
- // Latvia
3571
- 248: "EE",
3572
- // Estonia
3573
- 250: "RU",
3574
- // Russia
3575
- 255: "UA",
3576
- // Ukraine
3577
- 257: "BY",
3578
- // Belarus
3579
- 259: "MD",
3580
- // Moldova
3581
- 260: "PL",
3582
- // Poland
3583
- 262: "DE",
3584
- // Germany
3585
- 266: "GI",
3586
- // Gibraltar
3587
- 268: "PT",
3588
- // Portugal
3589
- 270: "LU",
3590
- // Luxembourg
3591
- 272: "IE",
3592
- // Ireland
3593
- 274: "IS",
3594
- // Iceland
3595
- 276: "AL",
3596
- // Albania
3597
- 278: "MT",
3598
- // Malta
3599
- 280: "CY",
3600
- // Cyprus
3601
- 282: "GE",
3602
- // Georgia
3603
- 283: "AM",
3604
- // Armenia
3605
- 284: "BG",
3606
- // Bulgaria
3607
- 286: "TR",
3608
- // Turkey
3609
- 288: "FO",
3610
- // Faroe Islands
3611
- 289: "GE",
3612
- // Abkhazia (Georgia)
3613
- 290: "GL",
3614
- // Greenland
3615
- 292: "SM",
3616
- // San Marino
3617
- 293: "SI",
3618
- // Slovenia
3619
- 294: "MK",
3620
- // North Macedonia
3621
- 295: "LI",
3622
- // Liechtenstein
3623
- 297: "ME",
3624
- // Montenegro
3625
- // Commonwealth of Independent States / Former USSR
3626
- 401: "KZ",
3627
- // Kazakhstan
3628
- 402: "BT",
3629
- // Bhutan
3630
- 404: "IN",
3631
- // India
3632
- 405: "IN",
3633
- // India
3634
- 406: "IN",
3635
- // India
3636
- 410: "PK",
3637
- // Pakistan
3638
- 412: "AF",
3639
- // Afghanistan
3640
- 413: "LK",
3641
- // Sri Lanka
3642
- 414: "MM",
3643
- // Myanmar
3644
- 415: "LB",
3645
- // Lebanon
3646
- 416: "JO",
3647
- // Jordan
3648
- 417: "SY",
3649
- // Syria
3650
- 418: "IQ",
3651
- // Iraq
3652
- 419: "KW",
3653
- // Kuwait
3654
- 420: "SA",
3655
- // Saudi Arabia
3656
- 421: "YE",
3657
- // Yemen
3658
- 422: "OM",
3659
- // Oman
3660
- 424: "AE",
3661
- // United Arab Emirates
3662
- 425: "IL",
3663
- // Israel
3664
- 426: "BH",
3665
- // Bahrain
3666
- 427: "QA",
3667
- // Qatar
3668
- 428: "MN",
3669
- // Mongolia
3670
- 429: "NP",
3671
- // Nepal
3672
- 430: "AE",
3673
- // United Arab Emirates
3674
- 431: "AE",
3675
- // United Arab Emirates
3676
- 432: "IR",
3677
- // Iran
3678
- 434: "UZ",
3679
- // Uzbekistan
3680
- 436: "TJ",
3681
- // Tajikistan
3682
- 437: "KG",
3683
- // Kyrgyzstan
3684
- 438: "TM",
3685
- // Turkmenistan
3686
- 440: "JP",
3687
- // Japan
3688
- 441: "JP",
3689
- // Japan
3690
- 450: "KR",
3691
- // South Korea
3692
- 452: "VN",
3693
- // Vietnam
3694
- 454: "HK",
3695
- // Hong Kong
3696
- 455: "MO",
3697
- // Macau
3698
- 456: "KH",
3699
- // Cambodia
3700
- 457: "LA",
3701
- // Laos
3702
- 460: "CN",
3703
- // China
3704
- 461: "CN",
3705
- // China
3706
- 466: "TW",
3707
- // Taiwan
3708
- 467: "KP",
3709
- // North Korea
3710
- 470: "BD",
3711
- // Bangladesh
3712
- 472: "MV",
3713
- // Maldives
3714
- 502: "MY",
3715
- // Malaysia
3716
- 505: "AU",
3717
- // Australia
3718
- 510: "ID",
3719
- // Indonesia
3720
- 514: "TL",
3721
- // East Timor
3722
- 515: "PH",
3723
- // Philippines
3724
- 520: "TH",
3725
- // Thailand
3726
- 525: "SG",
3727
- // Singapore
3728
- 528: "BN",
3729
- // Brunei
3730
- 530: "NZ",
3731
- // New Zealand
3732
- 536: "NR",
3733
- // Nauru
3734
- 537: "PG",
3735
- // Papua New Guinea
3736
- 539: "TO",
3737
- // Tonga
3738
- 540: "SB",
3739
- // Solomon Islands
3740
- 541: "VU",
3741
- // Vanuatu
3742
- 542: "FJ",
3743
- // Fiji
3744
- 544: "AS",
3745
- // American Samoa
3746
- 545: "KI",
3747
- // Kiribati
3748
- 546: "NC",
3749
- // New Caledonia
3750
- 547: "PF",
3751
- // French Polynesia
3752
- 548: "CK",
3753
- // Cook Islands
3754
- 549: "WS",
3755
- // Samoa
3756
- 550: "FM",
3757
- // Micronesia
3758
- 551: "MH",
3759
- // Marshall Islands
3760
- 552: "PW",
3761
- // Palau
3762
- 553: "TV",
3763
- // Tuvalu
3764
- 555: "NU",
3765
- // Niue
3766
- // Africa (ITU-T E.212)
3767
- 602: "EG",
3768
- // Egypt
3769
- 603: "DZ",
3770
- // Algeria
3771
- 604: "MA",
3772
- // Morocco
3773
- 605: "TN",
3774
- // Tunisia
3775
- 606: "LY",
3776
- // Libya
3777
- 607: "GM",
3778
- // Gambia
3779
- 608: "SN",
3780
- // Senegal
3781
- 609: "MR",
3782
- // Mauritania
3783
- 610: "ML",
3784
- // Mali
3785
- 611: "GN",
3786
- // Guinea
3787
- 612: "CI",
3788
- // Côte d'Ivoire
3789
- 613: "BF",
3790
- // Burkina Faso
3791
- 614: "NE",
3792
- // Niger
3793
- 615: "TG",
3794
- // Togo
3795
- 616: "BJ",
3796
- // Benin
3797
- 617: "MU",
3798
- // Mauritius
3799
- 618: "LR",
3800
- // Liberia
3801
- 619: "SL",
3802
- // Sierra Leone
3803
- 620: "GH",
3804
- // Ghana
3805
- 621: "NG",
3806
- // Nigeria
3807
- 622: "TD",
3808
- // Chad
3809
- 623: "CF",
3810
- // Central African Republic
3811
- 624: "CM",
3812
- // Cameroon
3813
- 625: "CV",
3814
- // Cape Verde
3815
- 626: "ST",
3816
- // São Tomé and Príncipe
3817
- 627: "GQ",
3818
- // Equatorial Guinea
3819
- 628: "GA",
3820
- // Gabon
3821
- 629: "CG",
3822
- // Republic of the Congo
3823
- 630: "CD",
3824
- // Democratic Republic of the Congo
3825
- 631: "AO",
3826
- // Angola
3827
- 632: "GW",
3828
- // Guinea-Bissau
3829
- 633: "SC",
3830
- // Seychelles
3831
- 634: "SD",
3832
- // Sudan
3833
- 635: "RW",
3834
- // Rwanda
3835
- 636: "ET",
3836
- // Ethiopia
3837
- 637: "SO",
3838
- // Somalia
3839
- 638: "DJ",
3840
- // Djibouti
3841
- 639: "KE",
3842
- // Kenya
3843
- 640: "TZ",
3844
- // Tanzania
3845
- 641: "UG",
3846
- // Uganda
3847
- 642: "BI",
3848
- // Burundi
3849
- 643: "MZ",
3850
- // Mozambique
3851
- 645: "ZM",
3852
- // Zambia
3853
- 646: "MG",
3854
- // Madagascar
3855
- 647: "RE",
3856
- // Réunion / French Indian Ocean
3857
- 648: "ZW",
3858
- // Zimbabwe
3859
- 649: "NA",
3860
- // Namibia
3861
- 650: "MW",
3862
- // Malawi
3863
- 651: "LS",
3864
- // Lesotho
3865
- 652: "BW",
3866
- // Botswana
3867
- 653: "SZ",
3868
- // Eswatini
3869
- 654: "KM",
3870
- // Comoros
3871
- 655: "ZA",
3872
- // South Africa
3873
- 657: "ER",
3874
- // Eritrea
3875
- 658: "SH",
3876
- // Saint Helena
3877
- 659: "SS",
3878
- // South Sudan
3879
- 702: "BZ",
3880
- // Belize
3881
- 704: "GT",
3882
- // Guatemala
3883
- 706: "SV",
3884
- // El Salvador
3885
- 708: "HN",
3886
- // Honduras
3887
- 710: "NI",
3888
- // Nicaragua
3889
- 712: "CR",
3890
- // Costa Rica
3891
- 714: "PA",
3892
- // Panama
3893
- 716: "PE",
3894
- // Peru
3895
- 722: "AR",
3896
- // Argentina
3897
- 724: "BR",
3898
- // Brazil
3899
- 730: "CL",
3900
- // Chile
3901
- 732: "CO",
3902
- // Colombia
3903
- 734: "VE",
3904
- // Venezuela
3905
- 736: "BO",
3906
- // Bolivia
3907
- 738: "GY",
3908
- // Guyana
3909
- 740: "EC",
3910
- // Ecuador
3911
- 742: "GF",
3912
- // French Guiana
3913
- 744: "PY",
3914
- // Paraguay
3915
- 746: "SR",
3916
- // Suriname
3917
- 748: "UY",
3918
- // Uruguay
3919
- 750: "FK",
3920
- // Falkland Islands
3921
- // North America, Caribbean
3922
- 302: "CA",
3923
- // Canada
3924
- 308: "PM",
3925
- // Saint Pierre and Miquelon
3926
- 310: "US",
3927
- // United States
3928
- 311: "US",
3929
- // United States
3930
- 312: "US",
3931
- // United States
3932
- 313: "US",
3933
- // United States
3934
- 314: "US",
3935
- // United States
3936
- 315: "US",
3937
- // United States
3938
- 316: "US",
3939
- // United States
3940
- 330: "PR",
3941
- // Puerto Rico
3942
- 332: "VI",
3943
- // U.S. Virgin Islands
3944
- 334: "MX",
3945
- // Mexico
3946
- 338: "JM",
3947
- // Jamaica
3948
- 340: "GP",
3949
- // Guadeloupe
3950
- 342: "BB",
3951
- // Barbados
3952
- 344: "AG",
3953
- // Antigua and Barbuda
3954
- 346: "KY",
3955
- // Cayman Islands
3956
- 348: "VG",
3957
- // British Virgin Islands
3958
- 350: "BM",
3959
- // Bermuda
3960
- 352: "GD",
3961
- // Grenada
3962
- 354: "MS",
3963
- // Montserrat
3964
- 356: "KN",
3965
- // Saint Kitts and Nevis
3966
- 358: "LC",
3967
- // Saint Lucia
3968
- 360: "VC",
3969
- // Saint Vincent and the Grenadines
3970
- 362: "CW",
3971
- // Curaçao / Netherlands Antilles
3972
- 363: "AW",
3973
- // Aruba
3974
- 364: "BS",
3975
- // Bahamas
3976
- 365: "AI",
3977
- // Anguilla
3978
- 366: "DM",
3979
- // Dominica
3980
- 368: "CU",
3981
- // Cuba
3982
- 370: "DO",
3983
- // Dominican Republic
3984
- 372: "HT",
3985
- // Haiti
3986
- 374: "TT",
3987
- // Trinidad and Tobago
3988
- 376: "TC",
3989
- // Turks and Caicos Islands
3990
- // Special / Test MCCs
3991
- 999: "XX",
3992
- // Test network
3993
- 901: "XX"
3994
- // International / satellite
3995
- };
3996
- function mccToIso(mcc) {
3997
- if (mcc == null) return null;
3998
- let n;
3999
- if (typeof mcc === "string") {
4000
- const trimmed = mcc.trim();
4001
- if (trimmed === "" || !/^\d+$/.test(trimmed)) return null;
4002
- n = parseInt(trimmed, 10);
4003
- } else {
4004
- n = mcc;
4005
- }
4006
- if (!Number.isFinite(n)) return null;
4007
- return MCC_TO_ISO[n] ?? null;
4008
- }
4009
-
4010
3551
  // ../../packages/ocs-spec/src/index.ts
4011
3552
  var ocsSpec = ocs_methods_default;
4012
3553
  var ocsMethods = ocsSpec.v1_methods;
@@ -4083,8 +3624,19 @@ function registerIntelligenceTools(server2, ctx) {
4083
3624
  severity = "critical";
4084
3625
  }
4085
3626
  const pkgs = await safeCall(ctx.env, token2, "listSubscriberPrepaidPackages", { iccid });
4086
- const activePkgs = prepaidPackageRows(pkgs.data).filter(isActivePackage);
3627
+ const allPkgs = prepaidPackageRows(pkgs.data);
3628
+ const activePkgs = allPkgs.filter((p) => isActivePackage(p));
3629
+ const stalePkgs = staleActivePackages(allPkgs);
4087
3630
  if (!pkgs.error) {
3631
+ for (const pkg of stalePkgs) {
3632
+ const label = packageName(pkg);
3633
+ const days = Math.abs(daysUntil(packageExpiry(pkg)));
3634
+ findings.push(
3635
+ `Package "${label}" is flagged active but expired ${days} days ago \u2014 it grants nothing`
3636
+ );
3637
+ actions.push("Deactivate the stale row via modify_package_status (status INACTIVE)");
3638
+ if (severity !== "critical") severity = "warning";
3639
+ }
4088
3640
  if (activePkgs.length === 0) {
4089
3641
  findings.push("No active packages \u2014 subscriber has no data/voice/SMS allowance");
4090
3642
  actions.push("Assign a package via assign_package");
@@ -9673,11 +9225,13 @@ var CURATED_ROUTER_TOOLS = [
9673
9225
  },
9674
9226
  {
9675
9227
  name: "subscriber_country_history",
9676
- description: "Return cross-border movement history for a subscriber from Relay LU events. Intent: 'where has subscriber X traveled', 'country history for ICCID', 'border crossings', 'which countries did this SIM visit', 'travel history'.",
9228
+ description: "Return cross-border movement history for a subscriber, reconstructed from OCS Gy charging events. Intent: 'where has subscriber X traveled', 'country history for ICCID', 'border crossings', 'which countries did this SIM visit', 'travel history'.",
9677
9229
  input_schema: {
9678
9230
  type: "object",
9679
9231
  properties: {
9680
9232
  subscriberId: { type: "string" },
9233
+ startDate: { type: "string" },
9234
+ endDate: { type: "string" },
9681
9235
  limit: { type: "number" }
9682
9236
  },
9683
9237
  required: ["subscriberId"]
@@ -10749,15 +10303,32 @@ function registerDepletionEventsTool(server2, ctx) {
10749
10303
 
10750
10304
  // src/tools-country-history.ts
10751
10305
  import { z as z15 } from "zod";
10306
+ function isoDate(now, daysAgo = 0) {
10307
+ const d = new Date(now.getTime() - daysAgo * 864e5);
10308
+ return d.toISOString().slice(0, 10);
10309
+ }
10310
+ function staysAsCountryEvents(stays) {
10311
+ return stays.map((stay, idx) => ({
10312
+ event_id: `gy-${stay.country}-${stay.first_seen}`,
10313
+ new_country: stay.country,
10314
+ previous_country: idx === 0 ? null : stays[idx - 1].country,
10315
+ mcc: stay.mccs[0] ?? null,
10316
+ mnc: null,
10317
+ timestamp: stay.first_seen,
10318
+ source: "ocs-gy"
10319
+ })).reverse();
10320
+ }
10752
10321
  function registerCountryHistoryTool(server2, ctx) {
10753
10322
  server2.registerTool(
10754
10323
  "subscriber_country_history",
10755
10324
  {
10756
10325
  title: "Subscriber Country History",
10757
- description: "Return cross-border movement history for a subscriber from Relay LU events. Reads country.entered events from the OCS ring-buffer (24h window, up to `limit` entries per request) written by the Bridge4IP Relay LU webhook. Each entry includes the new country, previous country, MCC/MNC, and timestamp. Use this to answer: 'where has subscriber X traveled', 'show country history for ICCID', 'border crossings for this SIM'. Params: `subscriberId` (ICCID, 19\u201320 digits), `limit` (1\u201350, default 20, newest first). Returns: ordered list of country.entered events with { new_country, previous_country, mcc, mnc, timestamp, source }. Empty list when no cross-border events recorded. Do NOT use this for raw location events \u2014 use `list_recent_ocs_events` with event_types=['location.changed'] for finer-grained location data.",
10326
+ description: "Return cross-border movement history for a subscriber, reconstructed from OCS Gy charging events. Reads `gyAnswer.events` from `subscriberNetworkEventsOverPeriod` \u2014 every Gy record carries its own country, operator and MCC \u2014 and collapses consecutive same-country records into stays with first-seen and last-seen timestamps. This needs no webhook: it works with Relay LU and Relay Gy off. Relay `country.entered` events from the 24h ring-buffer are merged in as a supplement when present. Use this to answer: 'where has subscriber X traveled', 'show country history for ICCID', 'border crossings for this SIM'. Params: `subscriberId` (ICCID, 19\u201320 digits), `startDate`/`endDate` (YYYY-MM-DD, max 7 days apart, default the last 7 days), `limit` (1\u201350, default 20, newest first). Returns: `stays` ({ country, country_name, first_seen, last_seen, operators, mccs, event_count, used_bytes }), `transitions` ({ from, to, at }), and `country_events` in the legacy flat shape. `used_bytes` already handles the string-typed `usedUnits` and its 'N/A' values. Do NOT use this for raw per-session records \u2014 use `subscriber_network_events` for those.",
10758
10327
  inputSchema: {
10759
10328
  subscriberId: z15.string().regex(/^\d{19,20}$/, "subscriberId must be a 19\u201320 digit ICCID").describe("Subscriber ICCID (19\u201320 digits, ITU-T E.118)"),
10760
- limit: z15.number().int().min(1).max(50).default(20).optional().describe("Maximum number of events to return, newest first (default 20, max 50)")
10329
+ startDate: z15.string().regex(/^\d{4}-\d{2}-\d{2}$/, "startDate must be YYYY-MM-DD").optional().describe("Start of the period, YYYY-MM-DD inclusive (default: 7 days ago)"),
10330
+ endDate: z15.string().regex(/^\d{4}-\d{2}-\d{2}$/, "endDate must be YYYY-MM-DD").optional().describe("End of the period, YYYY-MM-DD inclusive, max 7 days from start (default: today)"),
10331
+ limit: z15.number().int().min(1).max(50).default(20).optional().describe("Maximum number of country_events to return, newest first (default 20, max 50)")
10761
10332
  },
10762
10333
  annotations: { readOnlyHint: true, idempotentHint: true }
10763
10334
  },
@@ -10766,12 +10337,31 @@ function registerCountryHistoryTool(server2, ctx) {
10766
10337
  "getSingleSubscriber",
10767
10338
  "read",
10768
10339
  ctx,
10769
- async ({ subscriberId, limit }, token2) => {
10340
+ async ({
10341
+ subscriberId,
10342
+ startDate,
10343
+ endDate,
10344
+ limit
10345
+ }, token2) => {
10770
10346
  const effectiveLimit = limit ?? 20;
10347
+ const now = /* @__PURE__ */ new Date();
10348
+ const end = endDate ?? isoDate(now);
10349
+ const start = startDate ?? isoDate(now, 7);
10771
10350
  const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
10772
10351
  const subscriberPayload = await client2.call("getSingleSubscriber", {
10773
10352
  iccid: subscriberId
10774
10353
  });
10354
+ let gy = gyCountryHistoryFromResponse(void 0);
10355
+ let gyError = null;
10356
+ try {
10357
+ const events = await client2.call(
10358
+ "subscriberNetworkEventsOverPeriod",
10359
+ networkEventsOverPeriodParams(subscriberId, start, end)
10360
+ );
10361
+ gy = gyCountryHistoryFromResponse(events);
10362
+ } catch (err7) {
10363
+ gyError = err7 instanceof Error ? err7.message : String(err7);
10364
+ }
10775
10365
  let syntheticRingIccid = null;
10776
10366
  const msisdnRaw = msisdnFieldFromSubscriberPayload(subscriberPayload);
10777
10367
  if (msisdnRaw) {
@@ -10789,7 +10379,7 @@ function registerCountryHistoryTool(server2, ctx) {
10789
10379
  void 0,
10790
10380
  ctx.env.OCS_EVENT_ROUTING
10791
10381
  );
10792
- let countryEvents = primary.events;
10382
+ let relayEvents = primary.events;
10793
10383
  if (syntheticRingIccid) {
10794
10384
  const secondary = await listRecentOcsEvents(
10795
10385
  syntheticRingIccid,
@@ -10798,11 +10388,23 @@ function registerCountryHistoryTool(server2, ctx) {
10798
10388
  void 0,
10799
10389
  ctx.env.OCS_EVENT_ROUTING
10800
10390
  );
10801
- countryEvents = mergeOcsEventOutputsNewestFirst(
10391
+ relayEvents = mergeOcsEventOutputsNewestFirst(
10802
10392
  [primary.events, secondary.events],
10803
10393
  effectiveLimit
10804
10394
  );
10805
10395
  }
10396
+ const countryEvents = [
10397
+ ...relayEvents.map((e) => ({
10398
+ event_id: e.event_id,
10399
+ new_country: e.data["new_country"] ?? null,
10400
+ previous_country: e.data["previous_country"] ?? null,
10401
+ mcc: e.data["mcc"] ?? null,
10402
+ mnc: e.data["mnc"] ?? null,
10403
+ timestamp: e.timestamp,
10404
+ source: e.data["source"] ?? "relay-lu"
10405
+ })),
10406
+ ...staysAsCountryEvents(gy.stays)
10407
+ ].slice(0, effectiveLimit);
10806
10408
  return {
10807
10409
  content: [
10808
10410
  {
@@ -10810,18 +10412,17 @@ function registerCountryHistoryTool(server2, ctx) {
10810
10412
  text: JSON.stringify(
10811
10413
  {
10812
10414
  subscriber_id: subscriberId,
10813
- country_events: countryEvents.map((e) => ({
10814
- event_id: e.event_id,
10815
- new_country: e.data["new_country"] ?? null,
10816
- previous_country: e.data["previous_country"] ?? null,
10817
- mcc: e.data["mcc"] ?? null,
10818
- mnc: e.data["mnc"] ?? null,
10819
- timestamp: e.timestamp,
10820
- source: e.data["source"] ?? "relay-lu"
10821
- })),
10415
+ period: { start, end },
10416
+ stays: gy.stays,
10417
+ transitions: gy.transitions,
10418
+ gy_events_considered: gy.events_considered,
10419
+ gy_events_skipped: gy.events_skipped,
10420
+ gy_teardown_artifacts_dropped: gy.teardown_artifacts_dropped,
10421
+ gy_error: gyError ?? void 0,
10422
+ country_events: countryEvents,
10822
10423
  total_country_events: countryEvents.length,
10823
10424
  total_in_buffer: primary.total_in_buffer,
10824
- note: countryEvents.length === 0 ? "No cross-border events recorded in the 24h ring-buffer for this subscriber." : void 0
10425
+ note: countryEvents.length === 0 ? `No Gy charging records with a country between ${start} and ${end}, and no relay country events in the 24h ring-buffer. Widen the period, or check the subscriber has attached at all.` : void 0
10825
10426
  },
10826
10427
  null,
10827
10428
  2