@wopr-network/platform-core 1.33.0 → 1.34.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.
@@ -40,6 +40,8 @@ export interface FleetUpdaterConfig {
40
40
  configRepo?: ITenantUpdateConfigRepository;
41
41
  /** Optional fleet event emitter. When provided, bot.updated / bot.update_failed events are emitted. */
42
42
  eventEmitter?: FleetEventEmitter;
43
+ /** Called with manual-mode tenant IDs when a new image is available but they are excluded from rollout. */
44
+ onManualTenantsSkipped?: (tenantIds: string[]) => void;
43
45
  }
44
46
  export interface FleetUpdaterHandle {
45
47
  poller: ImagePoller;
@@ -30,7 +30,7 @@ import { VolumeSnapshotManager } from "./volume-snapshot-manager.js";
30
30
  * @param config - Optional pipeline configuration
31
31
  */
32
32
  export function initFleetUpdater(docker, fleet, profileStore, profileRepo, config = {}) {
33
- const { strategy: strategyType = "rolling-wave", strategyOptions, snapshotDir = "/data/fleet/snapshots", onBotUpdated, onRolloutComplete, configRepo, eventEmitter: configEventEmitter, } = config;
33
+ const { strategy: strategyType = "rolling-wave", strategyOptions, snapshotDir = "/data/fleet/snapshots", onBotUpdated, onRolloutComplete, configRepo, eventEmitter: configEventEmitter, onManualTenantsSkipped, } = config;
34
34
  const emitter = configEventEmitter ?? new FleetEventEmitter();
35
35
  const poller = new ImagePoller(docker, profileStore);
36
36
  const updater = new ContainerUpdater(docker, profileStore, fleet, poller);
@@ -42,17 +42,36 @@ export function initFleetUpdater(docker, fleet, profileStore, profileRepo, confi
42
42
  strategy,
43
43
  getUpdatableProfiles: async () => {
44
44
  const profiles = await profileRepo.list();
45
- const nonManualPolicy = profiles.filter((p) => p.updatePolicy !== "manual");
46
- if (!configRepo)
45
+ // Separate profiles by updatePolicy
46
+ const manualPolicyIds = [];
47
+ const nonManualPolicy = profiles.filter((p) => {
48
+ if (p.updatePolicy === "manual") {
49
+ manualPolicyIds.push(p.tenantId);
50
+ return false;
51
+ }
52
+ return true;
53
+ });
54
+ if (!configRepo) {
55
+ if (manualPolicyIds.length > 0 && onManualTenantsSkipped) {
56
+ onManualTenantsSkipped([...new Set(manualPolicyIds)]);
57
+ }
47
58
  return nonManualPolicy;
59
+ }
48
60
  // Filter out tenants whose per-tenant config is set to manual
61
+ const configManualIds = [];
49
62
  const results = await Promise.all(nonManualPolicy.map(async (p) => {
50
63
  const tenantCfg = await configRepo.get(p.tenantId);
51
64
  // If tenant has an explicit config with mode=manual, exclude
52
- if (tenantCfg && tenantCfg.mode === "manual")
65
+ if (tenantCfg && tenantCfg.mode === "manual") {
66
+ configManualIds.push(p.tenantId);
53
67
  return null;
68
+ }
54
69
  return p;
55
70
  }));
71
+ const allManualIds = [...manualPolicyIds, ...configManualIds];
72
+ if (allManualIds.length > 0 && onManualTenantsSkipped) {
73
+ onManualTenantsSkipped([...new Set(allManualIds)]);
74
+ }
56
75
  return results.filter((p) => p !== null);
57
76
  },
58
77
  onBotUpdated: (result) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wopr-network/platform-core",
3
- "version": "1.33.0",
3
+ "version": "1.34.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -39,6 +39,8 @@ export interface FleetUpdaterConfig {
39
39
  configRepo?: ITenantUpdateConfigRepository;
40
40
  /** Optional fleet event emitter. When provided, bot.updated / bot.update_failed events are emitted. */
41
41
  eventEmitter?: FleetEventEmitter;
42
+ /** Called with manual-mode tenant IDs when a new image is available but they are excluded from rollout. */
43
+ onManualTenantsSkipped?: (tenantIds: string[]) => void;
42
44
  }
43
45
 
44
46
  export interface FleetUpdaterHandle {
@@ -79,6 +81,7 @@ export function initFleetUpdater(
79
81
  onRolloutComplete,
80
82
  configRepo,
81
83
  eventEmitter: configEventEmitter,
84
+ onManualTenantsSkipped,
82
85
  } = config;
83
86
 
84
87
  const emitter = configEventEmitter ?? new FleetEventEmitter();
@@ -94,19 +97,43 @@ export function initFleetUpdater(
94
97
  strategy,
95
98
  getUpdatableProfiles: async () => {
96
99
  const profiles = await profileRepo.list();
97
- const nonManualPolicy = profiles.filter((p) => p.updatePolicy !== "manual");
98
100
 
99
- if (!configRepo) return nonManualPolicy;
101
+ // Separate profiles by updatePolicy
102
+ const manualPolicyIds: string[] = [];
103
+ const nonManualPolicy = profiles.filter((p) => {
104
+ if (p.updatePolicy === "manual") {
105
+ manualPolicyIds.push(p.tenantId);
106
+ return false;
107
+ }
108
+ return true;
109
+ });
110
+
111
+ if (!configRepo) {
112
+ if (manualPolicyIds.length > 0 && onManualTenantsSkipped) {
113
+ onManualTenantsSkipped([...new Set(manualPolicyIds)]);
114
+ }
115
+ return nonManualPolicy;
116
+ }
100
117
 
101
118
  // Filter out tenants whose per-tenant config is set to manual
119
+ const configManualIds: string[] = [];
102
120
  const results = await Promise.all(
103
121
  nonManualPolicy.map(async (p) => {
104
122
  const tenantCfg = await configRepo.get(p.tenantId);
105
123
  // If tenant has an explicit config with mode=manual, exclude
106
- if (tenantCfg && tenantCfg.mode === "manual") return null;
124
+ if (tenantCfg && tenantCfg.mode === "manual") {
125
+ configManualIds.push(p.tenantId);
126
+ return null;
127
+ }
107
128
  return p;
108
129
  }),
109
130
  );
131
+
132
+ const allManualIds = [...manualPolicyIds, ...configManualIds];
133
+ if (allManualIds.length > 0 && onManualTenantsSkipped) {
134
+ onManualTenantsSkipped([...new Set(allManualIds)]);
135
+ }
136
+
110
137
  return results.filter((p) => p !== null);
111
138
  },
112
139
  onBotUpdated: (result) => {