@tailuge/messaging 1.7.0 → 1.9.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/MESSAGING_SPEC.md +0 -1
- package/dist/ChallengeDeduplicator.d.ts +9 -0
- package/dist/ChallengeDeduplicator.js +46 -0
- package/dist/ChallengeDeduplicator.js.map +1 -0
- package/dist/lobby.d.ts +8 -0
- package/dist/lobby.js +23 -20
- package/dist/lobby.js.map +1 -1
- package/dist/messagingclient.d.ts +2 -0
- package/dist/messagingclient.js +29 -29
- package/dist/messagingclient.js.map +1 -1
- package/dist/nchanclient.js +7 -3
- package/dist/nchanclient.js.map +1 -1
- package/dist/table.js +7 -12
- package/dist/table.js.map +1 -1
- package/dist/types.d.ts +1 -2
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
package/MESSAGING_SPEC.md
CHANGED
|
@@ -139,7 +139,6 @@ All messages published through the transport layer are automatically enriched by
|
|
|
139
139
|
interface Meta {
|
|
140
140
|
ts: string; // ISO timestamp of the request (Source of Truth for time)
|
|
141
141
|
ua: string; // User-Agent header
|
|
142
|
-
ip: string; // Client remote address
|
|
143
142
|
origin: string; // Origin header value
|
|
144
143
|
method: string; // HTTP method (always POST for publish)
|
|
145
144
|
country: string; // Country code from IP (e.g., "US", "GB", "XX")
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ChallengeMessage } from "./types";
|
|
2
|
+
export declare class ChallengeDeduplicator {
|
|
3
|
+
private onEmit;
|
|
4
|
+
private pendingOffers;
|
|
5
|
+
constructor(onEmit: (challenge: ChallengeMessage) => void);
|
|
6
|
+
processMessage(msg: ChallengeMessage, currentUserId: string): void;
|
|
7
|
+
private clearInteraction;
|
|
8
|
+
clear(): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export class ChallengeDeduplicator {
|
|
2
|
+
constructor(onEmit) {
|
|
3
|
+
this.pendingOffers = new Map();
|
|
4
|
+
this.onEmit = onEmit;
|
|
5
|
+
}
|
|
6
|
+
processMessage(msg, currentUserId) {
|
|
7
|
+
// We use a combination of challenger and recipient to uniquely identify the interaction.
|
|
8
|
+
const interactionKey = [msg.challengerId, msg.recipientId].sort().join(':');
|
|
9
|
+
if (msg.type === "offer") {
|
|
10
|
+
// Only process offers directed at us
|
|
11
|
+
if (msg.recipientId === currentUserId) {
|
|
12
|
+
// Clear any prior timer for this specific interaction just in case
|
|
13
|
+
this.clearInteraction(interactionKey);
|
|
14
|
+
const timeoutId = setTimeout(() => {
|
|
15
|
+
this.onEmit(msg);
|
|
16
|
+
this.pendingOffers.delete(interactionKey);
|
|
17
|
+
}, 250);
|
|
18
|
+
timeoutId.unref?.();
|
|
19
|
+
this.pendingOffers.set(interactionKey, timeoutId);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
// Message types: accept, decline, cancel
|
|
24
|
+
// When any resolution happens, cancel any pending timer for this interaction
|
|
25
|
+
this.clearInteraction(interactionKey);
|
|
26
|
+
// We must notify the application if the resolution is directed at us!
|
|
27
|
+
if (msg.recipientId === currentUserId) {
|
|
28
|
+
this.onEmit(msg);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
clearInteraction(key) {
|
|
33
|
+
const timeoutId = this.pendingOffers.get(key);
|
|
34
|
+
if (timeoutId) {
|
|
35
|
+
clearTimeout(timeoutId);
|
|
36
|
+
this.pendingOffers.delete(key);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
clear() {
|
|
40
|
+
for (const timeoutId of this.pendingOffers.values()) {
|
|
41
|
+
clearTimeout(timeoutId);
|
|
42
|
+
}
|
|
43
|
+
this.pendingOffers.clear();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=ChallengeDeduplicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChallengeDeduplicator.js","sourceRoot":"","sources":["../src/ChallengeDeduplicator.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,qBAAqB;IAIhC,YAAY,MAA6C;QAFjD,kBAAa,GAAG,IAAI,GAAG,EAA0B,CAAC;QAGxD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEM,cAAc,CAAC,GAAqB,EAAE,aAAqB;QAChE,yFAAyF;QACzF,MAAM,cAAc,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE5E,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACzB,qCAAqC;YACrC,IAAI,GAAG,CAAC,WAAW,KAAK,aAAa,EAAE,CAAC;gBACtC,mEAAmE;gBACnE,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;gBAEtC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;oBAChC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACjB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;gBAC5C,CAAC,EAAE,GAAG,CAAC,CAAC;gBACR,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;gBAEpB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,yCAAyC;YACzC,6EAA6E;YAC7E,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;YAEtC,sEAAsE;YACtE,IAAI,GAAG,CAAC,WAAW,KAAK,aAAa,EAAE,CAAC;gBACtC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAEO,gBAAgB,CAAC,GAAW;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,SAAS,EAAE,CAAC;YACd,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAEM,KAAK;QACV,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;YACpD,YAAY,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;CACF"}
|
package/dist/lobby.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export declare class Lobby {
|
|
|
15
15
|
private users;
|
|
16
16
|
private listeners;
|
|
17
17
|
private challengeListeners;
|
|
18
|
+
private pendingChallenges;
|
|
19
|
+
private deduplicator;
|
|
18
20
|
private subscription;
|
|
19
21
|
private isJoined;
|
|
20
22
|
private heartbeatTimer?;
|
|
@@ -71,6 +73,7 @@ export declare class Lobby {
|
|
|
71
73
|
cancelChallenge(userId: string, ruleType: string): Promise<void>;
|
|
72
74
|
/**
|
|
73
75
|
* Subscribe to incoming challenges directed at the current user.
|
|
76
|
+
* Delivers any pending challenges that were received while disconnected.
|
|
74
77
|
*/
|
|
75
78
|
onChallenge(callback: (challenge: ChallengeMessage) => void): void;
|
|
76
79
|
/**
|
|
@@ -80,6 +83,11 @@ export declare class Lobby {
|
|
|
80
83
|
isTeardown?: boolean;
|
|
81
84
|
}): Promise<void>;
|
|
82
85
|
private handleIncomingMessage;
|
|
86
|
+
/**
|
|
87
|
+
* Handles incoming presence updates.
|
|
88
|
+
* Note: Nchan guarantees ordered delivery, so we don't need to check meta.ts for ordering.
|
|
89
|
+
* The last message received for each userId will be the current state.
|
|
90
|
+
*/
|
|
83
91
|
private handlePresenceUpdate;
|
|
84
92
|
private handleChallenge;
|
|
85
93
|
private notifyListeners;
|
package/dist/lobby.js
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
import { parseMessage } from "./types.js";
|
|
2
2
|
import { Table } from "./table.js";
|
|
3
3
|
import { getUID } from "./utils/uid.js";
|
|
4
|
+
import { ChallengeDeduplicator } from "./ChallengeDeduplicator.js";
|
|
4
5
|
/**
|
|
5
6
|
* Manages the global lobby state, including real-time presence tracking and challenge flows.
|
|
6
7
|
*/
|
|
7
8
|
export class Lobby {
|
|
8
|
-
nchan;
|
|
9
|
-
currentUser;
|
|
10
|
-
users = new Map();
|
|
11
|
-
listeners = [];
|
|
12
|
-
challengeListeners = [];
|
|
13
|
-
subscription = null;
|
|
14
|
-
isJoined = false;
|
|
15
|
-
heartbeatTimer;
|
|
16
|
-
pruneTimer;
|
|
17
|
-
heartbeatInterval;
|
|
18
|
-
pruneInterval;
|
|
19
|
-
staleTtl;
|
|
20
9
|
constructor(nchan, currentUser, options = {}) {
|
|
21
10
|
this.nchan = nchan;
|
|
22
11
|
this.currentUser = currentUser;
|
|
12
|
+
this.users = new Map();
|
|
13
|
+
this.listeners = [];
|
|
14
|
+
this.challengeListeners = [];
|
|
15
|
+
this.pendingChallenges = [];
|
|
16
|
+
this.subscription = null;
|
|
17
|
+
this.isJoined = false;
|
|
23
18
|
this.heartbeatInterval = options.heartbeatInterval || 30000;
|
|
24
19
|
this.pruneInterval = options.pruneInterval || 10000;
|
|
25
20
|
this.staleTtl = options.staleTtl || 90000;
|
|
21
|
+
this.deduplicator = new ChallengeDeduplicator((msg) => {
|
|
22
|
+
this.pendingChallenges.push(msg);
|
|
23
|
+
this.challengeListeners.forEach((cb) => cb(msg));
|
|
24
|
+
});
|
|
26
25
|
}
|
|
27
26
|
/**
|
|
28
27
|
* Initializes the lobby by subscribing to presence events and broadcasting "join".
|
|
@@ -81,8 +80,7 @@ export class Lobby {
|
|
|
81
80
|
for (const [userId, user] of this.users.entries()) {
|
|
82
81
|
if (userId === this.currentUser.userId)
|
|
83
82
|
continue;
|
|
84
|
-
|
|
85
|
-
const lastSeen = user.lastSeen || now;
|
|
83
|
+
const lastSeen = user.meta.ts;
|
|
86
84
|
if (now - lastSeen > this.staleTtl) {
|
|
87
85
|
this.users.delete(userId);
|
|
88
86
|
changed = true;
|
|
@@ -182,9 +180,11 @@ export class Lobby {
|
|
|
182
180
|
}
|
|
183
181
|
/**
|
|
184
182
|
* Subscribe to incoming challenges directed at the current user.
|
|
183
|
+
* Delivers any pending challenges that were received while disconnected.
|
|
185
184
|
*/
|
|
186
185
|
onChallenge(callback) {
|
|
187
186
|
this.challengeListeners.push(callback);
|
|
187
|
+
this.pendingChallenges.forEach((challenge) => callback(challenge));
|
|
188
188
|
}
|
|
189
189
|
/**
|
|
190
190
|
* Gracefully leaves the lobby.
|
|
@@ -203,6 +203,8 @@ export class Lobby {
|
|
|
203
203
|
console.error("Error leaving lobby:", e);
|
|
204
204
|
}
|
|
205
205
|
this.users.clear();
|
|
206
|
+
this.pendingChallenges = [];
|
|
207
|
+
this.deduplicator.clear();
|
|
206
208
|
this.notifyListeners();
|
|
207
209
|
this.isJoined = false;
|
|
208
210
|
}
|
|
@@ -217,22 +219,23 @@ export class Lobby {
|
|
|
217
219
|
this.handleChallenge(rawMsg);
|
|
218
220
|
}
|
|
219
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Handles incoming presence updates.
|
|
224
|
+
* Note: Nchan guarantees ordered delivery, so we don't need to check meta.ts for ordering.
|
|
225
|
+
* The last message received for each userId will be the current state.
|
|
226
|
+
*/
|
|
220
227
|
handlePresenceUpdate(msg) {
|
|
221
228
|
if (msg.type === "leave") {
|
|
222
229
|
this.users.delete(msg.userId);
|
|
223
230
|
}
|
|
224
231
|
else {
|
|
225
|
-
// Use local time for real-time pruning to avoid clock skew
|
|
226
|
-
msg.lastSeen = Date.now();
|
|
227
232
|
this.users.set(msg.userId, msg);
|
|
228
233
|
}
|
|
229
234
|
this.notifyListeners();
|
|
230
235
|
}
|
|
231
236
|
handleChallenge(msg) {
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
this.challengeListeners.forEach((cb) => cb(msg));
|
|
235
|
-
}
|
|
237
|
+
// Deduplicator tracks state from ALL challenge interactions (offer, accept, decline, cancel)
|
|
238
|
+
this.deduplicator.processMessage(msg, this.currentUser.userId);
|
|
236
239
|
}
|
|
237
240
|
notifyListeners() {
|
|
238
241
|
const list = this.getUsersList();
|
package/dist/lobby.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lobby.js","sourceRoot":"","sources":["../src/lobby.ts"],"names":[],"mappings":"AACA,OAAO,EAAqC,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"lobby.js","sourceRoot":"","sources":["../src/lobby.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,8 @@ export declare class MessagingClient {
|
|
|
27
27
|
}): Promise<void>;
|
|
28
28
|
/**
|
|
29
29
|
* Enters the global lobby for presence broadcasting and tracking.
|
|
30
|
+
* Note: Nchan guarantees ordered message delivery, so the Lobby class does not need
|
|
31
|
+
* to implement message ordering or deduplication based on meta.ts timestamps.
|
|
30
32
|
*/
|
|
31
33
|
joinLobby(user: PresenceMessage, options?: LobbyOptions): Promise<Lobby>;
|
|
32
34
|
/**
|
package/dist/messagingclient.js
CHANGED
|
@@ -6,12 +6,34 @@ import { Table } from "./table.js";
|
|
|
6
6
|
* Encapsulates transport logic and provides access to lobby and table functionality.
|
|
7
7
|
*/
|
|
8
8
|
export class MessagingClient {
|
|
9
|
-
nchan;
|
|
10
|
-
activeLobbies = [];
|
|
11
|
-
activeTables = [];
|
|
12
|
-
lastLobbyConfig;
|
|
13
|
-
isStopping = false;
|
|
14
9
|
constructor(options) {
|
|
10
|
+
this.activeLobbies = [];
|
|
11
|
+
this.activeTables = [];
|
|
12
|
+
this.isStopping = false;
|
|
13
|
+
this.handlePageHide = () => {
|
|
14
|
+
// Stop all connections on page hide (prevent ghosting)
|
|
15
|
+
// Non-blocking call because pagehide might terminate the process
|
|
16
|
+
this.stop({ isTeardown: true });
|
|
17
|
+
};
|
|
18
|
+
this.handlePageShow = async (event) => {
|
|
19
|
+
// If returning via bfcache, restore connections
|
|
20
|
+
if (event.persisted && this.lastLobbyConfig) {
|
|
21
|
+
try {
|
|
22
|
+
await this.joinLobby(this.lastLobbyConfig.user, this.lastLobbyConfig.options);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
console.error("Failed to restore lobby on pageshow:", e);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
this.handleVisibilityChange = () => {
|
|
30
|
+
if (document.hidden) {
|
|
31
|
+
this.activeLobbies.forEach((l) => l.pauseHeartbeat());
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
this.activeLobbies.forEach((l) => l.resumeHeartbeat());
|
|
35
|
+
}
|
|
36
|
+
};
|
|
15
37
|
this.nchan = new NchanClient(options.baseUrl);
|
|
16
38
|
}
|
|
17
39
|
/**
|
|
@@ -52,6 +74,8 @@ export class MessagingClient {
|
|
|
52
74
|
}
|
|
53
75
|
/**
|
|
54
76
|
* Enters the global lobby for presence broadcasting and tracking.
|
|
77
|
+
* Note: Nchan guarantees ordered message delivery, so the Lobby class does not need
|
|
78
|
+
* to implement message ordering or deduplication based on meta.ts timestamps.
|
|
55
79
|
*/
|
|
56
80
|
async joinLobby(user, options) {
|
|
57
81
|
// Prevent duplicate joins if already in a lobby for this user
|
|
@@ -83,29 +107,5 @@ export class MessagingClient {
|
|
|
83
107
|
await lobby.updatePresence({ tableId });
|
|
84
108
|
return table;
|
|
85
109
|
}
|
|
86
|
-
handlePageHide = () => {
|
|
87
|
-
// Stop all connections on page hide (prevent ghosting)
|
|
88
|
-
// Non-blocking call because pagehide might terminate the process
|
|
89
|
-
this.stop({ isTeardown: true });
|
|
90
|
-
};
|
|
91
|
-
handlePageShow = async (event) => {
|
|
92
|
-
// If returning via bfcache, restore connections
|
|
93
|
-
if (event.persisted && this.lastLobbyConfig) {
|
|
94
|
-
try {
|
|
95
|
-
await this.joinLobby(this.lastLobbyConfig.user, this.lastLobbyConfig.options);
|
|
96
|
-
}
|
|
97
|
-
catch (e) {
|
|
98
|
-
console.error("Failed to restore lobby on pageshow:", e);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
handleVisibilityChange = () => {
|
|
103
|
-
if (document.hidden) {
|
|
104
|
-
this.activeLobbies.forEach((l) => l.pauseHeartbeat());
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
this.activeLobbies.forEach((l) => l.resumeHeartbeat());
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
110
|
}
|
|
111
111
|
//# sourceMappingURL=messagingclient.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messagingclient.js","sourceRoot":"","sources":["../src/messagingclient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAgB,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC;;;GAGG;AACH,MAAM,OAAO,eAAe;
|
|
1
|
+
{"version":3,"file":"messagingclient.js","sourceRoot":"","sources":["../src/messagingclient.ts"],"names":[],"mappings":"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"}
|
package/dist/nchanclient.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
const PATHS = {
|
|
2
|
-
PRESENCE_PUBLISH: "/publish/
|
|
3
|
-
PRESENCE_SUBSCRIBE: "/subscribe/
|
|
2
|
+
PRESENCE_PUBLISH: "/publish/presence/lobby",
|
|
3
|
+
PRESENCE_SUBSCRIBE: "/subscribe/presence/lobby",
|
|
4
4
|
TABLE_PUBLISH: (tableId) => `/publish/table/${tableId}`,
|
|
5
5
|
TABLE_SUBSCRIBE: (tableId) => `/subscribe/table/${tableId}`,
|
|
6
6
|
};
|
|
7
7
|
export class NchanClient {
|
|
8
|
-
server;
|
|
9
8
|
constructor(server) {
|
|
10
9
|
// Ensure server string doesn't end with a slash
|
|
11
10
|
this.server = server.replace(/\/$/, "");
|
|
@@ -92,6 +91,11 @@ export class NchanClient {
|
|
|
92
91
|
};
|
|
93
92
|
ws.onopen = () => {
|
|
94
93
|
reconnectAttempts = 0;
|
|
94
|
+
// Clear any pending reconnect timer from previous disconnect
|
|
95
|
+
if (reconnectTimer) {
|
|
96
|
+
clearTimeout(reconnectTimer);
|
|
97
|
+
reconnectTimer = null;
|
|
98
|
+
}
|
|
95
99
|
resolveReady();
|
|
96
100
|
};
|
|
97
101
|
ws.onclose = () => {
|
package/dist/nchanclient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nchanclient.js","sourceRoot":"","sources":["../src/nchanclient.ts"],"names":[],"mappings":"AAEA,MAAM,KAAK,GAAG;IACZ,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"nchanclient.js","sourceRoot":"","sources":["../src/nchanclient.ts"],"names":[],"mappings":"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"}
|
package/dist/table.js
CHANGED
|
@@ -4,23 +4,18 @@ import { parseMessage } from "./types.js";
|
|
|
4
4
|
* Uses `any` as default for internal storage flexibility; consumers should use `unknown` or specific types.
|
|
5
5
|
*/
|
|
6
6
|
export class Table {
|
|
7
|
-
nchan;
|
|
8
|
-
tableId;
|
|
9
|
-
userId;
|
|
10
|
-
lobby;
|
|
11
|
-
subscription = null;
|
|
12
|
-
isJoined = false;
|
|
13
|
-
messageListeners = [];
|
|
14
|
-
spectatorListeners = [];
|
|
15
|
-
opponentLeftListeners = [];
|
|
16
|
-
lobbyUnsubscribe;
|
|
17
|
-
opponentLeft = false;
|
|
18
|
-
opponentSeen = false;
|
|
19
7
|
constructor(nchan, tableId, userId, lobby) {
|
|
20
8
|
this.nchan = nchan;
|
|
21
9
|
this.tableId = tableId;
|
|
22
10
|
this.userId = userId;
|
|
23
11
|
this.lobby = lobby;
|
|
12
|
+
this.subscription = null;
|
|
13
|
+
this.isJoined = false;
|
|
14
|
+
this.messageListeners = [];
|
|
15
|
+
this.spectatorListeners = [];
|
|
16
|
+
this.opponentLeftListeners = [];
|
|
17
|
+
this.opponentLeft = false;
|
|
18
|
+
this.opponentSeen = false;
|
|
24
19
|
if (this.lobby) {
|
|
25
20
|
const handler = (users) => this.handleLobbyUsersChange(users);
|
|
26
21
|
this.lobby.onUsersChange(handler);
|
package/dist/table.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.js","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,YAAY,EAAmB,MAAM,SAAS,CAAC;AAGtE;;;GAGG;AACH,MAAM,OAAO,KAAK;
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* This is the absolute source of truth for timing.
|
|
4
4
|
*/
|
|
5
5
|
export interface Meta {
|
|
6
|
-
ts:
|
|
6
|
+
ts: number;
|
|
7
7
|
ua: string;
|
|
8
8
|
ip: string;
|
|
9
9
|
origin: string;
|
|
@@ -28,7 +28,6 @@ export interface PresenceMessage {
|
|
|
28
28
|
ruleType?: string;
|
|
29
29
|
opponentId?: string | null;
|
|
30
30
|
seek?: Seek;
|
|
31
|
-
lastSeen?: number;
|
|
32
31
|
meta?: Meta;
|
|
33
32
|
tableId?: string;
|
|
34
33
|
}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAuFA;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAQ;IACxC,OAAO,GAAG,EAAE,WAAW,KAAK,UAAU,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAQ;IACzC,OAAO,GAAG,EAAE,WAAW,KAAK,WAAW,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAuB,EAAE,aAAqB;IACzE,OAAO,MAAM,CAAC,MAAM,KAAK,aAAa,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAuB,EAAE,cAAuB;IAC1E,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,KAAK,cAAc,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAwB;IAClD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAE9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE;oBACxB,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,OAAO,EAAE,EAAE;oBACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;iBACxB,CAAC,CAAC;YACL,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAE,CAAC,OAAO,CAAC,IAAI,CAAC;gBACtC,EAAE,EAAE,IAAI,CAAC,MAAM;gBACf,IAAI,EAAE,IAAI,CAAC,QAAQ;aACpB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAI,IAAY;IAC1C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;IAC/B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,CAAC,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailuge/messaging",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A stateful messaging library for Nchan-powered real-time applications.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"esbuild": "^0.27.4",
|
|
52
52
|
"http-server": "^14.1.1",
|
|
53
53
|
"jest": "30.3.0",
|
|
54
|
-
"oxlint": "^1.
|
|
54
|
+
"oxlint": "^1.56.0",
|
|
55
55
|
"testcontainers": "^11.12.0",
|
|
56
56
|
"ts-jest": "^29.4.6",
|
|
57
57
|
"typescript": "5.9.3",
|