@wopr-network/platform-core 1.73.0 → 1.74.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.
@@ -125,6 +125,15 @@ export class FleetManager {
125
125
  }
126
126
  const instance = await this.buildInstance(profile);
127
127
  instance.emitCreated();
128
+ // Register in bot_instances DB table for billing
129
+ if (this.instanceRepo) {
130
+ try {
131
+ await this.instanceRepo.register(id, profile.tenantId, profile.name);
132
+ }
133
+ catch (err) {
134
+ logger.warn("Failed to register bot instance in DB (non-fatal)", { id, err });
135
+ }
136
+ }
128
137
  return instance;
129
138
  };
130
139
  return hasExplicitId ? this.withLock(id, doCreate) : doCreate();
@@ -208,6 +217,15 @@ export class FleetManager {
208
217
  if (this.networkPolicy) {
209
218
  await this.networkPolicy.cleanupAfterRemoval(profile.tenantId);
210
219
  }
220
+ // Remove from bot_instances DB table
221
+ if (this.instanceRepo) {
222
+ try {
223
+ await this.instanceRepo.deleteById(id);
224
+ }
225
+ catch (err) {
226
+ logger.warn("Failed to delete bot instance from DB (non-fatal)", { id, err });
227
+ }
228
+ }
211
229
  await this.store.delete(id);
212
230
  logger.info(`Removed bot ${id}`);
213
231
  this.emitEvent("bot.removed", id, profile.tenantId);
@@ -80,9 +80,12 @@ export async function buildContainer(bootConfig) {
80
80
  const profileStore = new ProfileStore(fleetDataDir);
81
81
  const proxy = new ProxyManager();
82
82
  const serviceKeyRepo = new DrizzleServiceKeyRepository(db);
83
+ const { DrizzleBotInstanceRepository } = await import("../fleet/drizzle-bot-instance-repository.js");
84
+ const botInstanceRepo = new DrizzleBotInstanceRepository(db);
83
85
  const manager = new FleetManagerClass(docker, profileStore, undefined, // platformDiscovery
84
86
  undefined, // networkPolicy
85
- proxy);
87
+ proxy, undefined, // commandBus
88
+ botInstanceRepo);
86
89
  fleet = { manager, docker, proxy, profileStore, serviceKeyRepo };
87
90
  }
88
91
  // 9. Crypto services (when enabled)
@@ -27,6 +27,33 @@ export async function startBackgroundServices(container) {
27
27
  // Non-fatal — proxy sync will retry on next health tick
28
28
  }
29
29
  }
30
+ // Backfill bot_instances from YAML profiles (one-time sync on startup)
31
+ if (container.fleet) {
32
+ try {
33
+ const { DrizzleBotInstanceRepository } = await import("../fleet/drizzle-bot-instance-repository.js");
34
+ const botInstanceRepo = new DrizzleBotInstanceRepository(container.db);
35
+ const profiles = await container.fleet.profileStore.list();
36
+ let synced = 0;
37
+ for (const profile of profiles) {
38
+ const existing = await botInstanceRepo.getById(profile.id);
39
+ if (!existing) {
40
+ try {
41
+ await botInstanceRepo.register(profile.id, profile.tenantId, profile.name);
42
+ synced++;
43
+ }
44
+ catch {
45
+ // Ignore duplicates / constraint violations
46
+ }
47
+ }
48
+ }
49
+ if (synced > 0) {
50
+ logger.info(`Backfilled ${synced} bot instances from profiles into DB`);
51
+ }
52
+ }
53
+ catch (err) {
54
+ logger.warn("Failed to backfill bot_instances (non-fatal)", { error: String(err) });
55
+ }
56
+ }
30
57
  // Hot pool manager (if enabled)
31
58
  if (container.hotPool) {
32
59
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wopr-network/platform-core",
3
- "version": "1.73.0",
3
+ "version": "1.74.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -152,6 +152,16 @@ export class FleetManager {
152
152
 
153
153
  const instance = await this.buildInstance(profile);
154
154
  instance.emitCreated();
155
+
156
+ // Register in bot_instances DB table for billing
157
+ if (this.instanceRepo) {
158
+ try {
159
+ await this.instanceRepo.register(id, profile.tenantId, profile.name);
160
+ } catch (err) {
161
+ logger.warn("Failed to register bot instance in DB (non-fatal)", { id, err });
162
+ }
163
+ }
164
+
155
165
  return instance;
156
166
  };
157
167
 
@@ -239,6 +249,15 @@ export class FleetManager {
239
249
  await this.networkPolicy.cleanupAfterRemoval(profile.tenantId);
240
250
  }
241
251
 
252
+ // Remove from bot_instances DB table
253
+ if (this.instanceRepo) {
254
+ try {
255
+ await this.instanceRepo.deleteById(id);
256
+ } catch (err) {
257
+ logger.warn("Failed to delete bot instance from DB (non-fatal)", { id, err });
258
+ }
259
+ }
260
+
242
261
  await this.store.delete(id);
243
262
  logger.info(`Removed bot ${id}`);
244
263
  this.emitEvent("bot.removed", id, profile.tenantId);
@@ -178,12 +178,17 @@ export async function buildContainer(bootConfig: BootConfig): Promise<PlatformCo
178
178
  const profileStore: IProfileStore = new ProfileStore(fleetDataDir);
179
179
  const proxy: ProxyManagerInterface = new ProxyManager();
180
180
  const serviceKeyRepo: IServiceKeyRepository = new DrizzleServiceKeyRepository(db as never);
181
+ const { DrizzleBotInstanceRepository } = await import("../fleet/drizzle-bot-instance-repository.js");
182
+ const botInstanceRepo = new DrizzleBotInstanceRepository(db as never);
183
+
181
184
  const manager: FleetManager = new FleetManagerClass(
182
185
  docker,
183
186
  profileStore,
184
187
  undefined, // platformDiscovery
185
188
  undefined, // networkPolicy
186
189
  proxy,
190
+ undefined, // commandBus
191
+ botInstanceRepo,
187
192
  );
188
193
 
189
194
  fleet = { manager, docker, proxy, profileStore, serviceKeyRepo };
@@ -41,6 +41,32 @@ export async function startBackgroundServices(container: PlatformContainer): Pro
41
41
  }
42
42
  }
43
43
 
44
+ // Backfill bot_instances from YAML profiles (one-time sync on startup)
45
+ if (container.fleet) {
46
+ try {
47
+ const { DrizzleBotInstanceRepository } = await import("../fleet/drizzle-bot-instance-repository.js");
48
+ const botInstanceRepo = new DrizzleBotInstanceRepository(container.db);
49
+ const profiles = await container.fleet.profileStore.list();
50
+ let synced = 0;
51
+ for (const profile of profiles) {
52
+ const existing = await botInstanceRepo.getById(profile.id);
53
+ if (!existing) {
54
+ try {
55
+ await botInstanceRepo.register(profile.id, profile.tenantId, profile.name);
56
+ synced++;
57
+ } catch {
58
+ // Ignore duplicates / constraint violations
59
+ }
60
+ }
61
+ }
62
+ if (synced > 0) {
63
+ logger.info(`Backfilled ${synced} bot instances from profiles into DB`);
64
+ }
65
+ } catch (err) {
66
+ logger.warn("Failed to backfill bot_instances (non-fatal)", { error: String(err) });
67
+ }
68
+ }
69
+
44
70
  // Hot pool manager (if enabled)
45
71
  if (container.hotPool) {
46
72
  try {