@wopr-network/platform-core 1.72.4 → 1.73.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.
@@ -5,6 +5,7 @@
5
5
  * This module provides a standard interface for starting and stopping
6
6
  * those tasks so bootPlatformServer can manage them uniformly.
7
7
  */
8
+ import { logger } from "../config/logger.js";
8
9
  // ---------------------------------------------------------------------------
9
10
  // startBackgroundServices
10
11
  // ---------------------------------------------------------------------------
@@ -36,6 +37,45 @@ export async function startBackgroundServices(container) {
36
37
  // Non-fatal — pool will be empty but claiming falls back to cold create
37
38
  }
38
39
  }
40
+ // Runtime billing cron — daily $0.17/bot deduction (requires fleet + creditLedger)
41
+ if (container.fleet && container.creditLedger) {
42
+ try {
43
+ const { DrizzleBotInstanceRepository } = await import("../fleet/drizzle-bot-instance-repository.js");
44
+ const { DrizzleTenantAddonRepository } = await import("../monetization/addons/addon-repository.js");
45
+ const { startRuntimeScheduler } = await import("../monetization/credits/runtime-scheduler.js");
46
+ const botInstanceRepo = new DrizzleBotInstanceRepository(container.db);
47
+ const tenantAddonRepo = new DrizzleTenantAddonRepository(container.db);
48
+ const scheduler = startRuntimeScheduler({
49
+ ledger: container.creditLedger,
50
+ botInstanceRepo,
51
+ tenantAddonRepo,
52
+ });
53
+ handles.unsubscribes.push(scheduler.stop);
54
+ // Run immediately on startup (idempotent — skips if already billed today)
55
+ const { runRuntimeDeductions, buildResourceTierCosts } = await import("../monetization/credits/runtime-cron.js");
56
+ const { buildAddonCosts } = await import("../monetization/addons/addon-cron.js");
57
+ const today = new Date().toISOString().slice(0, 10);
58
+ void runRuntimeDeductions({
59
+ ledger: container.creditLedger,
60
+ date: today,
61
+ getActiveBotCount: async (tenantId) => {
62
+ const bots = await botInstanceRepo.listByTenant(tenantId);
63
+ return bots.filter((b) => b.billingState === "active").length;
64
+ },
65
+ getResourceTierCosts: buildResourceTierCosts(botInstanceRepo, async (tenantId) => {
66
+ const bots = await botInstanceRepo.listByTenant(tenantId);
67
+ return bots.filter((b) => b.billingState === "active").map((b) => b.id);
68
+ }),
69
+ getAddonCosts: buildAddonCosts(tenantAddonRepo),
70
+ })
71
+ .then((result) => logger.info("Initial runtime deductions complete", result))
72
+ .catch((err) => logger.error("Initial runtime deductions failed", { error: String(err) }));
73
+ logger.info("Runtime billing scheduler started (daily $0.17/bot deduction)");
74
+ }
75
+ catch (err) {
76
+ logger.warn("Failed to start runtime billing scheduler (non-fatal)", { error: String(err) });
77
+ }
78
+ }
39
79
  return handles;
40
80
  }
41
81
  // ---------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wopr-network/platform-core",
3
- "version": "1.72.4",
3
+ "version": "1.73.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -6,6 +6,7 @@
6
6
  * those tasks so bootPlatformServer can manage them uniformly.
7
7
  */
8
8
 
9
+ import { logger } from "../config/logger.js";
9
10
  import type { PlatformContainer } from "./container.js";
10
11
 
11
12
  // ---------------------------------------------------------------------------
@@ -50,6 +51,49 @@ export async function startBackgroundServices(container: PlatformContainer): Pro
50
51
  }
51
52
  }
52
53
 
54
+ // Runtime billing cron — daily $0.17/bot deduction (requires fleet + creditLedger)
55
+ if (container.fleet && container.creditLedger) {
56
+ try {
57
+ const { DrizzleBotInstanceRepository } = await import("../fleet/drizzle-bot-instance-repository.js");
58
+ const { DrizzleTenantAddonRepository } = await import("../monetization/addons/addon-repository.js");
59
+ const { startRuntimeScheduler } = await import("../monetization/credits/runtime-scheduler.js");
60
+
61
+ const botInstanceRepo = new DrizzleBotInstanceRepository(container.db);
62
+ const tenantAddonRepo = new DrizzleTenantAddonRepository(container.db);
63
+
64
+ const scheduler = startRuntimeScheduler({
65
+ ledger: container.creditLedger,
66
+ botInstanceRepo,
67
+ tenantAddonRepo,
68
+ });
69
+ handles.unsubscribes.push(scheduler.stop);
70
+
71
+ // Run immediately on startup (idempotent — skips if already billed today)
72
+ const { runRuntimeDeductions, buildResourceTierCosts } = await import("../monetization/credits/runtime-cron.js");
73
+ const { buildAddonCosts } = await import("../monetization/addons/addon-cron.js");
74
+ const today = new Date().toISOString().slice(0, 10);
75
+ void runRuntimeDeductions({
76
+ ledger: container.creditLedger,
77
+ date: today,
78
+ getActiveBotCount: async (tenantId) => {
79
+ const bots = await botInstanceRepo.listByTenant(tenantId);
80
+ return bots.filter((b) => b.billingState === "active").length;
81
+ },
82
+ getResourceTierCosts: buildResourceTierCosts(botInstanceRepo, async (tenantId) => {
83
+ const bots = await botInstanceRepo.listByTenant(tenantId);
84
+ return bots.filter((b) => b.billingState === "active").map((b) => b.id);
85
+ }),
86
+ getAddonCosts: buildAddonCosts(tenantAddonRepo),
87
+ })
88
+ .then((result) => logger.info("Initial runtime deductions complete", result))
89
+ .catch((err) => logger.error("Initial runtime deductions failed", { error: String(err) }));
90
+
91
+ logger.info("Runtime billing scheduler started (daily $0.17/bot deduction)");
92
+ } catch (err) {
93
+ logger.warn("Failed to start runtime billing scheduler (non-fatal)", { error: String(err) });
94
+ }
95
+ }
96
+
53
97
  return handles;
54
98
  }
55
99