@vgai/p2p-colyseus 0.5.4 → 0.5.6

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@vgai/p2p-colyseus",
3
3
  "author": "Volter AI, Inc.",
4
4
  "license": "Apache-2.0",
5
- "version": "0.5.4",
5
+ "version": "0.5.6",
6
6
  "type": "module",
7
7
  "description": "Colyseus-compatible transport for vgai — real Colyseus, loopback, WebRTC, or relay, chosen at runtime.",
8
8
  "homepage": "https://github.com/volter-ai/vgai-engine#readme",
@@ -18,6 +18,8 @@ interface DurableObjectStateLike {
18
18
  }
19
19
 
20
20
  interface DurableRoomEnv {
21
+ VGAI_BILLING?: { fetch(request: Request): Promise<Response> };
22
+ VGAI_BILLING_SERVICE_TOKEN?: string;
21
23
  P2P_COLYSEUS_RELAY_DISABLED?: string | undefined;
22
24
  P2P_COLYSEUS_RELAY_DAILY_BUDGET_USD?: string | undefined;
23
25
  P2P_COLYSEUS_RELAY_ESTIMATED_USD_PER_GIB?: string | undefined;
@@ -428,14 +430,75 @@ export class P2PColyseusDurableRoom {
428
430
  bytes: number,
429
431
  ): Promise<ErrorSignalEnvelope | null> {
430
432
  if (!principal) return null;
431
- return this.consumeDailyCounter(
433
+ const cap = await this.consumeDailyCounter(
432
434
  `relay-account-bytes:${principal}`,
433
435
  bytes,
434
436
  getFreeRelayBytesPerAccountPerDay(this.env),
435
437
  );
438
+ if (cap || !getRequireAccount(this.env)) return cap;
439
+ if (!this.env.VGAI_BILLING) {
440
+ return { kind: 'error', message: String(P2P_CLOSE_CODES.relayQuotaExceeded) };
441
+ }
442
+ const serviceToken = this.env.VGAI_BILLING_SERVICE_TOKEN?.trim();
443
+ if (!serviceToken) {
444
+ return { kind: 'error', message: String(P2P_CLOSE_CODES.relayQuotaExceeded) };
445
+ }
446
+ const day = dayKey(Date.now());
447
+ const offset =
448
+ (await this.state?.storage?.get<number>(`relay-account-bytes:${principal}:${day}`)) ?? bytes;
449
+ const authorization = await this.env.VGAI_BILLING.fetch(
450
+ new Request('https://billing.internal/usage/authorize', {
451
+ method: 'POST',
452
+ headers: billingHeaders(serviceToken),
453
+ body: JSON.stringify({
454
+ userId: principal,
455
+ kind: 'relay',
456
+ provider: 'cloudflare',
457
+ operation: 'relay-bytes',
458
+ operationId: `relay:${principal}:${day}:${offset}`,
459
+ providerPrice: { relayBytes: bytes },
460
+ }),
461
+ }),
462
+ );
463
+ const authorizationBody = (await authorization.json().catch(() => undefined)) as
464
+ | { reservationId?: unknown }
465
+ | undefined;
466
+ if (!authorization.ok || typeof authorizationBody?.reservationId !== 'string') {
467
+ return { kind: 'error', message: String(P2P_CLOSE_CODES.relayQuotaExceeded) };
468
+ }
469
+ const settled = await this.env.VGAI_BILLING.fetch(
470
+ new Request('https://billing.internal/usage/settle', {
471
+ method: 'POST',
472
+ headers: billingHeaders(serviceToken),
473
+ body: JSON.stringify({
474
+ reservationId: authorizationBody.reservationId,
475
+ kind: 'relay',
476
+ provider: 'cloudflare',
477
+ operation: 'relay-bytes',
478
+ providerUsage: { relayBytes: bytes },
479
+ externalId: `relay:${principal}:${day}:${offset}`,
480
+ }),
481
+ }),
482
+ );
483
+ if (settled.ok) return null;
484
+ await this.env.VGAI_BILLING.fetch(
485
+ new Request('https://billing.internal/usage/release', {
486
+ method: 'POST',
487
+ headers: billingHeaders(serviceToken),
488
+ body: JSON.stringify({
489
+ reservationId: authorizationBody.reservationId,
490
+ reason: 'relay_settlement_failed',
491
+ }),
492
+ }),
493
+ );
494
+ return { kind: 'error', message: String(P2P_CLOSE_CODES.relayQuotaExceeded) };
436
495
  }
437
496
  }
438
497
 
498
+ function billingHeaders(token: string): HeadersInit {
499
+ return { 'Content-Type': 'application/json', 'X-VGAI-Service-Token': token };
500
+ }
501
+
439
502
  function unauthorized(): ErrorSignalEnvelope {
440
503
  return { kind: 'error', message: String(P2P_CLOSE_CODES.unauthorized) };
441
504
  }