@wopr-network/platform-core 1.74.0 → 1.75.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.
- package/dist/fleet/drizzle-bot-instance-repository.d.ts +3 -1
- package/dist/fleet/drizzle-bot-instance-repository.js +8 -2
- package/dist/fleet/instance.d.ts +8 -0
- package/dist/fleet/instance.js +20 -0
- package/dist/fleet/repository-types.d.ts +1 -1
- package/dist/gateway/proxy.js +10 -2
- package/dist/gateway/types.d.ts +3 -1
- package/dist/index.js +4 -0
- package/dist/monetization/credits/bot-billing.test.js +35 -1
- package/dist/monetization/credits/runtime-cron.d.ts +10 -2
- package/dist/monetization/credits/runtime-cron.js +19 -4
- package/dist/monetization/credits/runtime-cron.test.js +49 -34
- package/dist/monetization/credits/storage-tier-billing.test.js +9 -1
- package/dist/monetization/credits/storage-tier-cron.test.js +13 -7
- package/dist/server/__tests__/container.test.js +5 -1
- package/dist/server/container.d.ts +2 -0
- package/dist/server/container.js +6 -1
- package/dist/server/index.js +1 -1
- package/dist/server/mount-routes.d.ts +1 -1
- package/dist/server/mount-routes.js +35 -2
- package/dist/server/routes/__tests__/admin.test.js +3 -3
- package/package.json +1 -1
- package/src/fleet/drizzle-bot-instance-repository.ts +15 -2
- package/src/fleet/instance.ts +21 -0
- package/src/fleet/repository-types.ts +1 -1
- package/src/gateway/proxy.ts +9 -2
- package/src/gateway/types.ts +3 -1
- package/src/index.ts +4 -0
- package/src/monetization/credits/bot-billing.test.ts +35 -1
- package/src/monetization/credits/runtime-cron.test.ts +51 -38
- package/src/monetization/credits/runtime-cron.ts +21 -4
- package/src/monetization/credits/storage-tier-billing.test.ts +9 -1
- package/src/monetization/credits/storage-tier-cron.test.ts +13 -7
- package/src/server/__tests__/container.test.ts +5 -1
- package/src/server/container.ts +9 -1
- package/src/server/index.ts +1 -1
- package/src/server/mount-routes.ts +41 -3
- package/src/server/routes/__tests__/admin.test.ts +3 -3
package/src/server/container.ts
CHANGED
|
@@ -51,6 +51,8 @@ export interface StripeServices {
|
|
|
51
51
|
|
|
52
52
|
export interface GatewayServices {
|
|
53
53
|
serviceKeyRepo: IServiceKeyRepository;
|
|
54
|
+
meter: import("../metering/emitter.js").MeterEmitter;
|
|
55
|
+
budgetChecker: import("../monetization/budget/budget-checker.js").IBudgetChecker;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export interface HotPoolServices {
|
|
@@ -239,8 +241,14 @@ export async function buildContainer(bootConfig: BootConfig): Promise<PlatformCo
|
|
|
239
241
|
let gateway: GatewayServices | null = null;
|
|
240
242
|
if (bootConfig.features.gateway) {
|
|
241
243
|
const { DrizzleServiceKeyRepository } = await import("../gateway/service-key-repository.js");
|
|
244
|
+
const { MeterEmitter } = await import("../metering/emitter.js");
|
|
245
|
+
const { DrizzleMeterEventRepository } = await import("../metering/meter-event-repository.js");
|
|
246
|
+
const { DrizzleBudgetChecker } = await import("../monetization/budget/budget-checker.js");
|
|
247
|
+
|
|
242
248
|
const serviceKeyRepo: IServiceKeyRepository = new DrizzleServiceKeyRepository(db as never);
|
|
243
|
-
|
|
249
|
+
const meter = new MeterEmitter(new DrizzleMeterEventRepository(db as never), { flushIntervalMs: 5_000 });
|
|
250
|
+
const budgetChecker = new DrizzleBudgetChecker(db as never, { cacheTtlMs: 30_000 });
|
|
251
|
+
gateway = { serviceKeyRepo, meter, budgetChecker };
|
|
244
252
|
}
|
|
245
253
|
|
|
246
254
|
// 12. Build the container (hotPool bound after construction)
|
package/src/server/index.ts
CHANGED
|
@@ -44,12 +44,12 @@ export interface MountConfig {
|
|
|
44
44
|
* 6. Product-specific route plugins
|
|
45
45
|
* 7. Tenant proxy middleware (catch-all — must be last)
|
|
46
46
|
*/
|
|
47
|
-
export function mountRoutes(
|
|
47
|
+
export async function mountRoutes(
|
|
48
48
|
app: Hono,
|
|
49
49
|
container: PlatformContainer,
|
|
50
50
|
config: MountConfig,
|
|
51
51
|
plugins: RoutePlugin[] = [],
|
|
52
|
-
): void {
|
|
52
|
+
): Promise<void> {
|
|
53
53
|
// 1. CORS middleware
|
|
54
54
|
const origins = deriveCorsOrigins(container.productConfig.product, container.productConfig.domains);
|
|
55
55
|
app.use(
|
|
@@ -95,7 +95,45 @@ export function mountRoutes(
|
|
|
95
95
|
);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
// 6.
|
|
98
|
+
// 6. Metered inference gateway (when gateway is enabled)
|
|
99
|
+
if (container.gateway) {
|
|
100
|
+
// Validate billing config exists in DB — fail hard, no silent defaults
|
|
101
|
+
const billingConfig = container.productConfig.billing;
|
|
102
|
+
const marginConfig = billingConfig?.marginConfig as { default?: number } | null;
|
|
103
|
+
if (!marginConfig?.default) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"Gateway enabled but product_billing_config.margin_config.default is not set. " +
|
|
106
|
+
"Seed the DB: INSERT INTO product_billing_config (product_id, margin_config) VALUES ('<id>', '{\"default\": 4.0}')",
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Live margin — reads from productConfig per-request (DB-cached with TTL)
|
|
111
|
+
const initialMargin = marginConfig.default;
|
|
112
|
+
const resolveMargin = (): number => {
|
|
113
|
+
const cfg = container.productConfig.billing?.marginConfig as { default?: number } | null;
|
|
114
|
+
return cfg?.default ?? initialMargin;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const gw = container.gateway;
|
|
118
|
+
const { mountGateway } = await import("../gateway/index.js");
|
|
119
|
+
mountGateway(app, {
|
|
120
|
+
meter: gw.meter,
|
|
121
|
+
budgetChecker: gw.budgetChecker,
|
|
122
|
+
creditLedger: container.creditLedger,
|
|
123
|
+
resolveMargin,
|
|
124
|
+
providers: {
|
|
125
|
+
openrouter: process.env.OPENROUTER_API_KEY
|
|
126
|
+
? { apiKey: process.env.OPENROUTER_API_KEY, baseUrl: process.env.OPENROUTER_BASE_URL || undefined }
|
|
127
|
+
: undefined,
|
|
128
|
+
},
|
|
129
|
+
resolveServiceKey: async (key: string) => {
|
|
130
|
+
const tenant = await gw.serviceKeyRepo.resolve(key);
|
|
131
|
+
return tenant ?? null;
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 7. Product-specific route plugins
|
|
99
137
|
for (const plugin of plugins) {
|
|
100
138
|
app.route(plugin.path, plugin.handler(container));
|
|
101
139
|
}
|
|
@@ -173,6 +173,7 @@ describe("createAdminRouter", () => {
|
|
|
173
173
|
},
|
|
174
174
|
serviceKeyRepo: {} as never,
|
|
175
175
|
},
|
|
176
|
+
gateway: { serviceKeyRepo: {} as never, meter: {} as never, budgetChecker: {} as never },
|
|
176
177
|
});
|
|
177
178
|
|
|
178
179
|
const caller = makeCaller(container);
|
|
@@ -220,6 +221,7 @@ describe("createAdminRouter", () => {
|
|
|
220
221
|
},
|
|
221
222
|
serviceKeyRepo: {} as never,
|
|
222
223
|
},
|
|
224
|
+
gateway: { serviceKeyRepo: {} as never, meter: {} as never, budgetChecker: {} as never },
|
|
223
225
|
});
|
|
224
226
|
|
|
225
227
|
const caller = makeCaller(container);
|
|
@@ -273,9 +275,7 @@ describe("createAdminRouter", () => {
|
|
|
273
275
|
|
|
274
276
|
const container = createTestContainer({
|
|
275
277
|
pool: mockPool as never,
|
|
276
|
-
gateway: {
|
|
277
|
-
serviceKeyRepo: {} as never,
|
|
278
|
-
},
|
|
278
|
+
gateway: { serviceKeyRepo: {} as never, meter: {} as never, budgetChecker: {} as never },
|
|
279
279
|
});
|
|
280
280
|
|
|
281
281
|
const caller = makeCaller(container);
|