@crowdedkingdoms/crowdyjs 8.4.6 → 8.6.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/MIGRATION.md +27 -0
- package/README.md +2 -1
- package/dist/crowdy-client.d.ts +13 -0
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +6 -2
- package/dist/domains/compute.d.ts +175 -0
- package/dist/domains/compute.d.ts.map +1 -0
- package/dist/domains/compute.js +232 -0
- package/dist/domains/udp.d.ts +5 -1
- package/dist/domains/udp.d.ts.map +1 -1
- package/dist/domains/udp.js +14 -1
- package/dist/generated/graphql.d.ts +893 -1
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +22 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/kit/npcs.d.ts.map +1 -1
- package/dist/kit/social.d.ts.map +1 -1
- package/dist/metrics.d.ts +90 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +158 -0
- package/dist/realtime.d.ts +5 -1
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +26 -1
- package/package.json +1 -1
package/dist/metrics.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Realtime traffic metrics — SDK-owned counters for every spatial message the
|
|
3
|
+
* client sends (the `client.udp.send*` mutations, including the ones issued
|
|
4
|
+
* internally by the World Stores layers) and every notification delivered on
|
|
5
|
+
* the shared `udpNotifications` subscription.
|
|
6
|
+
*
|
|
7
|
+
* Exposed as `client.metrics`; call {@link RealtimeMetrics.snapshot} from a
|
|
8
|
+
* HUD/diagnostics loop. Byte counts measure the app-defined **payload** field
|
|
9
|
+
* of each message (`state` / `audioData` / `text` / `payload` / `voxelState`),
|
|
10
|
+
* not wire framing or GraphQL envelope overhead.
|
|
11
|
+
*/
|
|
12
|
+
const WINDOW_SECONDS = 10;
|
|
13
|
+
/**
|
|
14
|
+
* Counter store behind `client.metrics`. All methods are cheap (plain counter
|
|
15
|
+
* increments and a fixed ring of per-second rate buckets), so recording on
|
|
16
|
+
* every message adds no meaningful overhead to the send/receive hot paths.
|
|
17
|
+
*/
|
|
18
|
+
export class RealtimeMetrics {
|
|
19
|
+
/** @param now - Clock override for tests. Defaults to `Date.now`. */
|
|
20
|
+
constructor(now = Date.now) {
|
|
21
|
+
this.now = now;
|
|
22
|
+
this.perKind = new Map();
|
|
23
|
+
this.totalSent = 0;
|
|
24
|
+
this.totalReceived = 0;
|
|
25
|
+
this.totalBytesSent = 0;
|
|
26
|
+
this.totalBytesReceived = 0;
|
|
27
|
+
this.buckets = Array.from({ length: WINDOW_SECONDS }, () => ({
|
|
28
|
+
second: -1,
|
|
29
|
+
sent: 0,
|
|
30
|
+
received: 0,
|
|
31
|
+
bytesSent: 0,
|
|
32
|
+
bytesReceived: 0,
|
|
33
|
+
}));
|
|
34
|
+
this.startedAtMs = this.now();
|
|
35
|
+
}
|
|
36
|
+
/** Record one outbound message. Called by the SDK's `udp.send*` methods. */
|
|
37
|
+
recordSent(kind, payloadBytes) {
|
|
38
|
+
this.totalSent += 1;
|
|
39
|
+
this.totalBytesSent += payloadBytes;
|
|
40
|
+
const entry = this.kindEntry(kind);
|
|
41
|
+
entry.sent.messages += 1;
|
|
42
|
+
entry.sent.bytes += payloadBytes;
|
|
43
|
+
const bucket = this.bucket();
|
|
44
|
+
bucket.sent += 1;
|
|
45
|
+
bucket.bytesSent += payloadBytes;
|
|
46
|
+
}
|
|
47
|
+
/** Record one delivered notification. Called by the realtime dispatch. */
|
|
48
|
+
recordReceived(kind, payloadBytes) {
|
|
49
|
+
this.totalReceived += 1;
|
|
50
|
+
this.totalBytesReceived += payloadBytes;
|
|
51
|
+
const entry = this.kindEntry(kind);
|
|
52
|
+
entry.received.messages += 1;
|
|
53
|
+
entry.received.bytes += payloadBytes;
|
|
54
|
+
const bucket = this.bucket();
|
|
55
|
+
bucket.received += 1;
|
|
56
|
+
bucket.bytesReceived += payloadBytes;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A point-in-time copy of all counters plus rates averaged over the sliding
|
|
60
|
+
* window. Safe to call every frame; allocation is proportional to the number
|
|
61
|
+
* of distinct message kinds.
|
|
62
|
+
*/
|
|
63
|
+
snapshot() {
|
|
64
|
+
const nowMs = this.now();
|
|
65
|
+
const currentSecond = Math.floor(nowMs / 1000);
|
|
66
|
+
let sent = 0;
|
|
67
|
+
let received = 0;
|
|
68
|
+
let bytesSent = 0;
|
|
69
|
+
let bytesReceived = 0;
|
|
70
|
+
for (const bucket of this.buckets) {
|
|
71
|
+
if (bucket.second < 0 || currentSecond - bucket.second >= WINDOW_SECONDS)
|
|
72
|
+
continue;
|
|
73
|
+
sent += bucket.sent;
|
|
74
|
+
received += bucket.received;
|
|
75
|
+
bytesSent += bucket.bytesSent;
|
|
76
|
+
bytesReceived += bucket.bytesReceived;
|
|
77
|
+
}
|
|
78
|
+
// Average over the tracked lifetime when younger than the full window so
|
|
79
|
+
// early rates aren't diluted by empty seconds that never happened.
|
|
80
|
+
const elapsedSeconds = Math.max(1, Math.min(WINDOW_SECONDS, (nowMs - this.startedAtMs) / 1000));
|
|
81
|
+
const perKind = {};
|
|
82
|
+
for (const [kind, entry] of this.perKind) {
|
|
83
|
+
perKind[kind] = {
|
|
84
|
+
sent: { ...entry.sent },
|
|
85
|
+
received: { ...entry.received },
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
totals: {
|
|
90
|
+
sent: this.totalSent,
|
|
91
|
+
received: this.totalReceived,
|
|
92
|
+
bytesSent: this.totalBytesSent,
|
|
93
|
+
bytesReceived: this.totalBytesReceived,
|
|
94
|
+
},
|
|
95
|
+
perKind,
|
|
96
|
+
rates: {
|
|
97
|
+
sentPerSecond: sent / elapsedSeconds,
|
|
98
|
+
receivedPerSecond: received / elapsedSeconds,
|
|
99
|
+
bytesSentPerSecond: bytesSent / elapsedSeconds,
|
|
100
|
+
bytesReceivedPerSecond: bytesReceived / elapsedSeconds,
|
|
101
|
+
},
|
|
102
|
+
startedAt: this.startedAtMs,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Zero every counter and restart the rate window. */
|
|
106
|
+
reset() {
|
|
107
|
+
this.totalSent = 0;
|
|
108
|
+
this.totalReceived = 0;
|
|
109
|
+
this.totalBytesSent = 0;
|
|
110
|
+
this.totalBytesReceived = 0;
|
|
111
|
+
this.perKind.clear();
|
|
112
|
+
for (const bucket of this.buckets) {
|
|
113
|
+
bucket.second = -1;
|
|
114
|
+
bucket.sent = 0;
|
|
115
|
+
bucket.received = 0;
|
|
116
|
+
bucket.bytesSent = 0;
|
|
117
|
+
bucket.bytesReceived = 0;
|
|
118
|
+
}
|
|
119
|
+
this.startedAtMs = this.now();
|
|
120
|
+
}
|
|
121
|
+
kindEntry(kind) {
|
|
122
|
+
let entry = this.perKind.get(kind);
|
|
123
|
+
if (!entry) {
|
|
124
|
+
entry = {
|
|
125
|
+
sent: { messages: 0, bytes: 0 },
|
|
126
|
+
received: { messages: 0, bytes: 0 },
|
|
127
|
+
};
|
|
128
|
+
this.perKind.set(kind, entry);
|
|
129
|
+
}
|
|
130
|
+
return entry;
|
|
131
|
+
}
|
|
132
|
+
bucket() {
|
|
133
|
+
const second = Math.floor(this.now() / 1000);
|
|
134
|
+
const bucket = this.buckets[second % WINDOW_SECONDS];
|
|
135
|
+
if (bucket.second !== second) {
|
|
136
|
+
bucket.second = second;
|
|
137
|
+
bucket.sent = 0;
|
|
138
|
+
bucket.received = 0;
|
|
139
|
+
bucket.bytesSent = 0;
|
|
140
|
+
bucket.bytesReceived = 0;
|
|
141
|
+
}
|
|
142
|
+
return bucket;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The size of a message's app-defined payload field: the first of `state`,
|
|
147
|
+
* `audioData`, `text`, `payload`, or `voxelState` present as a string. Base64
|
|
148
|
+
* and ASCII payloads measure 1 byte per character; multi-byte UTF-8 text is
|
|
149
|
+
* approximated by its UTF-16 length.
|
|
150
|
+
*/
|
|
151
|
+
export function payloadBytesOf(record) {
|
|
152
|
+
for (const key of ['state', 'audioData', 'text', 'payload', 'voxelState']) {
|
|
153
|
+
const value = record[key];
|
|
154
|
+
if (typeof value === 'string')
|
|
155
|
+
return value.length;
|
|
156
|
+
}
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
package/dist/realtime.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { SessionStore } from './session.js';
|
|
|
2
2
|
import type { CrowdyLogger } from './logger.js';
|
|
3
3
|
import { CrowdyRealtimeError } from './errors.js';
|
|
4
4
|
import type { LbCookieStore } from './lb-cookie-store.js';
|
|
5
|
+
import type { RealtimeMetrics } from './metrics.js';
|
|
5
6
|
import { type UdpNotificationsSubscription } from './generated/graphql.js';
|
|
6
7
|
/**
|
|
7
8
|
* Lifecycle state of the realtime WebSocket connection, as reported by
|
|
@@ -224,6 +225,7 @@ export interface RealtimeConfig {
|
|
|
224
225
|
*/
|
|
225
226
|
export declare class RealtimeClient {
|
|
226
227
|
private readonly session;
|
|
228
|
+
private readonly metrics?;
|
|
227
229
|
private readonly wsUrl;
|
|
228
230
|
private readonly logger;
|
|
229
231
|
private readonly retryAttempts;
|
|
@@ -249,8 +251,10 @@ export declare class RealtimeClient {
|
|
|
249
251
|
* the token tears the connection down (emitting an `AUTH_CLEARED`
|
|
250
252
|
* {@link CrowdyRealtimeError}), while a token change made while connected
|
|
251
253
|
* forces a reconnect using the new token.
|
|
254
|
+
* @param metrics - Optional traffic counters (`client.metrics`); each
|
|
255
|
+
* delivered notification is recorded once, regardless of subscriber count.
|
|
252
256
|
*/
|
|
253
|
-
constructor(config: RealtimeConfig | undefined, session: SessionStore);
|
|
257
|
+
constructor(config: RealtimeConfig | undefined, session: SessionStore, metrics?: RealtimeMetrics | undefined);
|
|
254
258
|
/**
|
|
255
259
|
* The current connection state.
|
|
256
260
|
*
|
package/dist/realtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"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"}
|
package/dist/realtime.js
CHANGED
|
@@ -2,6 +2,7 @@ import { print } from 'graphql';
|
|
|
2
2
|
import { createClient } from 'graphql-ws';
|
|
3
3
|
import { silentLogger } from './logger.js';
|
|
4
4
|
import { CrowdyRealtimeError } from './errors.js';
|
|
5
|
+
import { payloadBytesOf } from './metrics.js';
|
|
5
6
|
import { UdpNotificationsDocument, } from './generated/graphql.js';
|
|
6
7
|
/**
|
|
7
8
|
* Manages the single WebSocket subscription to the game-api's
|
|
@@ -30,9 +31,12 @@ export class RealtimeClient {
|
|
|
30
31
|
* the token tears the connection down (emitting an `AUTH_CLEARED`
|
|
31
32
|
* {@link CrowdyRealtimeError}), while a token change made while connected
|
|
32
33
|
* forces a reconnect using the new token.
|
|
34
|
+
* @param metrics - Optional traffic counters (`client.metrics`); each
|
|
35
|
+
* delivered notification is recorded once, regardless of subscriber count.
|
|
33
36
|
*/
|
|
34
|
-
constructor(config = {}, session) {
|
|
37
|
+
constructor(config = {}, session, metrics) {
|
|
35
38
|
this.session = session;
|
|
39
|
+
this.metrics = metrics;
|
|
36
40
|
this.client = null;
|
|
37
41
|
this.release = null;
|
|
38
42
|
this.desired = false;
|
|
@@ -293,6 +297,7 @@ export class RealtimeClient {
|
|
|
293
297
|
this.ensureSubscription();
|
|
294
298
|
}
|
|
295
299
|
dispatch(notification) {
|
|
300
|
+
this.metrics?.recordReceived(notificationKind(notification.__typename), payloadBytesOf(notification));
|
|
296
301
|
this.resolvePending(notification);
|
|
297
302
|
// A non-retryable connection event (e.g. APP_ID_REQUIRED, AUTH_REQUIRED)
|
|
298
303
|
// means the server completed the subscription and resubscribing would just
|
|
@@ -405,6 +410,26 @@ export class RealtimeClient {
|
|
|
405
410
|
}
|
|
406
411
|
}
|
|
407
412
|
}
|
|
413
|
+
/** GraphQL `__typename` → the handler-style kind name used by `client.metrics`. */
|
|
414
|
+
const NOTIFICATION_KINDS = {
|
|
415
|
+
ActorUpdateNotification: 'actorUpdate',
|
|
416
|
+
ActorUpdateResponse: 'actorUpdateResponse',
|
|
417
|
+
VoxelUpdateNotification: 'voxelUpdate',
|
|
418
|
+
VoxelUpdateResponse: 'voxelUpdateResponse',
|
|
419
|
+
ClientAudioNotification: 'audio',
|
|
420
|
+
ClientTextNotification: 'text',
|
|
421
|
+
ClientEventNotification: 'clientEvent',
|
|
422
|
+
ServerEventNotification: 'serverEvent',
|
|
423
|
+
SingleActorMessageNotification: 'singleActorMessage',
|
|
424
|
+
ChannelMessageNotification: 'channelMessage',
|
|
425
|
+
GenericErrorResponse: 'genericError',
|
|
426
|
+
RealtimeConnectionEvent: 'connectionEvent',
|
|
427
|
+
};
|
|
428
|
+
function notificationKind(typename) {
|
|
429
|
+
if (!typename)
|
|
430
|
+
return 'unknown';
|
|
431
|
+
return NOTIFICATION_KINDS[typename] ?? typename;
|
|
432
|
+
}
|
|
408
433
|
function isNodeRuntime() {
|
|
409
434
|
return (typeof process !== 'undefined' &&
|
|
410
435
|
typeof process.versions?.node === 'string');
|