@jeffusion/bungee-core 4.2.0 → 4.3.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.
Files changed (3) hide show
  1. package/dist/master.js +120 -76
  2. package/dist/worker.js +1267 -491
  3. package/package.json +2 -2
package/dist/master.js CHANGED
@@ -16341,7 +16341,43 @@ function uniqueServiceName(preferredName, existingNames) {
16341
16341
  }
16342
16342
  function moveRouteConfigToService(route, service, routeIndex, changes) {
16343
16343
  if (route.failover && !service.failover) {
16344
- service.failover = route.failover;
16344
+ const failover = route.failover;
16345
+ if (isPlainRecord(failover.health_check) && !service.health_check) {
16346
+ service.health_check = failover.health_check;
16347
+ changes.push({
16348
+ type: "move",
16349
+ path: `routes.${routeIndex}.failover.health_check`,
16350
+ from: `routes.${routeIndex}.failover.health_check`,
16351
+ to: `services.${service.name}.health_check`,
16352
+ message: `Extracted health_check from failover to service "${service.name}" top-level`
16353
+ });
16354
+ delete failover.health_check;
16355
+ }
16356
+ if (failover.passive_health?.auto_enable_on_active_health_check !== undefined) {
16357
+ if (service.health_check) {
16358
+ service.health_check.auto_enable_on_active_health_check = failover.passive_health.auto_enable_on_active_health_check;
16359
+ changes.push({
16360
+ type: "move",
16361
+ path: `routes.${routeIndex}.failover.passive_health.auto_enable_on_active_health_check`,
16362
+ from: "failover.passive_health.auto_enable_on_active_health_check",
16363
+ to: `services.${service.name}.health_check.auto_enable_on_active_health_check`,
16364
+ message: `Moved auto_enable_on_active_health_check from passive_health to health_check`
16365
+ });
16366
+ }
16367
+ delete failover.passive_health.auto_enable_on_active_health_check;
16368
+ }
16369
+ if (failover.recovery?.probe_interval_ms !== undefined) {
16370
+ failover.recovery.backoff_base_ms = failover.recovery.probe_interval_ms;
16371
+ delete failover.recovery.probe_interval_ms;
16372
+ changes.push({
16373
+ type: "rename",
16374
+ path: `routes.${routeIndex}.failover.recovery.probe_interval_ms`,
16375
+ from: "probe_interval_ms",
16376
+ to: "backoff_base_ms",
16377
+ message: `Renamed probe_interval_ms to backoff_base_ms (semantics: exponential backoff base)`
16378
+ });
16379
+ }
16380
+ service.failover = failover;
16345
16381
  changes.push({
16346
16382
  type: "move",
16347
16383
  path: `routes.${routeIndex}.failover`,
@@ -16350,14 +16386,18 @@ function moveRouteConfigToService(route, service, routeIndex, changes) {
16350
16386
  message: `Moved route failover to service "${service.name}"`
16351
16387
  });
16352
16388
  }
16353
- if (route.sticky_session && !service.sticky_session) {
16354
- service.sticky_session = route.sticky_session;
16389
+ if (route.sticky_session && !service.load_balancing) {
16390
+ const key_expression = route.sticky_session.key_expression;
16391
+ service.load_balancing = {
16392
+ policy: "consistent_hash",
16393
+ ...key_expression ? { hash_policy: { expression: key_expression } } : {}
16394
+ };
16355
16395
  changes.push({
16356
16396
  type: "move",
16357
16397
  path: `routes.${routeIndex}.sticky_session`,
16358
16398
  from: `routes.${routeIndex}.sticky_session`,
16359
- to: `services.${service.name}.sticky_session`,
16360
- message: `Moved route sticky_session to service "${service.name}"`
16399
+ to: `services.${service.name}.load_balancing`,
16400
+ message: `Migrated route sticky_session to service "${service.name}" as load_balancing.policy=consistent_hash`
16361
16401
  });
16362
16402
  }
16363
16403
  if (route.failover) {
@@ -16372,7 +16412,7 @@ var init_v3_to_v4 = __esm(() => {
16372
16412
  v3ToV4Migration = {
16373
16413
  fromVersion: 3,
16374
16414
  toVersion: 4,
16375
- description: "Move failover and sticky_session from routes to services",
16415
+ description: "Move failover and migrate sticky_session to load_balancing.consistent_hash on services",
16376
16416
  migrate(input) {
16377
16417
  const config = cloneJson(input);
16378
16418
  if (!isPlainRecord(config)) {
@@ -16415,11 +16455,26 @@ var init_v3_to_v4 = __esm(() => {
16415
16455
  }
16416
16456
  const serviceName = uniqueServiceName(serviceNameFromPath(route.path), serviceNames);
16417
16457
  const routeEndpoints = route.endpoints ?? [];
16458
+ const failover = route.failover;
16459
+ const extractedHealthCheck = isPlainRecord(failover?.health_check) ? failover.health_check : undefined;
16460
+ if (extractedHealthCheck) {
16461
+ delete failover.health_check;
16462
+ }
16463
+ if (failover?.recovery?.probe_interval_ms !== undefined) {
16464
+ failover.recovery.backoff_base_ms = failover.recovery.probe_interval_ms;
16465
+ delete failover.recovery.probe_interval_ms;
16466
+ }
16418
16467
  const service = {
16419
16468
  name: serviceName,
16420
16469
  endpoints: routeEndpoints,
16421
- ...route.failover && { failover: route.failover },
16422
- ...route.sticky_session && { sticky_session: route.sticky_session }
16470
+ ...failover && { failover },
16471
+ ...extractedHealthCheck && { health_check: extractedHealthCheck },
16472
+ ...route.sticky_session && {
16473
+ load_balancing: {
16474
+ policy: "consistent_hash",
16475
+ ...route.sticky_session.key_expression ? { hash_policy: { expression: route.sticky_session.key_expression } } : {}
16476
+ }
16477
+ }
16423
16478
  };
16424
16479
  services.push(service);
16425
16480
  route.service = serviceName;
@@ -16429,7 +16484,7 @@ var init_v3_to_v4 = __esm(() => {
16429
16484
  path: `routes.${routeIndex}`,
16430
16485
  from: `routes.${routeIndex}.endpoints/failover/sticky_session`,
16431
16486
  to: `services.${serviceName}`,
16432
- message: `Created service "${serviceName}" from route "${route.path}"`
16487
+ message: `Created service "${serviceName}" from route "${route.path}" (sticky_session migrated to load_balancing${extractedHealthCheck ? ", health_check extracted" : ""})`
16433
16488
  });
16434
16489
  moveRouteConfigToService(route, service, routeIndex, changes);
16435
16490
  }
@@ -19355,33 +19410,6 @@ var init_sortBy = __esm(() => {
19355
19410
  sortBy_default = sortBy;
19356
19411
  });
19357
19412
 
19358
- // ../../node_modules/lodash-es/_baseSum.js
19359
- function baseSum(array, iteratee) {
19360
- var result, index = -1, length = array.length;
19361
- while (++index < length) {
19362
- var current = iteratee(array[index]);
19363
- if (current !== undefined) {
19364
- result = result === undefined ? current : result + current;
19365
- }
19366
- }
19367
- return result;
19368
- }
19369
- var _baseSum_default;
19370
- var init__baseSum = __esm(() => {
19371
- _baseSum_default = baseSum;
19372
- });
19373
-
19374
- // ../../node_modules/lodash-es/sumBy.js
19375
- function sumBy(array, iteratee) {
19376
- return array && array.length ? _baseSum_default(array, _baseIteratee_default(iteratee, 2)) : 0;
19377
- }
19378
- var sumBy_default;
19379
- var init_sumBy = __esm(() => {
19380
- init__baseIteratee();
19381
- init__baseSum();
19382
- sumBy_default = sumBy;
19383
- });
19384
-
19385
19413
  // ../../node_modules/lodash-es/lodash.js
19386
19414
  var init_lodash = __esm(() => {
19387
19415
  init_find();
@@ -19392,7 +19420,6 @@ var init_lodash = __esm(() => {
19392
19420
  init_map();
19393
19421
  init_mergeWith();
19394
19422
  init_sortBy();
19395
- init_sumBy();
19396
19423
  });
19397
19424
 
19398
19425
  // src/expression-engine.ts
@@ -19794,21 +19821,29 @@ function normalizeRouteConfig(route, services) {
19794
19821
  }
19795
19822
  return route;
19796
19823
  }
19797
- function validateStickySession(service) {
19798
- if (service.sticky_session === undefined) {
19824
+ function validateLoadBalancing(service) {
19825
+ const lb = service.load_balancing;
19826
+ if (!lb)
19799
19827
  return;
19800
- }
19801
- if (typeof service.sticky_session !== "object" || service.sticky_session === null || Array.isArray(service.sticky_session)) {
19802
- logger.error(`Invalid sticky_session config in service "${service.name}". sticky_session must be an object.`);
19803
- process.exit(1);
19804
- }
19805
- if (service.sticky_session.enabled !== undefined && typeof service.sticky_session.enabled !== "boolean") {
19806
- logger.error(`Invalid sticky_session.enabled in service "${service.name}". sticky_session.enabled must be a boolean.`);
19828
+ const validPolicies = ["weighted_random", "round_robin", "least_requests", "consistent_hash"];
19829
+ if (!validPolicies.includes(lb.policy)) {
19830
+ logger.error(`Invalid load_balancing.policy "${lb.policy}" in service "${service.name}". Must be one of: ${validPolicies.join(", ")}`);
19807
19831
  process.exit(1);
19808
19832
  }
19809
- if (service.sticky_session.key_expression !== undefined && typeof service.sticky_session.key_expression !== "string") {
19810
- logger.error(`Invalid sticky_session.key_expression in service "${service.name}". sticky_session.key_expression must be a string.`);
19811
- process.exit(1);
19833
+ if (lb.policy === "consistent_hash") {
19834
+ const hp = lb.hash_policy;
19835
+ if (!hp || !hp.header && !hp.expression) {
19836
+ logger.error(`Service "${service.name}" with policy=consistent_hash requires hash_policy with at least one of header or expression.`);
19837
+ process.exit(1);
19838
+ }
19839
+ if (hp.header !== undefined && typeof hp.header !== "string") {
19840
+ logger.error(`Invalid load_balancing.hash_policy.header in service "${service.name}". Must be a string.`);
19841
+ process.exit(1);
19842
+ }
19843
+ if (hp.expression !== undefined && typeof hp.expression !== "string") {
19844
+ logger.error(`Invalid load_balancing.hash_policy.expression in service "${service.name}". Must be a string.`);
19845
+ process.exit(1);
19846
+ }
19812
19847
  }
19813
19848
  }
19814
19849
  function validateFailoverConfig(service) {
@@ -19823,8 +19858,8 @@ function validateFailoverConfig(service) {
19823
19858
  if (service.endpoints.length < 2 && failover.enabled) {
19824
19859
  logger.warn(`Service "${service.name}" has failover enabled but less than 2 endpoints. Failover will not be active.`);
19825
19860
  }
19826
- if (failover.recovery?.probe_interval_ms !== undefined) {
19827
- ensurePositiveNumber(failover.recovery.probe_interval_ms, "failover.recovery.probe_interval_ms", `service "${service.name}"`);
19861
+ if (failover.recovery?.backoff_base_ms !== undefined) {
19862
+ ensurePositiveNumber(failover.recovery.backoff_base_ms, "failover.recovery.backoff_base_ms", `service "${service.name}"`);
19828
19863
  }
19829
19864
  if (failover.recovery?.probe_timeout_ms !== undefined) {
19830
19865
  ensurePositiveNumber(failover.recovery.probe_timeout_ms, "failover.recovery.probe_timeout_ms", `service "${service.name}"`);
@@ -19838,10 +19873,6 @@ function validateFailoverConfig(service) {
19838
19873
  if (failover.passive_health?.auto_disable_threshold !== undefined) {
19839
19874
  ensurePositiveNumber(failover.passive_health.auto_disable_threshold, "failover.passive_health.auto_disable_threshold", `service "${service.name}"`);
19840
19875
  }
19841
- if (failover.passive_health?.auto_enable_on_active_health_check !== undefined && typeof failover.passive_health.auto_enable_on_active_health_check !== "boolean") {
19842
- logger.error(`Invalid failover.passive_health.auto_enable_on_active_health_check in service "${service.name}". It must be a boolean.`);
19843
- process.exit(1);
19844
- }
19845
19876
  if (failover.slow_start) {
19846
19877
  if (typeof failover.slow_start.enabled !== "boolean") {
19847
19878
  logger.error(`Invalid failover.slow_start.enabled in service "${service.name}". It must be a boolean.`);
@@ -19858,23 +19889,26 @@ function validateFailoverConfig(service) {
19858
19889
  }
19859
19890
  }
19860
19891
  }
19861
- if (failover.health_check) {
19862
- if (typeof failover.health_check.enabled !== "boolean") {
19863
- logger.error(`Invalid failover.health_check.enabled in service "${service.name}". It must be a boolean.`);
19864
- process.exit(1);
19865
- }
19866
- if (failover.health_check.interval_ms !== undefined) {
19867
- ensurePositiveNumber(failover.health_check.interval_ms, "failover.health_check.interval_ms", `service "${service.name}"`);
19868
- }
19869
- if (failover.health_check.timeout_ms !== undefined) {
19870
- ensurePositiveNumber(failover.health_check.timeout_ms, "failover.health_check.timeout_ms", `service "${service.name}"`);
19871
- }
19872
- if (failover.health_check.unhealthy_threshold !== undefined) {
19873
- ensurePositiveNumber(failover.health_check.unhealthy_threshold, "failover.health_check.unhealthy_threshold", `service "${service.name}"`);
19874
- }
19875
- if (failover.health_check.healthy_threshold !== undefined) {
19876
- ensurePositiveNumber(failover.health_check.healthy_threshold, "failover.health_check.healthy_threshold", `service "${service.name}"`);
19877
- }
19892
+ }
19893
+ function validateServiceHealthCheck(service) {
19894
+ const hc = service.health_check;
19895
+ if (!hc)
19896
+ return;
19897
+ if (typeof hc.enabled !== "boolean") {
19898
+ logger.error(`Invalid health_check.enabled in service "${service.name}". It must be a boolean.`);
19899
+ process.exit(1);
19900
+ }
19901
+ if (hc.interval_ms !== undefined)
19902
+ ensurePositiveNumber(hc.interval_ms, "health_check.interval_ms", `service "${service.name}"`);
19903
+ if (hc.timeout_ms !== undefined)
19904
+ ensurePositiveNumber(hc.timeout_ms, "health_check.timeout_ms", `service "${service.name}"`);
19905
+ if (hc.unhealthy_threshold !== undefined)
19906
+ ensurePositiveNumber(hc.unhealthy_threshold, "health_check.unhealthy_threshold", `service "${service.name}"`);
19907
+ if (hc.healthy_threshold !== undefined)
19908
+ ensurePositiveNumber(hc.healthy_threshold, "health_check.healthy_threshold", `service "${service.name}"`);
19909
+ if (hc.auto_enable_on_active_health_check !== undefined && typeof hc.auto_enable_on_active_health_check !== "boolean") {
19910
+ logger.error(`Invalid health_check.auto_enable_on_active_health_check in service "${service.name}". It must be a boolean.`);
19911
+ process.exit(1);
19878
19912
  }
19879
19913
  }
19880
19914
  function validateAuthConfig(authConfig, context) {
@@ -19923,10 +19957,23 @@ function validateServices(services) {
19923
19957
  process.exit(1);
19924
19958
  }
19925
19959
  }
19926
- validateStickySession(service);
19960
+ validateLoadBalancing(service);
19927
19961
  validateFailoverConfig(service);
19962
+ validateServiceTimeouts(service);
19963
+ validateServiceHealthCheck(service);
19928
19964
  }
19929
19965
  }
19966
+ function validateServiceTimeouts(service) {
19967
+ const t = service.timeouts;
19968
+ if (!t)
19969
+ return;
19970
+ if (t.connect_ms !== undefined)
19971
+ ensurePositiveNumber(t.connect_ms, "timeouts.connect_ms", `service "${service.name}"`);
19972
+ if (t.send_ms !== undefined)
19973
+ ensurePositiveNumber(t.send_ms, "timeouts.send_ms", `service "${service.name}"`);
19974
+ if (t.read_ms !== undefined)
19975
+ ensurePositiveNumber(t.read_ms, "timeouts.read_ms", `service "${service.name}"`);
19976
+ }
19930
19977
  function validateAndNormalizeConfig(config) {
19931
19978
  if (!config.routes || !Array.isArray(config.routes)) {
19932
19979
  logger.error('Error: "routes" is not defined or not an array in config.json.');
@@ -19959,9 +20006,6 @@ function validateAndNormalizeConfig(config) {
19959
20006
  validateAuthConfig(route.auth, `route "${route.path}"`);
19960
20007
  }
19961
20008
  normalizeRouteConfig(route, config.services);
19962
- if (route.timeouts?.connect_ms !== undefined) {
19963
- ensurePositiveNumber(route.timeouts.connect_ms, "timeouts.connect_ms", `route "${route.path}"`);
19964
- }
19965
20009
  if (route.timeouts?.request_ms !== undefined) {
19966
20010
  ensurePositiveNumber(route.timeouts.request_ms, "timeouts.request_ms", `route "${route.path}"`);
19967
20011
  }