@robinmordasiewicz/f5xc-xcsh 2.0.41-2601192054 → 2.0.43-2601200312

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 (2) hide show
  1. package/dist/index.js +961 -89
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -41229,8 +41229,8 @@ var init_logo_renderer = __esm({
41229
41229
 
41230
41230
  // src/branding/index.ts
41231
41231
  function getVersion() {
41232
- if ("v2.0.41-2601192054") {
41233
- return "v2.0.41-2601192054";
41232
+ if ("v2.0.43-2601200312") {
41233
+ return "v2.0.43-2601200312";
41234
41234
  }
41235
41235
  if (process.env.XCSH_VERSION) {
41236
41236
  return process.env.XCSH_VERSION;
@@ -152862,12 +152862,21 @@ var init_ai_services = __esm({
152862
152862
  });
152863
152863
 
152864
152864
  // src/domains/subscription/client.ts
152865
+ var client_exports = {};
152866
+ __export(client_exports, {
152867
+ SubscriptionClient: () => SubscriptionClient,
152868
+ getSubscriptionClient: () => getSubscriptionClient,
152869
+ resetSubscriptionClient: () => resetSubscriptionClient
152870
+ });
152865
152871
  function getSubscriptionClient(apiClient) {
152866
152872
  if (!cachedClient2) {
152867
152873
  cachedClient2 = new SubscriptionClient(apiClient);
152868
152874
  }
152869
152875
  return cachedClient2;
152870
152876
  }
152877
+ function resetSubscriptionClient() {
152878
+ cachedClient2 = null;
152879
+ }
152871
152880
  var SubscriptionClient, cachedClient2;
152872
152881
  var init_client3 = __esm({
152873
152882
  "src/domains/subscription/client.ts"() {
@@ -162663,7 +162672,7 @@ function getConflictsForFlag2(flagName, resourceType) {
162663
162672
  }
162664
162673
  return Array.from(conflicts);
162665
162674
  }
162666
- var HEALTHCHECK_CREATION_FLAGS, ORIGIN_POOL_CREATION_FLAGS, CREATION_FLAGS_REGISTRY;
162675
+ var HEALTHCHECK_CREATION_FLAGS, ORIGIN_POOL_CREATION_FLAGS, HTTP_LOADBALANCER_CREATION_FLAGS, APP_FIREWALL_CREATION_FLAGS, CREATION_FLAGS_REGISTRY;
162667
162676
  var init_creation_flags = __esm({
162668
162677
  "src/repl/completion/creation-flags.ts"() {
162669
162678
  "use strict";
@@ -162854,27 +162863,7 @@ var init_creation_flags = __esm({
162854
162863
  priority: 1
162855
162864
  // Highest priority - always first
162856
162865
  },
162857
- // Port configuration (mutually exclusive group)
162858
- {
162859
- name: "--port",
162860
- description: "Backend port (1-65535)",
162861
- required: false,
162862
- hasValue: true,
162863
- valueType: "integer"
162864
- },
162865
- {
162866
- name: "--automatic-port",
162867
- description: "Use automatic port selection",
162868
- required: false,
162869
- hasValue: false
162870
- },
162871
- {
162872
- name: "--lb-port",
162873
- description: "Use load balancer port",
162874
- required: false,
162875
- hasValue: false
162876
- },
162877
- // Origin Server Types (ALL 10 - REPEATABLE)
162866
+ // Origin Server Types (ALL 10 - REPEATABLE) - Priority 15-20
162878
162867
  {
162879
162868
  name: "--public-ip",
162880
162869
  description: "Public IP origin server",
@@ -162882,7 +162871,8 @@ var init_creation_flags = __esm({
162882
162871
  hasValue: true,
162883
162872
  valueType: "string",
162884
162873
  isRepeatable: true,
162885
- maxOccurrences: 32
162874
+ maxOccurrences: 32,
162875
+ priority: 15
162886
162876
  },
162887
162877
  {
162888
162878
  name: "--public-name",
@@ -162891,7 +162881,8 @@ var init_creation_flags = __esm({
162891
162881
  hasValue: true,
162892
162882
  valueType: "string",
162893
162883
  isRepeatable: true,
162894
- maxOccurrences: 32
162884
+ maxOccurrences: 32,
162885
+ priority: 15
162895
162886
  },
162896
162887
  {
162897
162888
  name: "--private-ip",
@@ -162900,7 +162891,8 @@ var init_creation_flags = __esm({
162900
162891
  hasValue: true,
162901
162892
  valueType: "string",
162902
162893
  isRepeatable: true,
162903
- maxOccurrences: 32
162894
+ maxOccurrences: 32,
162895
+ priority: 16
162904
162896
  },
162905
162897
  {
162906
162898
  name: "--private-name",
@@ -162909,7 +162901,8 @@ var init_creation_flags = __esm({
162909
162901
  hasValue: true,
162910
162902
  valueType: "string",
162911
162903
  isRepeatable: true,
162912
- maxOccurrences: 32
162904
+ maxOccurrences: 32,
162905
+ priority: 16
162913
162906
  },
162914
162907
  {
162915
162908
  name: "--k8s-service",
@@ -162918,7 +162911,8 @@ var init_creation_flags = __esm({
162918
162911
  hasValue: true,
162919
162912
  valueType: "string",
162920
162913
  isRepeatable: true,
162921
- maxOccurrences: 32
162914
+ maxOccurrences: 32,
162915
+ priority: 17
162922
162916
  },
162923
162917
  {
162924
162918
  name: "--consul-service",
@@ -162927,7 +162921,18 @@ var init_creation_flags = __esm({
162927
162921
  hasValue: true,
162928
162922
  valueType: "string",
162929
162923
  isRepeatable: true,
162930
- maxOccurrences: 32
162924
+ maxOccurrences: 32,
162925
+ priority: 17
162926
+ },
162927
+ {
162928
+ name: "--cbip-service",
162929
+ description: "Cloud-based IP service",
162930
+ required: false,
162931
+ hasValue: true,
162932
+ valueType: "string",
162933
+ isRepeatable: true,
162934
+ maxOccurrences: 32,
162935
+ priority: 17
162931
162936
  },
162932
162937
  {
162933
162938
  name: "--custom-endpoint",
@@ -162936,7 +162941,8 @@ var init_creation_flags = __esm({
162936
162941
  hasValue: true,
162937
162942
  valueType: "string",
162938
162943
  isRepeatable: true,
162939
- maxOccurrences: 32
162944
+ maxOccurrences: 32,
162945
+ priority: 18
162940
162946
  },
162941
162947
  {
162942
162948
  name: "--vn-private-ip",
@@ -162945,7 +162951,8 @@ var init_creation_flags = __esm({
162945
162951
  hasValue: true,
162946
162952
  valueType: "string",
162947
162953
  isRepeatable: true,
162948
- maxOccurrences: 32
162954
+ maxOccurrences: 32,
162955
+ priority: 19
162949
162956
  },
162950
162957
  {
162951
162958
  name: "--vn-private-name",
@@ -162954,63 +162961,88 @@ var init_creation_flags = __esm({
162954
162961
  hasValue: true,
162955
162962
  valueType: "string",
162956
162963
  isRepeatable: true,
162957
- maxOccurrences: 32
162964
+ maxOccurrences: 32,
162965
+ priority: 19
162958
162966
  },
162967
+ // Site reference (for private origins) - Priority 20
162959
162968
  {
162960
- name: "--cbip-service",
162961
- description: "Cloud-based IP service",
162969
+ name: "--site",
162970
+ description: "Site reference for private origins",
162962
162971
  required: false,
162963
162972
  hasValue: true,
162964
162973
  valueType: "string",
162965
- isRepeatable: true,
162966
- maxOccurrences: 32
162974
+ priority: 20
162967
162975
  },
162968
- // Load Balancing Algorithm
162976
+ // Port configuration (mutually exclusive group) - Priority 25-26
162969
162977
  {
162970
- name: "--algorithm",
162971
- description: "Load balancing algorithm",
162978
+ name: "--port",
162979
+ description: "Backend port (1-65535)",
162972
162980
  required: false,
162973
162981
  hasValue: true,
162974
- valueType: "enum",
162975
- enumValues: [
162976
- "ROUND_ROBIN",
162977
- "LEAST_ACTIVE",
162978
- "RANDOM",
162979
- "SOURCE_IP_STICKINESS",
162980
- "COOKIE_STICKINESS",
162981
- "RING_HASH"
162982
- ]
162982
+ valueType: "integer",
162983
+ recommendedValue: 443,
162984
+ priority: 25
162983
162985
  },
162984
- // Health Checks (repeatable, max 4)
162985
162986
  {
162986
- name: "--health-check",
162987
- description: "Health check reference",
162987
+ name: "--automatic-port",
162988
+ description: "Use automatic port selection",
162988
162989
  required: false,
162989
- hasValue: true,
162990
- valueType: "string",
162991
- isRepeatable: true,
162992
- maxOccurrences: 4
162990
+ hasValue: false,
162991
+ priority: 26
162992
+ },
162993
+ {
162994
+ name: "--lb-port",
162995
+ description: "Use load balancer port",
162996
+ required: false,
162997
+ hasValue: false,
162998
+ priority: 26
162993
162999
  },
162994
- // TLS Configuration
163000
+ // TLS Configuration - Priority 32
162995
163001
  {
162996
163002
  name: "--no-tls",
162997
163003
  description: "Disable TLS for origin connections",
162998
163004
  required: false,
162999
- hasValue: false
163005
+ hasValue: false,
163006
+ priority: 32
163000
163007
  },
163001
163008
  {
163002
163009
  name: "--use-tls",
163003
163010
  description: "Enable TLS for origin connections",
163004
163011
  required: false,
163005
- hasValue: false
163012
+ hasValue: false,
163013
+ priority: 32
163006
163014
  },
163007
- // Site reference (for private origins)
163015
+ // Load Balancing Algorithm - Priority 35
163008
163016
  {
163009
- name: "--site",
163010
- description: "Site reference for private origins",
163017
+ name: "--algorithm",
163018
+ description: "Load balancing algorithm",
163019
+ required: false,
163020
+ hasValue: true,
163021
+ valueType: "enum",
163022
+ enumValues: [
163023
+ "ROUND_ROBIN",
163024
+ "LEAST_REQUEST",
163025
+ "RANDOM",
163026
+ "SOURCE_IP_STICKINESS",
163027
+ "COOKIE_STICKINESS",
163028
+ "RING_HASH",
163029
+ "LB_OVERRIDE"
163030
+ ],
163031
+ defaultValue: "ROUND_ROBIN",
163032
+ hasServerDefault: true,
163033
+ recommendedValue: "LB_OVERRIDE",
163034
+ priority: 35
163035
+ },
163036
+ // Health Checks (repeatable, max 4) - Priority 38
163037
+ {
163038
+ name: "--health-check",
163039
+ description: "Health check reference",
163011
163040
  required: false,
163012
163041
  hasValue: true,
163013
- valueType: "string"
163042
+ valueType: "string",
163043
+ isRepeatable: true,
163044
+ maxOccurrences: 4,
163045
+ priority: 38
163014
163046
  },
163015
163047
  // Connection Pool - Parent Flag (Priority 30)
163016
163048
  {
@@ -163020,6 +163052,7 @@ var init_creation_flags = __esm({
163020
163052
  hasValue: true,
163021
163053
  valueType: "enum",
163022
163054
  enumValues: ["default", "enable-reuse", "disable-reuse"],
163055
+ recommendedValue: "enable-reuse",
163023
163056
  priority: 30
163024
163057
  },
163025
163058
  // Health Check Port - Parent Flag (Priority 35)
@@ -163055,6 +163088,7 @@ var init_creation_flags = __esm({
163055
163088
  enumValues: ["DISTRIBUTED", "LOCAL_ONLY", "LOCAL_PREFERRED"],
163056
163089
  defaultValue: "DISTRIBUTED",
163057
163090
  hasServerDefault: true,
163091
+ recommendedValue: "LOCAL_PREFERRED",
163058
163092
  priority: 40
163059
163093
  },
163060
163094
  // Advanced Timeouts (Priority 45)
@@ -163283,13 +163317,534 @@ var init_creation_flags = __esm({
163283
163317
  priority: 80
163284
163318
  }
163285
163319
  ];
163320
+ HTTP_LOADBALANCER_CREATION_FLAGS = [
163321
+ // Required - Name
163322
+ {
163323
+ name: "--name",
163324
+ description: "HTTP load balancer name",
163325
+ required: true,
163326
+ hasValue: true,
163327
+ valueType: "string",
163328
+ priority: 1
163329
+ },
163330
+ // Domains (virtual hosts) - Priority 10
163331
+ {
163332
+ name: "--domain",
163333
+ description: "Domain name for virtual host (e.g., example.com)",
163334
+ required: false,
163335
+ hasValue: true,
163336
+ valueType: "string",
163337
+ isRepeatable: true,
163338
+ maxOccurrences: 64,
163339
+ priority: 10
163340
+ },
163341
+ // Port Configuration - Priority 15
163342
+ {
163343
+ name: "--http-port",
163344
+ description: "HTTP listening port (default: 80)",
163345
+ required: false,
163346
+ hasValue: true,
163347
+ valueType: "integer",
163348
+ defaultValue: 80,
163349
+ hasServerDefault: true,
163350
+ priority: 15
163351
+ },
163352
+ {
163353
+ name: "--https-port",
163354
+ description: "HTTPS listening port (default: 443)",
163355
+ required: false,
163356
+ hasValue: true,
163357
+ valueType: "integer",
163358
+ defaultValue: 443,
163359
+ hasServerDefault: true,
163360
+ recommendedValue: 443,
163361
+ priority: 15
163362
+ },
163363
+ // TLS Configuration - Priority 20
163364
+ {
163365
+ name: "--tls-certificate",
163366
+ description: "TLS certificate reference for HTTPS",
163367
+ required: false,
163368
+ hasValue: true,
163369
+ valueType: "string",
163370
+ priority: 20
163371
+ },
163372
+ {
163373
+ name: "--http-redirect",
163374
+ description: "Redirect HTTP to HTTPS automatically",
163375
+ required: false,
163376
+ hasValue: false,
163377
+ priority: 21
163378
+ },
163379
+ // Origin Pool - Priority 25
163380
+ {
163381
+ name: "--origin-pool",
163382
+ description: "Default origin pool for backend traffic",
163383
+ required: false,
163384
+ hasValue: true,
163385
+ valueType: "string",
163386
+ priority: 25
163387
+ },
163388
+ // Advertise Policy - Priority 30
163389
+ {
163390
+ name: "--advertise-policy",
163391
+ description: "Where to advertise this load balancer",
163392
+ required: false,
163393
+ hasValue: true,
163394
+ valueType: "enum",
163395
+ enumValues: ["INTERNET", "VIRTUAL_SITE", "CUSTOM"],
163396
+ recommendedValue: "INTERNET",
163397
+ priority: 30
163398
+ },
163399
+ // WAF/Security - Priority 40
163400
+ {
163401
+ name: "--app-firewall",
163402
+ description: "Application firewall (WAF) policy reference",
163403
+ required: false,
163404
+ hasValue: true,
163405
+ valueType: "string",
163406
+ priority: 40
163407
+ },
163408
+ {
163409
+ name: "--service-policy",
163410
+ description: "Service policy reference for rate limiting",
163411
+ required: false,
163412
+ hasValue: true,
163413
+ valueType: "string",
163414
+ priority: 41
163415
+ },
163416
+ // Advanced Features - Priority 50+
163417
+ {
163418
+ name: "--enable-api-discovery",
163419
+ description: "Enable automatic API endpoint discovery",
163420
+ required: false,
163421
+ hasValue: false,
163422
+ priority: 50
163423
+ },
163424
+ {
163425
+ name: "--bot-defense",
163426
+ description: "Bot defense policy reference",
163427
+ required: false,
163428
+ hasValue: true,
163429
+ valueType: "string",
163430
+ priority: 51
163431
+ },
163432
+ {
163433
+ name: "--enable-ddos",
163434
+ description: "Enable DDoS protection",
163435
+ required: false,
163436
+ hasValue: false,
163437
+ priority: 52
163438
+ }
163439
+ ];
163440
+ APP_FIREWALL_CREATION_FLAGS = [
163441
+ // Required - Name
163442
+ {
163443
+ name: "--name",
163444
+ description: "Application firewall name",
163445
+ required: true,
163446
+ hasValue: true,
163447
+ valueType: "string",
163448
+ priority: 1
163449
+ },
163450
+ // Blocking Mode - Priority 10
163451
+ {
163452
+ name: "--blocking-mode",
163453
+ description: "WAF enforcement mode",
163454
+ required: false,
163455
+ hasValue: true,
163456
+ valueType: "enum",
163457
+ enumValues: ["MONITORING", "BLOCKING"],
163458
+ defaultValue: "MONITORING",
163459
+ hasServerDefault: true,
163460
+ recommendedValue: "BLOCKING",
163461
+ priority: 10
163462
+ },
163463
+ // Detection Settings - Priority 15
163464
+ {
163465
+ name: "--detection-mode",
163466
+ description: "Attack detection sensitivity",
163467
+ required: false,
163468
+ hasValue: true,
163469
+ valueType: "enum",
163470
+ enumValues: ["LOW", "MEDIUM", "HIGH", "CUSTOM"],
163471
+ defaultValue: "MEDIUM",
163472
+ hasServerDefault: true,
163473
+ recommendedValue: "HIGH",
163474
+ priority: 15
163475
+ },
163476
+ // Attack Types - Priority 20
163477
+ {
163478
+ name: "--enable-sql-injection",
163479
+ description: "Enable SQL injection detection",
163480
+ required: false,
163481
+ hasValue: false,
163482
+ priority: 20
163483
+ },
163484
+ {
163485
+ name: "--enable-xss",
163486
+ description: "Enable cross-site scripting (XSS) detection",
163487
+ required: false,
163488
+ hasValue: false,
163489
+ priority: 20
163490
+ },
163491
+ {
163492
+ name: "--enable-command-injection",
163493
+ description: "Enable command injection detection",
163494
+ required: false,
163495
+ hasValue: false,
163496
+ priority: 20
163497
+ },
163498
+ // Violation Settings - Priority 30
163499
+ {
163500
+ name: "--allowed-response-codes",
163501
+ description: "Allowed HTTP response codes (comma-separated)",
163502
+ required: false,
163503
+ hasValue: true,
163504
+ valueType: "string",
163505
+ priority: 30
163506
+ },
163507
+ {
163508
+ name: "--max-request-size",
163509
+ description: "Maximum request size in bytes",
163510
+ required: false,
163511
+ hasValue: true,
163512
+ valueType: "integer",
163513
+ defaultValue: 10485760,
163514
+ priority: 31
163515
+ },
163516
+ // Advanced Features - Priority 40+
163517
+ {
163518
+ name: "--enable-api-protection",
163519
+ description: "Enable API-specific protection",
163520
+ required: false,
163521
+ hasValue: false,
163522
+ priority: 40
163523
+ },
163524
+ {
163525
+ name: "--enable-bot-protection",
163526
+ description: "Enable bot detection integration",
163527
+ required: false,
163528
+ hasValue: false,
163529
+ priority: 41
163530
+ },
163531
+ {
163532
+ name: "--enable-threat-campaigns",
163533
+ description: "Enable threat campaign protection",
163534
+ required: false,
163535
+ hasValue: false,
163536
+ priority: 42
163537
+ }
163538
+ ];
163286
163539
  CREATION_FLAGS_REGISTRY = /* @__PURE__ */ new Map([
163287
163540
  ["healthcheck", HEALTHCHECK_CREATION_FLAGS],
163288
- ["origin_pool", ORIGIN_POOL_CREATION_FLAGS]
163541
+ ["origin_pool", ORIGIN_POOL_CREATION_FLAGS],
163542
+ ["http_loadbalancer", HTTP_LOADBALANCER_CREATION_FLAGS],
163543
+ ["app_firewall", APP_FIREWALL_CREATION_FLAGS]
163289
163544
  ]);
163290
163545
  }
163291
163546
  });
163292
163547
 
163548
+ // src/quota/cache.ts
163549
+ function getQuotaCache() {
163550
+ if (!globalCache) {
163551
+ globalCache = new QuotaCache();
163552
+ }
163553
+ return globalCache;
163554
+ }
163555
+ function resetQuotaCache() {
163556
+ if (globalCache) {
163557
+ globalCache.invalidate();
163558
+ }
163559
+ globalCache = null;
163560
+ }
163561
+ var CACHE_TTL_MS, QuotaCache, globalCache;
163562
+ var init_cache2 = __esm({
163563
+ "src/quota/cache.ts"() {
163564
+ "use strict";
163565
+ CACHE_TTL_MS = 6e4;
163566
+ QuotaCache = class {
163567
+ cache = /* @__PURE__ */ new Map();
163568
+ /**
163569
+ * Get quota usage, using cache if available and fresh
163570
+ *
163571
+ * @param client - Subscription client for API calls
163572
+ * @param namespace - Namespace to get quota for
163573
+ * @returns Array of quota usage items
163574
+ */
163575
+ async getQuotaUsage(client, namespace) {
163576
+ const cacheKey = this.getCacheKey(namespace);
163577
+ const cached = this.cache.get(cacheKey);
163578
+ if (cached && !this.isExpired(cached.fetchedAt)) {
163579
+ return cached.usage;
163580
+ }
163581
+ const response = await client.getQuotaUsage(namespace);
163582
+ const usage = [];
163583
+ if (response.quota_usage) {
163584
+ for (const [name, item] of Object.entries(response.quota_usage)) {
163585
+ const current = item.usage?.current ?? 0;
163586
+ const limit = item.limit?.maximum ?? 0;
163587
+ const percentage = limit > 0 ? Math.round(current / limit * 100) : 0;
163588
+ usage.push({
163589
+ name,
163590
+ display_name: item.display_name || name,
163591
+ current,
163592
+ limit,
163593
+ percentage
163594
+ });
163595
+ }
163596
+ }
163597
+ this.cache.set(cacheKey, {
163598
+ usage,
163599
+ fetchedAt: Date.now(),
163600
+ namespace
163601
+ });
163602
+ return usage;
163603
+ }
163604
+ /**
163605
+ * Find quota usage for a specific quota name
163606
+ *
163607
+ * @param client - Subscription client for API calls
163608
+ * @param namespace - Namespace to get quota for
163609
+ * @param quotaName - API quota name to find
163610
+ * @returns Quota usage item or undefined if not found
163611
+ */
163612
+ async findQuotaUsage(client, namespace, quotaName) {
163613
+ const usage = await this.getQuotaUsage(client, namespace);
163614
+ return usage.find((q) => q.name === quotaName);
163615
+ }
163616
+ /**
163617
+ * Invalidate cache for a namespace or all namespaces
163618
+ *
163619
+ * @param namespace - Optional namespace to invalidate; if omitted, clears all
163620
+ */
163621
+ invalidate(namespace) {
163622
+ if (namespace) {
163623
+ this.cache.delete(this.getCacheKey(namespace));
163624
+ } else {
163625
+ this.cache.clear();
163626
+ }
163627
+ }
163628
+ /**
163629
+ * Generate cache key for a namespace
163630
+ */
163631
+ getCacheKey(namespace) {
163632
+ return `quota:${namespace}`;
163633
+ }
163634
+ /**
163635
+ * Check if cached data is expired
163636
+ */
163637
+ isExpired(fetchedAt) {
163638
+ return Date.now() - fetchedAt > CACHE_TTL_MS;
163639
+ }
163640
+ };
163641
+ globalCache = null;
163642
+ }
163643
+ });
163644
+
163645
+ // src/quota/mapping.ts
163646
+ var mapping_exports = {};
163647
+ __export(mapping_exports, {
163648
+ getAllQuotaMappings: () => getAllQuotaMappings,
163649
+ getQuotaMapping: () => getQuotaMapping,
163650
+ getQuotaMappingByName: () => getQuotaMappingByName,
163651
+ hasQuotaMapping: () => hasQuotaMapping
163652
+ });
163653
+ function getQuotaMapping(resourceType) {
163654
+ return MAPPING_BY_RESOURCE_TYPE.get(resourceType);
163655
+ }
163656
+ function getQuotaMappingByName(quotaName) {
163657
+ return MAPPING_BY_QUOTA_NAME.get(quotaName);
163658
+ }
163659
+ function getAllQuotaMappings() {
163660
+ return QUOTA_MAPPINGS;
163661
+ }
163662
+ function hasQuotaMapping(resourceType) {
163663
+ return MAPPING_BY_RESOURCE_TYPE.has(resourceType);
163664
+ }
163665
+ var QUOTA_MAPPINGS, MAPPING_BY_RESOURCE_TYPE, MAPPING_BY_QUOTA_NAME;
163666
+ var init_mapping = __esm({
163667
+ "src/quota/mapping.ts"() {
163668
+ "use strict";
163669
+ QUOTA_MAPPINGS = [
163670
+ // Load Balancing
163671
+ // API returns: "HTTP Load Balancer", "TCP Load Balancer"
163672
+ {
163673
+ resourceType: "http_loadbalancer",
163674
+ quotaName: "HTTP Load Balancer",
163675
+ displayName: "HTTP Load Balancers"
163676
+ },
163677
+ {
163678
+ resourceType: "tcp_loadbalancer",
163679
+ quotaName: "TCP Load Balancer",
163680
+ displayName: "TCP Load Balancers"
163681
+ },
163682
+ // Origin & Health
163683
+ // API returns: "origin_pool" (snake_case), "Healthcheck" (title case)
163684
+ {
163685
+ resourceType: "origin_pool",
163686
+ quotaName: "origin_pool",
163687
+ displayName: "Origin Pools"
163688
+ },
163689
+ {
163690
+ resourceType: "healthcheck",
163691
+ quotaName: "Healthcheck",
163692
+ displayName: "Health Checks"
163693
+ },
163694
+ // Sites
163695
+ // API returns: "AWS VPC Site", "Azure VNET Site", "GCP VPC Site"
163696
+ {
163697
+ resourceType: "aws_vpc_site",
163698
+ quotaName: "AWS VPC Site",
163699
+ displayName: "AWS VPC Sites"
163700
+ },
163701
+ {
163702
+ resourceType: "azure_vnet_site",
163703
+ quotaName: "Azure VNET Site",
163704
+ displayName: "Azure VNET Sites"
163705
+ },
163706
+ {
163707
+ resourceType: "gcp_vpc_site",
163708
+ quotaName: "GCP VPC Site",
163709
+ displayName: "GCP VPC Sites"
163710
+ },
163711
+ // Networking
163712
+ // API returns: "Virtual Network", "Network Connector"
163713
+ {
163714
+ resourceType: "virtual_network",
163715
+ quotaName: "Virtual Network",
163716
+ displayName: "Virtual Networks"
163717
+ },
163718
+ {
163719
+ resourceType: "network_connector",
163720
+ quotaName: "Network Connector",
163721
+ displayName: "Network Connectors"
163722
+ },
163723
+ // Security
163724
+ // API returns: "Application Firewall", "Service Policy", "Rate Limiter"
163725
+ {
163726
+ resourceType: "app_firewall",
163727
+ quotaName: "Application Firewall",
163728
+ displayName: "Application Firewalls"
163729
+ },
163730
+ {
163731
+ resourceType: "service_policy",
163732
+ quotaName: "Service Policy",
163733
+ displayName: "Service Policies"
163734
+ },
163735
+ {
163736
+ resourceType: "rate_limiter",
163737
+ quotaName: "Rate Limiter",
163738
+ displayName: "Rate Limiters"
163739
+ },
163740
+ // DNS
163741
+ // API returns: "DNS Zone", "DNS Domain"
163742
+ {
163743
+ resourceType: "dns_zone",
163744
+ quotaName: "DNS Zone",
163745
+ displayName: "DNS Zones"
163746
+ },
163747
+ {
163748
+ resourceType: "dns_domain",
163749
+ quotaName: "DNS Domain",
163750
+ displayName: "DNS Domains"
163751
+ },
163752
+ // API Security
163753
+ // API returns: "API Definition"
163754
+ {
163755
+ resourceType: "api_definition",
163756
+ quotaName: "API Definition",
163757
+ displayName: "API Definitions"
163758
+ },
163759
+ // Namespaces
163760
+ // API returns: "Namespace"
163761
+ {
163762
+ resourceType: "namespace",
163763
+ quotaName: "Namespace",
163764
+ displayName: "Namespaces"
163765
+ }
163766
+ ];
163767
+ MAPPING_BY_RESOURCE_TYPE = new Map(
163768
+ QUOTA_MAPPINGS.map((m) => [m.resourceType, m])
163769
+ );
163770
+ MAPPING_BY_QUOTA_NAME = new Map(
163771
+ QUOTA_MAPPINGS.map((m) => [m.quotaName, m])
163772
+ );
163773
+ }
163774
+ });
163775
+
163776
+ // src/repl/completion/quota-helper.ts
163777
+ var quota_helper_exports = {};
163778
+ __export(quota_helper_exports, {
163779
+ getQuotaForResourceType: () => getQuotaForResourceType,
163780
+ getQuotasForResourceTypes: () => getQuotasForResourceTypes
163781
+ });
163782
+ async function getQuotaForResourceType(apiClient, namespace, resourceType) {
163783
+ const mapping = getQuotaMapping(resourceType);
163784
+ if (!mapping) {
163785
+ return null;
163786
+ }
163787
+ try {
163788
+ const subscriptionClient = new SubscriptionClient(apiClient);
163789
+ const cache3 = getQuotaCache();
163790
+ const usage = await cache3.findQuotaUsage(
163791
+ subscriptionClient,
163792
+ namespace,
163793
+ mapping.quotaName
163794
+ );
163795
+ if (!usage) {
163796
+ return null;
163797
+ }
163798
+ if (usage.limit < 0) {
163799
+ return {
163800
+ current: usage.current,
163801
+ limit: usage.limit,
163802
+ percentage: 0,
163803
+ level: "none",
163804
+ display: `${usage.current} (unlimited)`
163805
+ };
163806
+ }
163807
+ if (usage.limit === 0) {
163808
+ return null;
163809
+ }
163810
+ const percentage = Math.round(usage.current / usage.limit * 100);
163811
+ const level = percentage >= 100 ? "error" : percentage >= 90 ? "warning" : "none";
163812
+ return {
163813
+ current: usage.current,
163814
+ limit: usage.limit,
163815
+ percentage,
163816
+ level,
163817
+ display: `${usage.current}/${usage.limit}`
163818
+ };
163819
+ } catch {
163820
+ return null;
163821
+ }
163822
+ }
163823
+ async function getQuotasForResourceTypes(apiClient, namespace, resourceTypes) {
163824
+ const results = /* @__PURE__ */ new Map();
163825
+ await Promise.all(
163826
+ resourceTypes.map(async (rt) => {
163827
+ const info = await getQuotaForResourceType(
163828
+ apiClient,
163829
+ namespace,
163830
+ rt
163831
+ );
163832
+ if (info) {
163833
+ results.set(rt, info);
163834
+ }
163835
+ })
163836
+ );
163837
+ return results;
163838
+ }
163839
+ var init_quota_helper = __esm({
163840
+ "src/repl/completion/quota-helper.ts"() {
163841
+ "use strict";
163842
+ init_cache2();
163843
+ init_mapping();
163844
+ init_client3();
163845
+ }
163846
+ });
163847
+
163293
163848
  // src/repl/completion/completer.ts
163294
163849
  function isResourceCompletionAppropriate(resource) {
163295
163850
  if (resource.isPrimary) {
@@ -163554,8 +164109,10 @@ var init_completer = __esm({
163554
164109
  }
163555
164110
  return suggestions2;
163556
164111
  }
163557
- const resourceTypes = this.getResourceTypeSuggestions(
163558
- resourceCtx.domain
164112
+ const resourceTypes = await this.getResourceTypeSuggestionsWithQuota(
164113
+ resourceCtx.domain,
164114
+ this.session?.getNamespace() ?? null,
164115
+ this.session?.getAPIClient() ?? null
163559
164116
  );
163560
164117
  if (resourceTypes.length > 0) {
163561
164118
  let suggestions2 = resourceTypes;
@@ -163624,6 +164181,50 @@ var init_completer = __esm({
163624
164181
  }
163625
164182
  return suggestions;
163626
164183
  }
164184
+ /**
164185
+ * Get suggestions with metadata (including resource quota info)
164186
+ * Use this when you need quota info for the status line
164187
+ */
164188
+ async completeWithMeta(text) {
164189
+ const trimmed = text.trimStart();
164190
+ const parsed = parseInput(trimmed);
164191
+ const resourceCtx = this.parseResourceContext(parsed);
164192
+ const suggestions = await this.complete(text);
164193
+ let resourceQuotaInfo;
164194
+ if (resourceCtx.resourceType && resourceCtx.action && CREATION_ACTIONS.has(resourceCtx.action) && hasCreationFlags(resourceCtx.resourceType) && this.session) {
164195
+ try {
164196
+ const { getQuotaForResourceType: getQuotaForResourceType2 } = await Promise.resolve().then(() => (init_quota_helper(), quota_helper_exports));
164197
+ const { getQuotaMapping: getQuotaMapping2 } = await Promise.resolve().then(() => (init_mapping(), mapping_exports));
164198
+ const namespace = this.session.getNamespace();
164199
+ const client = this.session.getAPIClient();
164200
+ const mapping = getQuotaMapping2(resourceCtx.resourceType);
164201
+ if (namespace && client && mapping) {
164202
+ const quotaInfo = await getQuotaForResourceType2(
164203
+ client,
164204
+ namespace,
164205
+ resourceCtx.resourceType
164206
+ );
164207
+ if (quotaInfo) {
164208
+ resourceQuotaInfo = {
164209
+ resourceType: resourceCtx.resourceType,
164210
+ displayName: mapping.displayName,
164211
+ current: quotaInfo.current,
164212
+ limit: quotaInfo.limit,
164213
+ level: quotaInfo.level
164214
+ };
164215
+ }
164216
+ }
164217
+ } catch {
164218
+ }
164219
+ }
164220
+ const result = {
164221
+ suggestions
164222
+ };
164223
+ if (resourceQuotaInfo) {
164224
+ result.resourceQuotaInfo = resourceQuotaInfo;
164225
+ }
164226
+ return result;
164227
+ }
163627
164228
  /**
163628
164229
  * Get completions for custom domain commands
163629
164230
  * Uses unified completion registry for structure navigation,
@@ -163929,6 +164530,47 @@ var init_completer = __esm({
163929
164530
  };
163930
164531
  });
163931
164532
  }
164533
+ /**
164534
+ * Get resource type suggestions with quota information
164535
+ *
164536
+ * Enhanced version of getResourceTypeSuggestions that includes quota usage
164537
+ * data for resources that have quota mappings. Quota info is displayed
164538
+ * right-justified with color coding:
164539
+ * - White: Normal usage (< 90%)
164540
+ * - Yellow: Warning (90-99%)
164541
+ * - Red: At quota limit (100%)
164542
+ *
164543
+ * @param domain - The domain to get resource types for
164544
+ * @param namespace - The namespace to get quota for
164545
+ * @param client - The API client for quota lookups
164546
+ * @returns Promise of completion suggestions with quota info
164547
+ */
164548
+ async getResourceTypeSuggestionsWithQuota(domain, namespace, client) {
164549
+ const baseSuggestions = this.getResourceTypeSuggestions(domain);
164550
+ if (!client || !namespace) {
164551
+ return baseSuggestions;
164552
+ }
164553
+ try {
164554
+ const { getQuotasForResourceTypes: getQuotasForResourceTypes2 } = await Promise.resolve().then(() => (init_quota_helper(), quota_helper_exports));
164555
+ const resourceTypes = baseSuggestions.map((s) => s.text);
164556
+ const quotas = await getQuotasForResourceTypes2(
164557
+ client,
164558
+ namespace,
164559
+ resourceTypes
164560
+ );
164561
+ return baseSuggestions.map((suggestion) => {
164562
+ const quota = quotas.get(suggestion.text);
164563
+ if (!quota) return suggestion;
164564
+ return {
164565
+ ...suggestion,
164566
+ quotaLevel: quota.level,
164567
+ quotaInfo: quota.display
164568
+ };
164569
+ });
164570
+ } catch {
164571
+ return baseSuggestions;
164572
+ }
164573
+ }
163932
164574
  /**
163933
164575
  * Get resource name suggestions from live API
163934
164576
  * Fetches actual resource names for a given resource type
@@ -164496,8 +165138,8 @@ var init_completer = __esm({
164496
165138
  category: "value"
164497
165139
  },
164498
165140
  {
164499
- text: "LEAST_ACTIVE",
164500
- description: "Least active connections",
165141
+ text: "LEAST_REQUEST",
165142
+ description: "Least request algorithm",
164501
165143
  category: "value"
164502
165144
  },
164503
165145
  {
@@ -165202,6 +165844,131 @@ var init_verb_handler = __esm({
165202
165844
  }
165203
165845
  });
165204
165846
 
165847
+ // src/quota/pre-check.ts
165848
+ async function checkQuotaBeforeCreate(client, options) {
165849
+ const { resourceType, namespace, force = false } = options;
165850
+ const mapping = getQuotaMapping(resourceType);
165851
+ if (!mapping) {
165852
+ return { proceed: true, level: "none" };
165853
+ }
165854
+ try {
165855
+ const cache3 = getQuotaCache();
165856
+ const quotaUsage = await cache3.findQuotaUsage(
165857
+ client,
165858
+ namespace,
165859
+ mapping.quotaName
165860
+ );
165861
+ if (!quotaUsage) {
165862
+ return { proceed: true, level: "none" };
165863
+ }
165864
+ const percentage = quotaUsage.percentage ?? (quotaUsage.limit > 0 ? Math.round(quotaUsage.current / quotaUsage.limit * 100) : 0);
165865
+ const quotaInfo = {
165866
+ name: quotaUsage.name,
165867
+ displayName: mapping.displayName,
165868
+ current: quotaUsage.current,
165869
+ limit: quotaUsage.limit,
165870
+ percentage
165871
+ };
165872
+ if (percentage >= ERROR_THRESHOLD) {
165873
+ return {
165874
+ proceed: force,
165875
+ level: "error",
165876
+ message: force ? `Quota limit reached for ${mapping.displayName}, proceeding due to --force` : `Quota limit reached for ${mapping.displayName}`,
165877
+ quota: quotaInfo
165878
+ };
165879
+ }
165880
+ if (percentage >= WARNING_THRESHOLD) {
165881
+ return {
165882
+ proceed: true,
165883
+ level: "warning",
165884
+ message: `Approaching quota limit for ${mapping.displayName}`,
165885
+ quota: quotaInfo
165886
+ };
165887
+ }
165888
+ return { proceed: true, level: "none" };
165889
+ } catch (error) {
165890
+ const message = error instanceof Error ? error.message : "Unknown error";
165891
+ return {
165892
+ proceed: true,
165893
+ level: "none",
165894
+ message: `Could not check quota: ${message}`
165895
+ };
165896
+ }
165897
+ }
165898
+ function formatQuotaWarning(result) {
165899
+ if (result.level === "none" || !result.quota) {
165900
+ return [];
165901
+ }
165902
+ const { quota, level } = result;
165903
+ const lines = [];
165904
+ const icon = level === "error" ? "\u274C" : "\u26A0\uFE0F";
165905
+ const title = level === "error" ? "Quota Exceeded" : "Quota Warning";
165906
+ lines.push(`${icon} ${title}: ${quota.displayName}`);
165907
+ lines.push(
165908
+ ` Usage: ${quota.current}/${quota.limit} (${quota.percentage}%)`
165909
+ );
165910
+ const barWidth = 20;
165911
+ const filledWidth = Math.round(quota.percentage / 100 * barWidth);
165912
+ const emptyWidth = barWidth - filledWidth;
165913
+ const filledChar = "\u2588";
165914
+ const emptyChar = "\u2591";
165915
+ const progressBar2 = filledChar.repeat(filledWidth) + emptyChar.repeat(emptyWidth);
165916
+ lines.push(` ${progressBar2}`);
165917
+ lines.push("");
165918
+ if (level === "error") {
165919
+ lines.push(" Cannot create - quota limit reached.");
165920
+ lines.push(
165921
+ " Use --force to attempt anyway, or delete existing resources."
165922
+ );
165923
+ } else {
165924
+ lines.push(
165925
+ " Creating this resource will approach your quota limit."
165926
+ );
165927
+ }
165928
+ return lines;
165929
+ }
165930
+ function formatQuotaStatusLine(result) {
165931
+ if (result.level === "none" || !result.quota) {
165932
+ return "";
165933
+ }
165934
+ const { quota, level } = result;
165935
+ const icon = level === "error" ? "\u274C" : "\u26A0\uFE0F";
165936
+ return `${icon} ${quota.displayName}: ${quota.current}/${quota.limit} (${quota.percentage}%)`;
165937
+ }
165938
+ var WARNING_THRESHOLD, ERROR_THRESHOLD;
165939
+ var init_pre_check = __esm({
165940
+ "src/quota/pre-check.ts"() {
165941
+ "use strict";
165942
+ init_mapping();
165943
+ init_cache2();
165944
+ WARNING_THRESHOLD = 90;
165945
+ ERROR_THRESHOLD = 100;
165946
+ }
165947
+ });
165948
+
165949
+ // src/quota/index.ts
165950
+ var quota_exports = {};
165951
+ __export(quota_exports, {
165952
+ QuotaCache: () => QuotaCache,
165953
+ checkQuotaBeforeCreate: () => checkQuotaBeforeCreate,
165954
+ formatQuotaStatusLine: () => formatQuotaStatusLine,
165955
+ formatQuotaWarning: () => formatQuotaWarning,
165956
+ getAllQuotaMappings: () => getAllQuotaMappings,
165957
+ getQuotaCache: () => getQuotaCache,
165958
+ getQuotaMapping: () => getQuotaMapping,
165959
+ getQuotaMappingByName: () => getQuotaMappingByName,
165960
+ hasQuotaMapping: () => hasQuotaMapping,
165961
+ resetQuotaCache: () => resetQuotaCache
165962
+ });
165963
+ var init_quota = __esm({
165964
+ "src/quota/index.ts"() {
165965
+ "use strict";
165966
+ init_pre_check();
165967
+ init_mapping();
165968
+ init_cache2();
165969
+ }
165970
+ });
165971
+
165205
165972
  // src/profiling/profiler.ts
165206
165973
  var DEFAULT_THRESHOLDS = {
165207
165974
  slowPhaseMs: 100,
@@ -173273,6 +174040,16 @@ function getCategoryColor(category) {
173273
174040
  return "#ffffff";
173274
174041
  }
173275
174042
  }
174043
+ function getQuotaColor(quotaLevel) {
174044
+ if (quotaLevel === "error") return "#CA260A";
174045
+ if (quotaLevel === "warning") return "#ffc107";
174046
+ return null;
174047
+ }
174048
+ function getQuotaIndicator(quotaLevel) {
174049
+ if (quotaLevel === "error") return " \u274C";
174050
+ if (quotaLevel === "warning") return " \u26A0\uFE0F";
174051
+ return "";
174052
+ }
173276
174053
  function SuggestionItem({
173277
174054
  suggestion,
173278
174055
  isSelected,
@@ -173280,20 +174057,45 @@ function SuggestionItem({
173280
174057
  isContextOnly
173281
174058
  }) {
173282
174059
  const categoryColor = getCategoryColor(suggestion.category);
173283
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { children: [
173284
- isContextOnly ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: " " }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: isSelected ? "#CA260A" : "#333333", children: isSelected ? "\u25B6 " : " " }),
173285
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: categoryColor, bold: isSelected, inverse: isSelected, children: suggestion.label.padEnd(maxLabelWidth) }),
173286
- suggestion.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
174060
+ const quotaColor = getQuotaColor(suggestion.quotaLevel);
174061
+ const quotaIndicator = getQuotaIndicator(suggestion.quotaLevel);
174062
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { justifyContent: "space-between", width: "100%", children: [
174063
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { children: [
174064
+ isContextOnly ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: " " }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: isSelected ? "#CA260A" : "#333333", children: isSelected ? "\u25B6 " : " " }),
174065
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
174066
+ Text,
174067
+ {
174068
+ color: categoryColor,
174069
+ bold: isSelected,
174070
+ inverse: isSelected,
174071
+ children: suggestion.label.padEnd(maxLabelWidth)
174072
+ }
174073
+ ),
174074
+ suggestion.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
174075
+ Text,
174076
+ {
174077
+ color: suggestion.isPrimary ? "#ffffff" : "#666666",
174078
+ bold: suggestion.isPrimary || false,
174079
+ children: [
174080
+ " - ",
174081
+ suggestion.description
174082
+ ]
174083
+ }
174084
+ )
174085
+ ] }),
174086
+ suggestion.quotaInfo && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
173287
174087
  Text,
173288
174088
  {
173289
- color: suggestion.isPrimary ? "#ffffff" : "#666666",
173290
- bold: suggestion.isPrimary || false,
174089
+ color: quotaColor ?? "#666666",
174090
+ bold: suggestion.quotaLevel === "error",
173291
174091
  children: [
173292
- " - ",
173293
- suggestion.description
174092
+ "(",
174093
+ suggestion.quotaInfo,
174094
+ quotaIndicator,
174095
+ ")"
173294
174096
  ]
173295
174097
  }
173296
- )
174098
+ ) })
173297
174099
  ] });
173298
174100
  }
173299
174101
  function Suggestions({
@@ -173303,7 +174105,8 @@ function Suggestions({
173303
174105
  onNavigate,
173304
174106
  onCancel,
173305
174107
  maxVisible = 20,
173306
- isActive = true
174108
+ isActive = true,
174109
+ resourceQuotaInfo
173307
174110
  }) {
173308
174111
  const isContextOnlyMode = suggestions.every(
173309
174112
  (s) => s.category === "context"
@@ -173387,7 +174190,25 @@ function Suggestions({
173387
174190
  totalCount - startIndex - maxVisible,
173388
174191
  " more below)"
173389
174192
  ] }),
173390
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: "#666666", dimColor: true, children: isContextOnlyMode ? "\u2191\u2193: scroll | Esc: close" : "Tab/\u2192: select | Enter: execute | \u2191\u2193: navigate | Esc: cancel" }) })
174193
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { marginTop: 1, justifyContent: "space-between", width: "100%", children: [
174194
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: "#666666", dimColor: true, children: isContextOnlyMode ? "\u2191\u2193: scroll | Esc: close" : "Tab/\u2192: select | Enter: execute | \u2191\u2193: navigate | Esc: cancel" }),
174195
+ resourceQuotaInfo && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
174196
+ Text,
174197
+ {
174198
+ color: getQuotaColor(resourceQuotaInfo.level) ?? "#666666",
174199
+ bold: resourceQuotaInfo.level === "error",
174200
+ children: [
174201
+ resourceQuotaInfo.displayName,
174202
+ ":",
174203
+ " ",
174204
+ resourceQuotaInfo.current,
174205
+ "/",
174206
+ resourceQuotaInfo.limit,
174207
+ getQuotaIndicator(resourceQuotaInfo.level)
174208
+ ]
174209
+ }
174210
+ )
174211
+ ] })
173391
174212
  ]
173392
174213
  }
173393
174214
  );
@@ -174183,6 +175004,7 @@ function useCompletion(options) {
174183
175004
  const [suggestions, setSuggestions] = (0, import_react32.useState)([]);
174184
175005
  const [selectedIndex, setSelectedIndex] = (0, import_react32.useState)(0);
174185
175006
  const [isShowing, setIsShowing] = (0, import_react32.useState)(false);
175007
+ const [resourceQuotaInfo, setResourceQuotaInfo] = (0, import_react32.useState)(null);
174186
175008
  (0, import_react32.useEffect)(() => {
174187
175009
  if (session) {
174188
175010
  completer.setSession(session);
@@ -174192,10 +175014,13 @@ function useCompletion(options) {
174192
175014
  setIsShowing(false);
174193
175015
  setSuggestions([]);
174194
175016
  setSelectedIndex(0);
175017
+ setResourceQuotaInfo(null);
174195
175018
  }, []);
174196
175019
  const triggerCompletion = (0, import_react32.useCallback)(
174197
175020
  async (input) => {
174198
- const newSuggestions = await completer.complete(input);
175021
+ const result = await completer.completeWithMeta(input);
175022
+ const newSuggestions = result.suggestions;
175023
+ setResourceQuotaInfo(result.resourceQuotaInfo ?? null);
174199
175024
  if (newSuggestions.length === 1) {
174200
175025
  const singleSuggestion = newSuggestions[0];
174201
175026
  if (singleSuggestion?.category === "context") {
@@ -174221,7 +175046,9 @@ function useCompletion(options) {
174221
175046
  const filterSuggestions = (0, import_react32.useCallback)(
174222
175047
  async (input) => {
174223
175048
  if (!isShowing) return;
174224
- const newSuggestions = await completer.complete(input);
175049
+ const result = await completer.completeWithMeta(input);
175050
+ const newSuggestions = result.suggestions;
175051
+ setResourceQuotaInfo(result.resourceQuotaInfo ?? null);
174225
175052
  if (newSuggestions.length === 0) {
174226
175053
  hide();
174227
175054
  } else {
@@ -174256,6 +175083,7 @@ function useCompletion(options) {
174256
175083
  suggestions,
174257
175084
  selectedIndex,
174258
175085
  isShowing,
175086
+ resourceQuotaInfo,
174259
175087
  triggerCompletion,
174260
175088
  navigateUp,
174261
175089
  navigateDown,
@@ -177078,6 +177906,35 @@ async function executeAPICommand(session, ctx, cmd) {
177078
177906
  contextChanged: false
177079
177907
  };
177080
177908
  }
177909
+ if (action === "create" && effectiveResourceType) {
177910
+ const { SubscriptionClient: SubscriptionClient2 } = await Promise.resolve().then(() => (init_client3(), client_exports));
177911
+ const { checkQuotaBeforeCreate: checkQuotaBeforeCreate2, formatQuotaWarning: formatQuotaWarning2 } = await Promise.resolve().then(() => (init_quota(), quota_exports));
177912
+ const subscriptionClient = new SubscriptionClient2(client);
177913
+ const forceFlag = args.some(
177914
+ (a) => a === "--force" || a === "-f"
177915
+ );
177916
+ const quotaResult = await checkQuotaBeforeCreate2(
177917
+ subscriptionClient,
177918
+ {
177919
+ resourceType: effectiveResourceType,
177920
+ namespace: effectiveNamespace,
177921
+ force: forceFlag
177922
+ }
177923
+ );
177924
+ if (quotaResult.level !== "none") {
177925
+ const quotaWarningLines = formatQuotaWarning2(quotaResult);
177926
+ if (!quotaResult.proceed) {
177927
+ return {
177928
+ output: quotaWarningLines,
177929
+ shouldExit: false,
177930
+ shouldClear: false,
177931
+ contextChanged: false,
177932
+ error: "Quota exceeded"
177933
+ };
177934
+ }
177935
+ warningOutput.push(...quotaWarningLines, "");
177936
+ }
177937
+ }
177081
177938
  if (action === "create") {
177082
177939
  const response = await client.post(apiPath, requestBody);
177083
177940
  result = response.data ?? {
@@ -177429,13 +178286,25 @@ function isValidDomain2(word) {
177429
178286
  return false;
177430
178287
  }
177431
178288
  function toUISuggestions(suggestions) {
177432
- return suggestions.map((s) => ({
177433
- label: s.text,
177434
- value: s.text,
177435
- description: s.description,
177436
- category: s.category ?? "builtin"
177437
- // Provide default to avoid undefined
177438
- }));
178289
+ return suggestions.map((s) => {
178290
+ const suggestion = {
178291
+ label: s.text,
178292
+ value: s.text,
178293
+ description: s.description,
178294
+ category: s.category ?? "builtin"
178295
+ // Provide default to avoid undefined
178296
+ };
178297
+ if (s.isPrimary !== void 0) {
178298
+ suggestion.isPrimary = s.isPrimary;
178299
+ }
178300
+ if (s.quotaLevel !== void 0) {
178301
+ suggestion.quotaLevel = s.quotaLevel;
178302
+ }
178303
+ if (s.quotaInfo !== void 0) {
178304
+ suggestion.quotaInfo = s.quotaInfo;
178305
+ }
178306
+ return suggestion;
178307
+ });
177439
178308
  }
177440
178309
  function App2({ initialSession } = {}) {
177441
178310
  const { exit } = use_app_default();
@@ -177910,7 +178779,10 @@ function App2({ initialSession } = {}) {
177910
178779
  onNavigate: handleSuggestionNavigate,
177911
178780
  onCancel: completion.hide,
177912
178781
  maxVisible: 20,
177913
- isActive: false
178782
+ isActive: false,
178783
+ ...completion.resourceQuotaInfo ? {
178784
+ resourceQuotaInfo: completion.resourceQuotaInfo
178785
+ } : {}
177914
178786
  }
177915
178787
  ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
177916
178788
  StatusBar,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robinmordasiewicz/f5xc-xcsh",
3
- "version": "2.0.41-2601192054",
3
+ "version": "2.0.43-2601200312",
4
4
  "description": "F5 Distributed Cloud Shell - Interactive CLI for F5 XC",
5
5
  "type": "module",
6
6
  "bin": {