@ai-matrx/messaging 0.13.0 → 0.14.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 +47 -0
- package/README.md +5 -1
- package/dist/index.cjs +30 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -9
- package/dist/index.d.ts +28 -9
- package/dist/index.js +30 -14
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +43 -24
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +34 -10
- package/dist/react.d.ts +34 -10
- package/dist/react.js +43 -24
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -869,7 +869,7 @@ function projectMessage(row, fallbackOrganizationId) {
|
|
|
869
869
|
id: requiredStr(row, "id", operation),
|
|
870
870
|
conversationId: requiredStr(row, "conversation_id", operation),
|
|
871
871
|
senderId: requiredStr(row, "sender_id", operation),
|
|
872
|
-
organizationId: str(row, "organization_id") ?? fallbackOrganizationId,
|
|
872
|
+
organizationId: str(row, "organization_id") ?? fallbackOrganizationId ?? "",
|
|
873
873
|
content: typeof row["content"] === "string" ? row["content"] : "",
|
|
874
874
|
kind: MESSAGE_KINDS.has(kindRaw) ? kindRaw : "text",
|
|
875
875
|
// A row read from the DB is at least `sent`. `sending`/`failed` are outbox
|
|
@@ -917,7 +917,7 @@ function projectConversationSummary(row, viewerId, fallbackOrganizationId) {
|
|
|
917
917
|
groupName,
|
|
918
918
|
groupImageUrl,
|
|
919
919
|
createdBy: createdBy === null ? null : createdBy,
|
|
920
|
-
organizationId: str(row, "organization_id") ?? fallbackOrganizationId,
|
|
920
|
+
organizationId: str(row, "organization_id") ?? fallbackOrganizationId ?? "",
|
|
921
921
|
createdAt,
|
|
922
922
|
updatedAt,
|
|
923
923
|
metadata: jsonObject(row["metadata"])
|
|
@@ -1250,7 +1250,11 @@ function createMessagingEngine(options) {
|
|
|
1250
1250
|
optimisticMessage({
|
|
1251
1251
|
conversationId: entry.draft.conversationId,
|
|
1252
1252
|
senderId: identity.userId,
|
|
1253
|
-
|
|
1253
|
+
// Client-only until the confirmed row replaces it: the active
|
|
1254
|
+
// organization, else the conversation's own.
|
|
1255
|
+
organizationId: identity.organizationId ?? store.snapshot().conversations.find(
|
|
1256
|
+
(item) => item.conversation.id === entry.draft.conversationId
|
|
1257
|
+
)?.conversation.organizationId ?? "",
|
|
1254
1258
|
content: entry.draft.content,
|
|
1255
1259
|
clientMessageId: entry.clientMessageId,
|
|
1256
1260
|
...entry.draft.kind !== void 0 ? { kind: entry.draft.kind } : {},
|
|
@@ -1393,12 +1397,12 @@ function createMessagingEngine(options) {
|
|
|
1393
1397
|
},
|
|
1394
1398
|
async openConversation(id) {
|
|
1395
1399
|
store.setActiveConversation(id);
|
|
1396
|
-
store.setConversationReadFailure(id, null);
|
|
1397
1400
|
try {
|
|
1398
1401
|
const page = await repository.listMessages(id, { limit: messagePageSize });
|
|
1399
1402
|
if (page.items.length === 0) {
|
|
1400
1403
|
await repository.getConversation(id);
|
|
1401
1404
|
}
|
|
1405
|
+
store.setConversationReadFailure(id, null);
|
|
1402
1406
|
store.setThread(id, page.items, { hasMoreOlder: page.hasMore });
|
|
1403
1407
|
} catch (error) {
|
|
1404
1408
|
const normalized = normalizeMessagingError(error, "openConversation");
|
|
@@ -1739,12 +1743,15 @@ var RPCS = {
|
|
|
1739
1743
|
};
|
|
1740
1744
|
var MESSAGE_COLUMNS = "id,conversation_id,sender_id,organization_id,content,message_type,status,reply_to_id,client_message_id,action_data,media_url,media_thumbnail_url,media_metadata,created_at,edited_at,deleted_at,deleted_for_everyone,metadata";
|
|
1741
1745
|
var CONVERSATION_COLUMNS = "id,type,group_name,group_image_url,created_by,organization_id,created_at,updated_at,metadata";
|
|
1746
|
+
function optionalOrg(organizationId) {
|
|
1747
|
+
return typeof organizationId === "string" && organizationId.length > 0 ? organizationId : null;
|
|
1748
|
+
}
|
|
1742
1749
|
function requireOrg(organizationId, operation) {
|
|
1743
|
-
if (
|
|
1750
|
+
if (organizationId === null) {
|
|
1744
1751
|
throw new MessagingError(
|
|
1745
|
-
"
|
|
1746
|
-
`${operation}: no
|
|
1747
|
-
"
|
|
1752
|
+
"organization-required",
|
|
1753
|
+
`${operation}: no organization selected`,
|
|
1754
|
+
"A new conversation is filed under one organization. Ask the person to choose one, then pass it as organizationId on <MessagingProvider>. Reading and replying to existing conversations never needs it."
|
|
1748
1755
|
);
|
|
1749
1756
|
}
|
|
1750
1757
|
return organizationId;
|
|
@@ -1756,7 +1763,7 @@ function sleep(ms) {
|
|
|
1756
1763
|
return new Promise((resolve) => setTimeout(resolve, jittered));
|
|
1757
1764
|
}
|
|
1758
1765
|
function createMessagingRepository(options) {
|
|
1759
|
-
const org =
|
|
1766
|
+
const org = optionalOrg(options.organizationId);
|
|
1760
1767
|
const handedIn = options.identity;
|
|
1761
1768
|
if (handedIn !== void 0 && handedIn !== null && handedIn.userId !== void 0) {
|
|
1762
1769
|
options.onDiagnostic?.(
|
|
@@ -1826,6 +1833,11 @@ function createMessagingRepository(options) {
|
|
|
1826
1833
|
});
|
|
1827
1834
|
return found;
|
|
1828
1835
|
}
|
|
1836
|
+
async function organizationOfExisting(conversationId) {
|
|
1837
|
+
if (org !== null) return org;
|
|
1838
|
+
const conversation = await repository.getConversation(conversationId);
|
|
1839
|
+
return conversation.organizationId;
|
|
1840
|
+
}
|
|
1829
1841
|
const repository = {
|
|
1830
1842
|
organizationId: org,
|
|
1831
1843
|
actingUserId,
|
|
@@ -1958,6 +1970,7 @@ function createMessagingRepository(options) {
|
|
|
1958
1970
|
},
|
|
1959
1971
|
async getOrCreateDirectConversation(otherUserId) {
|
|
1960
1972
|
const operation = "getOrCreateDirectConversation";
|
|
1973
|
+
const destination = requireOrg(org, operation);
|
|
1961
1974
|
const me = await actingUser(operation);
|
|
1962
1975
|
const id = await withSessionRetry(
|
|
1963
1976
|
operation,
|
|
@@ -1969,7 +1982,7 @@ function createMessagingRepository(options) {
|
|
|
1969
1982
|
// not a preference.
|
|
1970
1983
|
p_user1_id: me,
|
|
1971
1984
|
p_user2_id: otherUserId,
|
|
1972
|
-
p_organization_id:
|
|
1985
|
+
p_organization_id: destination
|
|
1973
1986
|
},
|
|
1974
1987
|
operation
|
|
1975
1988
|
)
|
|
@@ -1981,13 +1994,14 @@ function createMessagingRepository(options) {
|
|
|
1981
1994
|
},
|
|
1982
1995
|
async createGroupConversation({ name, memberIds }) {
|
|
1983
1996
|
const operation = "createGroupConversation";
|
|
1997
|
+
const destination = requireOrg(org, operation);
|
|
1984
1998
|
const me = await actingUser(operation);
|
|
1985
1999
|
const { data, error } = await withSessionRetry(
|
|
1986
2000
|
operation,
|
|
1987
2001
|
async () => db().from(TABLES.conversations).insert({
|
|
1988
2002
|
type: "group",
|
|
1989
2003
|
group_name: name,
|
|
1990
|
-
organization_id:
|
|
2004
|
+
organization_id: destination,
|
|
1991
2005
|
created_by: me
|
|
1992
2006
|
}).select("id").single()
|
|
1993
2007
|
);
|
|
@@ -2002,7 +2016,7 @@ function createMessagingRepository(options) {
|
|
|
2002
2016
|
conversation_id: conversationId,
|
|
2003
2017
|
user_id: userId,
|
|
2004
2018
|
role: userId === me ? "owner" : "member",
|
|
2005
|
-
organization_id:
|
|
2019
|
+
organization_id: destination,
|
|
2006
2020
|
created_by: me
|
|
2007
2021
|
}))
|
|
2008
2022
|
);
|
|
@@ -2012,10 +2026,11 @@ function createMessagingRepository(options) {
|
|
|
2012
2026
|
async insertMessage(draft, clientMessageId) {
|
|
2013
2027
|
const operation = "insertMessage";
|
|
2014
2028
|
const me = await actingUser(operation);
|
|
2029
|
+
const destination = await organizationOfExisting(draft.conversationId);
|
|
2015
2030
|
const { data, error } = await db().from(TABLES.messages).insert({
|
|
2016
2031
|
conversation_id: draft.conversationId,
|
|
2017
2032
|
sender_id: me,
|
|
2018
|
-
organization_id:
|
|
2033
|
+
organization_id: destination,
|
|
2019
2034
|
created_by: me,
|
|
2020
2035
|
content: draft.content,
|
|
2021
2036
|
message_type: draft.kind ?? "text",
|
|
@@ -2076,12 +2091,13 @@ function createMessagingRepository(options) {
|
|
|
2076
2091
|
async addMembers(conversationId, memberIds) {
|
|
2077
2092
|
const operation = "addMembers";
|
|
2078
2093
|
const me = await actingUser(operation);
|
|
2094
|
+
const destination = await organizationOfExisting(conversationId);
|
|
2079
2095
|
const { error } = await db().from(TABLES.participants).insert(
|
|
2080
2096
|
memberIds.map((userId) => ({
|
|
2081
2097
|
conversation_id: conversationId,
|
|
2082
2098
|
user_id: userId,
|
|
2083
2099
|
role: "member",
|
|
2084
|
-
organization_id:
|
|
2100
|
+
organization_id: destination,
|
|
2085
2101
|
created_by: me
|
|
2086
2102
|
}))
|
|
2087
2103
|
);
|
|
@@ -2192,7 +2208,7 @@ function MessagingProvider(props) {
|
|
|
2192
2208
|
}, [strayUserId]);
|
|
2193
2209
|
const session = useSessionUserId(client, props.onDiagnostic);
|
|
2194
2210
|
const userId = session.snapshot.userId;
|
|
2195
|
-
const ready = client != null && userId !== null
|
|
2211
|
+
const ready = client != null && userId !== null;
|
|
2196
2212
|
const hostProvidesRealtime = (0, import_react2.useIsRealtimeProviderMounted)();
|
|
2197
2213
|
const runtime = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2198
2214
|
MessagingRuntime,
|
|
@@ -2228,12 +2244,13 @@ function MessagingRuntime(props) {
|
|
|
2228
2244
|
actionRegistry.register(handler);
|
|
2229
2245
|
});
|
|
2230
2246
|
}, [actionRegistry, handlers]);
|
|
2231
|
-
const ready = client != null && manager !== null && sessionIdentity !== null && userId !== null
|
|
2247
|
+
const ready = client != null && manager !== null && sessionIdentity !== null && userId !== null;
|
|
2248
|
+
const activeOrganizationId = typeof organizationId === "string" && organizationId.length > 0 ? organizationId : null;
|
|
2232
2249
|
const engine = (0, import_react.useMemo)(() => {
|
|
2233
2250
|
if (!ready || manager === null || sessionIdentity === null || userId === null) return null;
|
|
2234
2251
|
const identity = {
|
|
2235
2252
|
userId,
|
|
2236
|
-
organizationId
|
|
2253
|
+
organizationId: activeOrganizationId
|
|
2237
2254
|
};
|
|
2238
2255
|
const report = (event) => {
|
|
2239
2256
|
(diagnosticRef.current ?? defaultDiagnostics)(event);
|
|
@@ -2244,7 +2261,7 @@ function MessagingRuntime(props) {
|
|
|
2244
2261
|
// supabase-shape.ts); everything below this line works against the rich
|
|
2245
2262
|
// contract, which `supabase-shape.test.ts` proves a real client honors.
|
|
2246
2263
|
client,
|
|
2247
|
-
organizationId,
|
|
2264
|
+
organizationId: activeOrganizationId,
|
|
2248
2265
|
// THE SAME READER the render loop above uses. Two readers would be two
|
|
2249
2266
|
// answers during the tick an account switch takes.
|
|
2250
2267
|
sessionIdentity,
|
|
@@ -2277,14 +2294,14 @@ function MessagingRuntime(props) {
|
|
|
2277
2294
|
}
|
|
2278
2295
|
});
|
|
2279
2296
|
return built;
|
|
2280
|
-
}, [ready, manager, sessionIdentity, userId,
|
|
2297
|
+
}, [ready, manager, sessionIdentity, userId, activeOrganizationId]);
|
|
2281
2298
|
(0, import_react.useEffect)(() => {
|
|
2282
2299
|
if (engine === null) return void 0;
|
|
2283
2300
|
void engine.start().catch((error) => {
|
|
2284
2301
|
(diagnosticRef.current ?? defaultDiagnostics)({
|
|
2285
2302
|
level: "error",
|
|
2286
2303
|
message: `Messaging failed to start: ${String(error?.message ?? error)}`,
|
|
2287
|
-
remedy: "Check the signed-in session
|
|
2304
|
+
remedy: "Check the signed-in session, then reload the surface."
|
|
2288
2305
|
});
|
|
2289
2306
|
});
|
|
2290
2307
|
return () => {
|
|
@@ -2298,9 +2315,10 @@ function MessagingRuntime(props) {
|
|
|
2298
2315
|
const sourceFeature = props.sourceFeature;
|
|
2299
2316
|
const ai = (0, import_react.useMemo)(() => {
|
|
2300
2317
|
if (transport === void 0 || agents === void 0 || !ready) return null;
|
|
2318
|
+
if (activeOrganizationId === null) return null;
|
|
2301
2319
|
return createMessagingAi({
|
|
2302
2320
|
transport,
|
|
2303
|
-
organizationId,
|
|
2321
|
+
organizationId: activeOrganizationId,
|
|
2304
2322
|
agents,
|
|
2305
2323
|
...maxTranscriptMessages !== void 0 ? { maxTranscriptMessages } : {},
|
|
2306
2324
|
...sourceApp !== void 0 ? { sourceApp } : {},
|
|
@@ -2310,7 +2328,7 @@ function MessagingRuntime(props) {
|
|
|
2310
2328
|
transport,
|
|
2311
2329
|
agents,
|
|
2312
2330
|
ready,
|
|
2313
|
-
|
|
2331
|
+
activeOrganizationId,
|
|
2314
2332
|
maxTranscriptMessages,
|
|
2315
2333
|
sourceApp,
|
|
2316
2334
|
sourceFeature
|
|
@@ -2361,7 +2379,7 @@ function useRequiredMessagingHost() {
|
|
|
2361
2379
|
const host = useMessagingHost();
|
|
2362
2380
|
if (host === null) {
|
|
2363
2381
|
throw new Error(
|
|
2364
|
-
"[@ai-matrx/messaging] No messaging host. Wrap this tree in <MessagingProvider client={supabase}
|
|
2382
|
+
"[@ai-matrx/messaging] No messaging host. Wrap this tree in <MessagingProvider client={supabase} organizationId={orgId}> and render it only once auth has resolved."
|
|
2365
2383
|
);
|
|
2366
2384
|
}
|
|
2367
2385
|
return host;
|
|
@@ -2751,7 +2769,8 @@ function useMessageAction(message) {
|
|
|
2751
2769
|
const context = {
|
|
2752
2770
|
messageId: message.id,
|
|
2753
2771
|
actorId: host.identity.userId,
|
|
2754
|
-
|
|
2772
|
+
// The active organization, else the organization the message lives in.
|
|
2773
|
+
organizationId: host.identity.organizationId ?? message.organizationId,
|
|
2755
2774
|
choice
|
|
2756
2775
|
};
|
|
2757
2776
|
host.actions.execute(action, context).then(setReceipt).catch((cause) => {
|