@ai-matrx/messaging 0.7.0 → 0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # Changelog — `@ai-matrx/messaging`
2
2
 
3
+ ## 0.9.0 — 2026-09-07
4
+
5
+ **`<MessagingProvider client={supabase}>` did not typecheck for a host with generated Supabase
6
+ types** — the one line the README tells every consumer to write.
7
+
8
+ ### Fixed
9
+
10
+ - **The public `client` prop type is now shallow.** Checking a fully-typed
11
+ `SupabaseClient<Database>` against the rich internal shape makes tsc chase PostgREST's schema
12
+ machinery until it bails with `TS2589: Type instantiation is excessively deep and possibly
13
+ infinite`, followed by a page of "not assignable" — so the only way to pass the client a host
14
+ already has was the cast this package's own header forbids. The boundary is method names and
15
+ arity with `unknown` results; the rich contract (`MessagingSupabaseInternal`, formerly the
16
+ public type's body) is still what everything inside works against, and the provider narrows to
17
+ it ONCE, in-package. Same lesson as data 0.2.1: type a public boundary over `unknown`, never
18
+ over a strict recursive type the host's generator also produces.
19
+ - **`createMessagingRepository` takes the same shallow client**, so the framework-free path a
20
+ service module uses (the README's "Outside React" section) compiles for the same host that the
21
+ provider does. Both legs are proven at compile time.
22
+ - **`supabase-shape.test.ts` now proves the consumer's leg**: a `SupabaseClient<Database>` is
23
+ assignable to `MessagingSupabaseClient`. The old proof deliberately checked only the CALLS,
24
+ noting that whole-interface assignability "makes tsc bail with TS2589, which is a compiler
25
+ limit, not a contract failure" — true, and precisely why the consumer could not compile. The
26
+ limit was the contract failure.
27
+
28
+ ### Consumer action (C28)
29
+
30
+ None, and one less cast: pass your `SupabaseClient` straight in. A host that had written
31
+ `client={supabase as never}` can delete the cast. `MessagingSupabaseInternal` is exported for
32
+ anyone building the repository directly.
33
+
34
+ ## 0.8.0 — 2026-09-07
35
+
36
+ **Every conversation in the first real inbox was titled with a raw UUID.** The second live defect
37
+ of the adoption session, found by looking at the screen rather than at a test.
38
+
39
+ ### Fixed
40
+
41
+ - **The participant profile is NESTED under `user`, and the top-level `id` is the participant
42
+ ROW.** The live `get_dm_conversations_with_details` aggregate is
43
+ `{ id, user_id, role, is_muted, last_read_at, user: { user_id, email, display_name, avatar_url } }`.
44
+ This package read `display_name` / `email` / `avatar_url` off the TOP level, found nothing, and
45
+ fell back to the user id — so a direct conversation's title, its avatar, and every participant
46
+ name rendered as a UUID. The nested profile is now the source, `user_id` is the identity, and
47
+ the bare `id` fallback survives only for an aggregate that carries neither — because here `id`
48
+ belongs to a different entity, and using it as a user id attributes a message to a row key.
49
+ - A regression test built from the verbatim live aggregate; it fails against 0.7.0.
50
+
51
+ ### Consumer action (C28)
52
+
53
+ None. Names and avatars simply appear now.
54
+
3
55
  ## 0.7.0 — 2026-09-07
4
56
 
5
57
  🚨 **Every RPC in this package was calling the wrong schema, so every read failed against the
package/dist/index.cjs CHANGED
@@ -798,11 +798,13 @@ function projectParticipants(value, operation) {
798
798
  for (const entry of value) {
799
799
  if (typeof entry !== "object" || entry === null) continue;
800
800
  const record = entry;
801
- const id = str(record, "user_id") ?? str(record, "id");
801
+ const nested = typeof record["user"] === "object" && record["user"] !== null ? record["user"] : {};
802
+ const id = str(record, "user_id") ?? str(nested, "user_id") ?? str(record, "id");
802
803
  if (id === null) continue;
803
804
  summaries.push(
804
805
  projectUserSummary({
805
806
  ...record,
807
+ ...nested,
806
808
  user_id: id
807
809
  })
808
810
  );
@@ -1569,12 +1571,13 @@ function requireOrg(organizationId, operation) {
1569
1571
  return organizationId;
1570
1572
  }
1571
1573
  function createMessagingRepository(options) {
1572
- const { client, identity } = options;
1574
+ const { identity } = options;
1573
1575
  const org = requireOrg(identity.organizationId, "createMessagingRepository");
1574
1576
  const userCache = createReadCache({
1575
1577
  ttlMs: options.userTtlMs ?? 5 * 6e4,
1576
1578
  ...options.now !== void 0 ? { now: options.now } : {}
1577
1579
  });
1580
+ const client = options.client;
1578
1581
  const db = () => client.schema(MESSAGING_SCHEMA);
1579
1582
  const rpcDb = () => client.schema(MESSAGING_RPC_SCHEMA);
1580
1583
  async function withSessionRetry(operation, run) {