@ai-matrx/messaging 0.4.0 → 0.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,84 @@
1
1
  # Changelog — `@ai-matrx/messaging`
2
2
 
3
+ ## 0.7.0 — 2026-09-07
4
+
5
+ 🚨 **Every RPC in this package was calling the wrong schema, so every read failed against the
6
+ live database.** Found the first time the package ran a real query — the honest verification the
7
+ work order named, which is also why no source gate could have caught it.
8
+
9
+ ### Fixed
10
+
11
+ - **RPCs are called on `public`; only the TABLES are in `communication`.** Matrx Main's messaging
12
+ tables moved into `communication` during the schema reorg, and the five auth-checked SECURITY
13
+ DEFINER functions stayed in `public` where PostgREST exposes them by default and where every
14
+ existing caller and GRANT already pointed. This package sent both to `communication`, so the
15
+ inbox read, the direct-conversation get-or-create, the unread count, the profile read and the
16
+ participant check all failed with PGRST202 — *"Could not find the function
17
+ communication.get_dm_conversations_with_details … in the schema cache"*. The whole product was
18
+ dead against the real database while 129 tests and a packed-tarball canary stayed green,
19
+ because a fake PostgREST answers whatever schema it is asked for.
20
+ - New constant `MESSAGING_RPC_SCHEMA` (`"public"`), exported and asserted by the tarball canary
21
+ beside `MESSAGING_SCHEMA`, with the verification query in a comment above it. A regression test
22
+ proves the RPC lands on `public` and the table write on `communication`; it fails when the two
23
+ are collapsed.
24
+
25
+ **The lesson, recorded where the next agent will read it:** "verified against the live schema by
26
+ inspection" is not verification. One query would have found this on day one.
27
+
28
+ ### Consumer action (C28)
29
+
30
+ None. Nothing in the API changed — the package simply works against the real database now.
31
+
32
+ ## 0.6.0 — 2026-09-07
33
+
34
+ **The two entries did not agree on their own branded ids.** A consumer that minted a
35
+ `ConversationId` with `asConversationId` from `@ai-matrx/messaging` could not pass it to a hook
36
+ from `@ai-matrx/messaging/react` — the two were different types, with an error message that
37
+ blames the consumer. Found by the first real adoption, which does exactly that on its
38
+ conversation route.
39
+
40
+ ### Fixed
41
+
42
+ - **The nominal brand is a named marker, not a `unique symbol`.** The package ships two entries
43
+ built as two bundles, so every shared type is DECLARED TWICE in the shipped `.d.ts` — and two
44
+ `declare const brand: unique symbol` declarations are two different symbols, hence two
45
+ incompatible `ConversationId`s. A structural marker (`__mxBrand`) is identical in both
46
+ declarations, so the brands unify while still being impossible to produce by accident. No
47
+ runtime change: the marker is types-only.
48
+ - **`verify-tarball` now typechecks a real consumer against BOTH entries** — core-minted ids
49
+ assigned to `/react` types and back. It fails against the `unique symbol` build, which is the
50
+ only way this class can be caught: in `src/` there is only ever one declaration, so every
51
+ source gate stays green while the shipped types are broken.
52
+ - The canary still imported `getInitials` / `avatarPaletteIndex`, which moved to
53
+ `@ai-matrx/kit/format` in 0.5.0 — it would have failed that release's publish.
54
+
55
+ ### Consumer action (C28)
56
+
57
+ None. `asConversationId(...)` and friends behave exactly as before; ids from the two entries now
58
+ actually interoperate, which is what the types always claimed.
59
+
60
+ ## 0.5.0 — 2026-09-07
61
+
62
+ **Consumer action (C28).** Two exports MOVED OUT of this package to
63
+ `@ai-matrx/kit/format`. Update the import; the behaviour is identical.
64
+
65
+ | was | now |
66
+ |---|---|
67
+ | `import { getInitials } from "@ai-matrx/messaging"` | `import { getInitials } from "@ai-matrx/kit/format"` |
68
+ | `import { avatarPaletteIndex } from "@ai-matrx/messaging"` | `import { avatarPaletteIndex } from "@ai-matrx/kit/format"` |
69
+
70
+ **Why.** Duplication census finding H1 (2026-09-07): both bodies were
71
+ duplicated in `@ai-matrx/meet`, and while two packages claimed them no host
72
+ twin had a correct owner to point at. They now live in `@ai-matrx/kit`, which
73
+ has zero sibling dependencies.
74
+
75
+ The conversation-shaped formatters — `formatConversationTime`,
76
+ `formatMessageTime`, `formatDateSeparator`, `formatLastSeen`, `formatTypists`,
77
+ `groupMessages`, `isSameDay`, `participantNames` — all stay here. Nothing is
78
+ re-exported: this package imports kit directly.
79
+
80
+ New dependency: `@ai-matrx/kit` (`latest`).
81
+
3
82
  ## 0.4.0 — 2026-09-07
