@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 CHANGED
@@ -131,29 +131,27 @@ interface Table<T = any> {
131
131
 
132
132
  ## Data Models
133
133
 
134
- ### `_meta` (Server-Enriched Metadata)
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 `_meta` object is **added by the server** and should be used by clients as the absolute source of truth for timing (`ts`) and origin.
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 `locale` or `ua` in published messages — the server adds these automatically from HTTP headers. This ensures reliable, tamper-resistant metadata for UI features like flag rendering.
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 `locale` and `ua` fields are **not** set by the client — they are provided by the server via `_meta`.
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 _meta.ts)
168
- _meta?: Meta; // Server-enriched metadata (received messages only)
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
- _meta?: Meta; // Server-enriched metadata (received messages only)
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
- _meta?: Meta; // Server-enriched metadata (received messages only)
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._meta?.ts);
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._meta?.country);
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._meta?.ts}`);
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
  */
@@ -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 and origin.
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
- _meta?: Meta;
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
- _meta?: Meta;
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
- _meta?: Meta;
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 (target.userId !== currentUserId &&
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 (!!target.tableId &&
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":"AA2FA;;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,CACL,MAAM,CAAC,MAAM,KAAK,aAAa;QAC/B,CAAC,MAAM,CAAC,OAAO;QACf,CAAC,MAAM,CAAC,IAAI,CACb,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAuB,EAAE,cAAuB;IAC1E,OAAO,CACL,CAAC,CAAC,MAAM,CAAC,OAAO;QAChB,MAAM,CAAC,OAAO,KAAK,cAAc,CAClC,CAAC;AACJ,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"}
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.0",
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/",