@tailuge/messaging 1.3.0 → 1.5.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 +10 -12
- package/SKILL.md +2 -2
- package/dist/index.js +5 -5
- package/dist/lobby.js +3 -3
- package/dist/messagingclient.js +3 -3
- package/dist/table.js +1 -1
- package/dist/types.d.ts +4 -7
- package/dist/types.js +2 -5
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
package/MESSAGING_SPEC.md
CHANGED
|
@@ -131,29 +131,27 @@ interface Table<T = any> {
|
|
|
131
131
|
|
|
132
132
|
## Data Models
|
|
133
133
|
|
|
134
|
-
### `
|
|
134
|
+
### `meta` (Server-Enriched Metadata)
|
|
135
135
|
|
|
136
|
-
All messages published through the transport layer are automatically enriched by the server with metadata from HTTP headers and connection info. This `
|
|
136
|
+
All messages published through the transport layer are automatically enriched by the server with metadata from HTTP headers and connection info. This `meta` object is **added by the server** and should be used by clients as the absolute source of truth for timing (`ts`).
|
|
137
137
|
|
|
138
138
|
```typescript
|
|
139
139
|
interface Meta {
|
|
140
140
|
ts: string; // ISO timestamp of the request (Source of Truth for time)
|
|
141
|
-
locale: string; // Accept-Language header (use for flag rendering)
|
|
142
141
|
ua: string; // User-Agent header
|
|
143
142
|
ip: string; // Client remote address
|
|
144
|
-
origin: string; // Origin header value
|
|
145
143
|
host: string; // Host header value
|
|
146
|
-
path: string; // Request URI path
|
|
147
144
|
method: string; // HTTP method (always POST for publish)
|
|
148
145
|
country: string; // Country code from IP (e.g., "US", "GB", "XX")
|
|
146
|
+
city: string; // City from IP geolocation
|
|
149
147
|
}
|
|
150
148
|
```
|
|
151
149
|
|
|
152
|
-
**Note**: The client should NOT include `
|
|
150
|
+
**Note**: The client should NOT include `ua` in published messages — the server adds this automatically from HTTP headers. This ensures reliable, tamper-resistant metadata for UI features like flag rendering.
|
|
153
151
|
|
|
154
152
|
### `PresenceMessage`
|
|
155
153
|
|
|
156
|
-
Information about a user in the lobby. The `
|
|
154
|
+
Information about a user in the lobby. The `ua` field is **not** set by the client — it is provided by the server via `meta`.
|
|
157
155
|
|
|
158
156
|
```typescript
|
|
159
157
|
interface PresenceMessage {
|
|
@@ -164,8 +162,8 @@ interface PresenceMessage {
|
|
|
164
162
|
ruleType?: string;
|
|
165
163
|
opponentId?: string | null;
|
|
166
164
|
seek?: Seek;
|
|
167
|
-
lastSeen?: number; // Managed internally for pruning (derived from
|
|
168
|
-
|
|
165
|
+
lastSeen?: number; // Managed internally for pruning (derived from meta.ts)
|
|
166
|
+
meta?: Meta; // Server-enriched metadata (received messages only)
|
|
169
167
|
|
|
170
168
|
// Current game state:
|
|
171
169
|
// - If present: user is playing or spectating at that table (available for spectating)
|
|
@@ -187,7 +185,7 @@ interface ChallengeMessage {
|
|
|
187
185
|
recipientId: string;
|
|
188
186
|
ruleType: string;
|
|
189
187
|
tableId?: string; // Optional: table created by challenger
|
|
190
|
-
|
|
188
|
+
meta?: Meta; // Server-enriched metadata (received messages only)
|
|
191
189
|
}
|
|
192
190
|
```
|
|
193
191
|
|
|
@@ -215,7 +213,7 @@ interface TableMessage<T = any> {
|
|
|
215
213
|
type: string;
|
|
216
214
|
senderId: string;
|
|
217
215
|
data: T; // Application-specific payload
|
|
218
|
-
|
|
216
|
+
meta?: Meta; // Server-enriched metadata (received messages only)
|
|
219
217
|
}
|
|
220
218
|
```
|
|
221
219
|
|
|
@@ -363,7 +361,7 @@ table.onMessage((msg) => {
|
|
|
363
361
|
if (msg.type === "MOVE") {
|
|
364
362
|
// msg.data is typed as Move
|
|
365
363
|
applyMove(msg.data);
|
|
366
|
-
console.log("Move received at:", msg.
|
|
364
|
+
console.log("Move received at:", msg.meta?.ts);
|
|
367
365
|
}
|
|
368
366
|
});
|
|
369
367
|
|
package/SKILL.md
CHANGED
|
@@ -40,7 +40,7 @@ const lobby = await client.joinLobby({
|
|
|
40
40
|
lobby.onUsersChange((users) => {
|
|
41
41
|
console.log(`Online: ${users.length}`);
|
|
42
42
|
users.forEach(u => {
|
|
43
|
-
const flag = countryToFlag(u.
|
|
43
|
+
const flag = countryToFlag(u.meta?.country);
|
|
44
44
|
console.log(`${flag} ${u.userName}`);
|
|
45
45
|
});
|
|
46
46
|
});
|
|
@@ -66,7 +66,7 @@ const table = await client.joinTable<Move>("table-xyz", "user-123");
|
|
|
66
66
|
|
|
67
67
|
table.onMessage((msg) => {
|
|
68
68
|
if (msg.type === "MOVE") {
|
|
69
|
-
console.log(`Move at: ${msg.
|
|
69
|
+
console.log(`Move at: ${msg.meta?.ts}`);
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export * from "./messagingclient";
|
|
2
|
-
export * from "./lobby";
|
|
3
|
-
export * from "./table";
|
|
4
|
-
export * from "./types";
|
|
5
|
-
export * from "./nchanclient";
|
|
1
|
+
export * from "./messagingclient.js";
|
|
2
|
+
export * from "./lobby.js";
|
|
3
|
+
export * from "./table.js";
|
|
4
|
+
export * from "./types.js";
|
|
5
|
+
export * from "./nchanclient.js";
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/dist/lobby.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { parseMessage } from "./types";
|
|
2
|
-
import { Table } from "./table";
|
|
3
|
-
import { getUID } from "./utils/uid";
|
|
1
|
+
import { parseMessage } from "./types.js";
|
|
2
|
+
import { Table } from "./table.js";
|
|
3
|
+
import { getUID } from "./utils/uid.js";
|
|
4
4
|
/**
|
|
5
5
|
* Manages the global lobby state, including real-time presence tracking and challenge flows.
|
|
6
6
|
*/
|
package/dist/messagingclient.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { NchanClient } from "./nchanclient";
|
|
2
|
-
import { Lobby } from "./lobby";
|
|
3
|
-
import { Table } from "./table";
|
|
1
|
+
import { NchanClient } from "./nchanclient.js";
|
|
2
|
+
import { Lobby } from "./lobby.js";
|
|
3
|
+
import { Table } from "./table.js";
|
|
4
4
|
/**
|
|
5
5
|
* The main messaging client library entry point.
|
|
6
6
|
* Encapsulates transport logic and provides access to lobby and table functionality.
|
package/dist/table.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseMessage } from "./types";
|
|
1
|
+
import { parseMessage } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Represents a specific communication channel for a 2-player/spectator scenario at a table.
|
|
4
4
|
* Uses `any` as default for internal storage flexibility; consumers should use `unknown` or specific types.
|
package/dist/types.d.ts
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Server-enriched metadata added to all messages by Nchan.
|
|
3
|
-
* This is the absolute source of truth for timing
|
|
3
|
+
* This is the absolute source of truth for timing.
|
|
4
4
|
*/
|
|
5
5
|
export interface Meta {
|
|
6
6
|
ts: string;
|
|
7
|
-
locale: string;
|
|
8
7
|
ua: string;
|
|
9
8
|
ip: string;
|
|
10
|
-
origin: string;
|
|
11
9
|
host: string;
|
|
12
|
-
path: string;
|
|
13
10
|
method: string;
|
|
14
11
|
country: string;
|
|
15
12
|
}
|
|
@@ -32,7 +29,7 @@ export interface PresenceMessage {
|
|
|
32
29
|
opponentId?: string | null;
|
|
33
30
|
seek?: Seek;
|
|
34
31
|
lastSeen?: number;
|
|
35
|
-
|
|
32
|
+
meta?: Meta;
|
|
36
33
|
tableId?: string;
|
|
37
34
|
}
|
|
38
35
|
/**
|
|
@@ -46,7 +43,7 @@ export interface ChallengeMessage {
|
|
|
46
43
|
recipientId: string;
|
|
47
44
|
ruleType: string;
|
|
48
45
|
tableId?: string;
|
|
49
|
-
|
|
46
|
+
meta?: Meta;
|
|
50
47
|
}
|
|
51
48
|
/**
|
|
52
49
|
* Generic structure for table/game events
|
|
@@ -55,7 +52,7 @@ export interface TableMessage<T = unknown> {
|
|
|
55
52
|
type: string;
|
|
56
53
|
senderId: string;
|
|
57
54
|
data: T;
|
|
58
|
-
|
|
55
|
+
meta?: Meta;
|
|
59
56
|
}
|
|
60
57
|
/**
|
|
61
58
|
* Lobby-level information about an active game table
|
package/dist/types.js
CHANGED
|
@@ -12,17 +12,14 @@ export function isChallengeMessage(msg) {
|
|
|
12
12
|
* Returns true if target is not self, not in a game, and not seeking
|
|
13
13
|
*/
|
|
14
14
|
export function canChallenge(target, currentUserId) {
|
|
15
|
-
return
|
|
16
|
-
!target.tableId &&
|
|
17
|
-
!target.seek);
|
|
15
|
+
return target.userId !== currentUserId && !target.tableId && !target.seek;
|
|
18
16
|
}
|
|
19
17
|
/**
|
|
20
18
|
* Predicate: can the current user spectate this target's game?
|
|
21
19
|
* Returns true if target is at a table and it's not the current user's table
|
|
22
20
|
*/
|
|
23
21
|
export function canSpectate(target, currentTableId) {
|
|
24
|
-
return
|
|
25
|
-
target.tableId !== currentTableId);
|
|
22
|
+
return !!target.tableId && target.tableId !== currentTableId;
|
|
26
23
|
}
|
|
27
24
|
/**
|
|
28
25
|
* Filter: derive active games from presence list
|
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":"AAwFA;;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.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A stateful messaging library for Nchan-powered real-time applications.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"test:debug": "npm run playwright",
|
|
24
24
|
"lint": "tsc --noEmit && npx oxlint src test",
|
|
25
25
|
"prettify": "npx oxfmt src test",
|
|
26
|
-
"build": "tsc --declaration",
|
|
26
|
+
"build": "tsc --declaration && node scripts/add-js-extensions.js",
|
|
27
27
|
"release": "npm version minor --no-git-tag-version && npm run build",
|
|
28
28
|
"build:all": "npm run build && npm run build:example && npm run docker:start",
|
|
29
29
|
"build:example": "mkdir -p docker/html/example && npx esbuild example/src/client.ts --bundle --outfile=docker/html/example/client.js && cp example/*.html docker/html/example/",
|