4
83
 
5
84
  **A ```matrx fence written in the PLATFORM's dialect was being deleted on render.** Found the
package/README.md CHANGED
@@ -314,7 +314,8 @@ One canonical schema, in Matrx Main, under the platform's DB conventions:
314
314
 
315
315
  | | |
316
316
  |---|---|
317
- | Schema | `communication` (never `public`) |
317
+ | Table schema | `communication` (never `public`) |
318
+ | RPC schema | `public` — the SECURITY DEFINER functions stayed there through the schema reorg. The two DIFFER, deliberately; collapsing them fails every read with PGRST202 |
318
319
  | Tables | `dm_conversations`, `dm_conversation_participants`, `dm_messages` |
319
320
  | RPCs | `dm_get_or_create_direct_conversation`, `get_dm_conversations_with_details`, `get_dm_user_info`, `get_dm_unread_count`, `is_dm_participant` |
320
321
 
package/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  MESSAGING_EVENTS: () => MESSAGING_EVENTS,
24
+ MESSAGING_RPC_SCHEMA: () => MESSAGING_RPC_SCHEMA,
24
25
  MESSAGING_SCHEMA: () => MESSAGING_SCHEMA,
25
26
  MessagingError: () => MessagingError,
26
27
  RPCS: () => RPCS,
@@ -30,7 +31,6 @@ __export(src_exports, {
30
31
  asMessageId: () => asMessageId,
31
32
  asOrganizationId: () => asOrganizationId,
32
33
  asUserId: () => asUserId,
33
- avatarPaletteIndex: () => avatarPaletteIndex,
34
34
  composeFence: () => composeFence,
35
35
  conversationTopic: () => conversationTopic,
36
36
  createActionRegistry: () => createActionRegistry,
@@ -48,7 +48,6 @@ __export(src_exports, {
48
48
  formatLastSeen: () => formatLastSeen,
49
49
  formatMessageTime: () => formatMessageTime,
50
50
  formatTypists: () => formatTypists,
51
- getInitials: () => getInitials,
52
51
  groupMessages: () => groupMessages,
53
52
  inboxTopic: () => inboxTopic,
54
53
  invalidResponse: () => invalidResponse,
@@ -1496,20 +1495,6 @@ function formatDateSeparator(isoString, now = Date.now(), locale) {
1496
1495
  day: "numeric"
1497
1496
  });
1498
1497
  }
1499
- function getInitials(name) {
1500
- const parts = name.trim().split(/\s+/).filter(Boolean);
1501
- if (parts.length === 0) return "?";
1502
- const first = parts[0]?.[0] ?? "";
1503
- const last = parts.length > 1 ? parts.at(-1)?.[0] ?? "" : "";
1504
- return `${first}${last}`.toUpperCase() || "?";
1505
- }
1506
- function avatarPaletteIndex(seed, buckets = 8) {
1507
- let hash = 0;
1508
- for (let index = 0; index < seed.length; index += 1) {
1509
- hash = hash * 31 + seed.charCodeAt(index) | 0;
1510
- }
1511
- return Math.abs(hash) % buckets;
1512
- }
1513
1498
  function groupMessages(messages, args = {}) {
1514
1499
  const windowMs = args.windowMs ?? 5 * MINUTE;
1515
1500
  const now = args.now ?? Date.now();
@@ -1556,6 +1541,7 @@ function formatLastSeen(lastSeenMs, now = Date.now()) {
1556
1541
 
1557
1542
  // src/core/repository.ts
1558
1543
  var MESSAGING_SCHEMA = "communication";
1544
+ var MESSAGING_RPC_SCHEMA = "public";
1559
1545
  var TABLES = {
1560
1546
  conversations: "dm_conversations",
1561
1547
  participants: "dm_conversation_participants",
@@ -1590,6 +1576,7 @@ function createMessagingRepository(options) {
1590
1576
  ...options.now !== void 0 ? { now: options.now } : {}
1591
1577
  });
1592
1578
  const db = () => client.schema(MESSAGING_SCHEMA);
1579
+ const rpcDb = () => client.schema(MESSAGING_RPC_SCHEMA);
1593
1580
  async function withSessionRetry(operation, run) {
1594
1581
  try {
1595
1582
  return await run();
@@ -1607,7 +1594,7 @@ function createMessagingRepository(options) {
1607
1594
  }
1608
1595
  }
1609
1596
  async function rpc(fn, args, operation) {
1610
- const { data, error } = await db().rpc(fn, args);
1597
+ const { data, error } = await rpcDb().rpc(fn, args);
1611
1598
  if (error !== null) throw normalizeMessagingError(error, operation);
1612
1599
  return data;
1613
1600
  }