@ttt-productions/chat-react 0.13.6 → 0.13.8
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/dist/context/ChatNameResolverContext.d.ts +24 -16
- package/dist/context/ChatNameResolverContext.d.ts.map +1 -1
- package/dist/context/ChatNameResolverContext.js +15 -19
- package/dist/context/ChatNameResolverContext.js.map +1 -1
- package/dist/hooks/useChatMessages.d.ts +9 -0
- package/dist/hooks/useChatMessages.d.ts.map +1 -1
- package/dist/hooks/useChatMessages.js +10 -10
- package/dist/hooks/useChatMessages.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/realtime/channel-client.d.ts +32 -0
- package/dist/realtime/channel-client.d.ts.map +1 -1
- package/dist/realtime/channel-client.js +114 -15
- package/dist/realtime/channel-client.js.map +1 -1
- package/dist/realtime/inbox-client.d.ts +50 -6
- package/dist/realtime/inbox-client.d.ts.map +1 -1
- package/dist/realtime/inbox-client.js +133 -18
- package/dist/realtime/inbox-client.js.map +1 -1
- package/dist/realtime/index.d.ts +3 -3
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/index.js +1 -1
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime/initial-load-budget.d.ts +31 -0
- package/dist/realtime/initial-load-budget.d.ts.map +1 -0
- package/dist/realtime/initial-load-budget.js +69 -0
- package/dist/realtime/initial-load-budget.js.map +1 -0
- package/dist/realtime/map.d.ts.map +1 -1
- package/dist/realtime/map.js +3 -2
- package/dist/realtime/map.js.map +1 -1
- package/dist/realtime/shared.d.ts +13 -0
- package/dist/realtime/shared.d.ts.map +1 -1
- package/dist/realtime/shared.js +18 -0
- package/dist/realtime/shared.js.map +1 -1
- package/dist/realtime/transport.d.ts +6 -3
- package/dist/realtime/transport.d.ts.map +1 -1
- package/dist/realtime/transport.js +1 -0
- package/dist/realtime/transport.js.map +1 -1
- package/dist/realtime/useRealtimeChatMessages.d.ts +4 -0
- package/dist/realtime/useRealtimeChatMessages.d.ts.map +1 -1
- package/dist/realtime/useRealtimeChatMessages.js +7 -8
- package/dist/realtime/useRealtimeChatMessages.js.map +1 -1
- package/dist/realtime/wire.d.ts +11 -6
- package/dist/realtime/wire.d.ts.map +1 -1
- package/dist/realtime/wire.js +2 -2
- package/dist/realtime/wire.js.map +1 -1
- package/dist/types.d.ts +16 -19
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/ui/ChatShell.d.ts +27 -1
- package/dist/ui/ChatShell.d.ts.map +1 -1
- package/dist/ui/ChatShell.js +27 -7
- package/dist/ui/ChatShell.js.map +1 -1
- package/dist/ui/Composer.d.ts.map +1 -1
- package/dist/ui/Composer.js +4 -2
- package/dist/ui/Composer.js.map +1 -1
- package/dist/ui/MessageItemDefault.d.ts +1 -1
- package/dist/ui/MessageItemDefault.d.ts.map +1 -1
- package/dist/ui/MessageItemDefault.js +10 -6
- package/dist/ui/MessageItemDefault.js.map +1 -1
- package/dist/ui/MessageList.d.ts +7 -1
- package/dist/ui/MessageList.d.ts.map +1 -1
- package/dist/ui/MessageList.js +6 -5
- package/dist/ui/MessageList.js.map +1 -1
- package/dist/ui/SenderName.d.ts +9 -0
- package/dist/ui/SenderName.d.ts.map +1 -0
- package/dist/ui/SenderName.js +16 -0
- package/dist/ui/SenderName.js.map +1 -0
- package/package.json +12 -12
- package/dist/hooks/useChatThreadAccess.d.ts +0 -8
- package/dist/hooks/useChatThreadAccess.d.ts.map +0 -1
- package/dist/hooks/useChatThreadAccess.js +0 -19
- package/dist/hooks/useChatThreadAccess.js.map +0 -1
|
@@ -1,37 +1,45 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import type { ChatNameResolver, ChatPrewarmSenders } from "@ttt-productions/chat-core";
|
|
2
|
+
import type { ChatNameResolution, ChatNameResolver, ChatPrewarmSenders } from "@ttt-productions/chat-core";
|
|
3
|
+
/** A sender name the app could not resolve: pending, unavailable, or failed. */
|
|
4
|
+
export type UnresolvedChatName = Exclude<ChatNameResolution, {
|
|
5
|
+
status: "resolved";
|
|
6
|
+
}>;
|
|
3
7
|
type ChatNameResolverContextValue = {
|
|
4
8
|
resolveName: ChatNameResolver;
|
|
5
9
|
prewarm?: ChatPrewarmSenders;
|
|
10
|
+
renderUnresolvedName?: (resolution: UnresolvedChatName) => React.ReactNode;
|
|
6
11
|
};
|
|
7
12
|
export type ChatNameResolverProviderProps = {
|
|
8
13
|
resolveName: ChatNameResolver;
|
|
9
14
|
prewarm?: ChatPrewarmSenders;
|
|
15
|
+
/**
|
|
16
|
+
* Renders a sender whose name is not resolved — the app's own placeholder while the
|
|
17
|
+
* read is pending, its unavailable state when there is no person to name, and its
|
|
18
|
+
* load-error state (with `retry`) when the read failed. The chat UI never writes a
|
|
19
|
+
* stand-in name of its own; without this slot an unresolved sender renders nothing.
|
|
20
|
+
*/
|
|
21
|
+
renderUnresolvedName?: (resolution: UnresolvedChatName) => React.ReactNode;
|
|
10
22
|
children: React.ReactNode;
|
|
11
23
|
};
|
|
12
24
|
/**
|
|
13
|
-
* Wraps any chat-
|
|
14
|
-
*
|
|
15
|
-
*
|
|
25
|
+
* Wraps any chat-react consumer (typically the whole app shell) and provides the name
|
|
26
|
+
* resolver. Required for any tree that renders <ChatShell>, <MessageList>, or
|
|
27
|
+
* <MessageItemDefault>.
|
|
16
28
|
*/
|
|
17
29
|
export declare function ChatNameResolverProvider(props: ChatNameResolverProviderProps): React.JSX.Element;
|
|
18
30
|
/**
|
|
19
|
-
* Strict hook — throws if no provider is wrapped. Used inside this package's
|
|
20
|
-
*
|
|
21
|
-
*
|
|
31
|
+
* Strict hook — throws if no provider is wrapped. Used inside this package's own
|
|
32
|
+
* renderers so a missing setup surfaces on first render instead of rendering a sender
|
|
33
|
+
* with no name.
|
|
22
34
|
*/
|
|
23
35
|
export declare function useChatNameResolver(): ChatNameResolverContextValue;
|
|
24
36
|
/**
|
|
25
|
-
* Optional variant — returns null instead of throwing when no provider is
|
|
26
|
-
*
|
|
27
|
-
*
|
|
37
|
+
* Optional variant — returns null instead of throwing when no provider is wrapped.
|
|
38
|
+
* Used internally by the message hooks so headless callers (tests, data-only consumers
|
|
39
|
+
* that render no UI) can still use them.
|
|
28
40
|
*/
|
|
29
41
|
export declare function useOptionalChatNameResolver(): ChatNameResolverContextValue | null;
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
* by falling back to "User" when the cache hasn't filled yet. Re-renders
|
|
33
|
-
* automatically once the upstream cache settles.
|
|
34
|
-
*/
|
|
35
|
-
export declare function useResolvedSenderName(senderId: string): string;
|
|
42
|
+
/** What the app knows about a sender's name right now. Re-renders as the app's cache settles. */
|
|
43
|
+
export declare function useSenderNameResolution(senderId: string): ChatNameResolution;
|
|
36
44
|
export {};
|
|
37
45
|
//# sourceMappingURL=ChatNameResolverContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatNameResolverContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatNameResolverContext.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ChatNameResolverContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatNameResolverContext.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAEpC,gFAAgF;AAChF,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,EAAE;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC;AAErF,KAAK,4BAA4B,GAAG;IAClC,WAAW,EAAE,gBAAgB,CAAC;IAC9B,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,KAAK,KAAK,CAAC,SAAS,CAAC;CAC5E,CAAC;AAIF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,WAAW,EAAE,gBAAgB,CAAC;IAC9B,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,KAAK,KAAK,CAAC,SAAS,CAAC;IAC3E,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,6BAA6B,qBAW5E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,4BAA4B,CAQlE;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,4BAA4B,GAAG,IAAI,CAEjF;AAED,iGAAiG;AACjG,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAG5E"}
|
|
@@ -3,42 +3,38 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
const ChatNameResolverContext = React.createContext(null);
|
|
5
5
|
/**
|
|
6
|
-
* Wraps any chat-
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Wraps any chat-react consumer (typically the whole app shell) and provides the name
|
|
7
|
+
* resolver. Required for any tree that renders <ChatShell>, <MessageList>, or
|
|
8
|
+
* <MessageItemDefault>.
|
|
9
9
|
*/
|
|
10
10
|
export function ChatNameResolverProvider(props) {
|
|
11
|
-
const { resolveName, prewarm, children } = props;
|
|
12
|
-
const value = React.useMemo(() => ({ resolveName, prewarm }), [resolveName, prewarm]);
|
|
11
|
+
const { resolveName, prewarm, renderUnresolvedName, children } = props;
|
|
12
|
+
const value = React.useMemo(() => ({ resolveName, prewarm, renderUnresolvedName }), [resolveName, prewarm, renderUnresolvedName]);
|
|
13
13
|
return (_jsx(ChatNameResolverContext.Provider, { value: value, children: children }));
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Strict hook — throws if no provider is wrapped. Used inside this package's
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Strict hook — throws if no provider is wrapped. Used inside this package's own
|
|
17
|
+
* renderers so a missing setup surfaces on first render instead of rendering a sender
|
|
18
|
+
* with no name.
|
|
19
19
|
*/
|
|
20
20
|
export function useChatNameResolver() {
|
|
21
21
|
const ctx = React.useContext(ChatNameResolverContext);
|
|
22
22
|
if (!ctx) {
|
|
23
|
-
throw new Error("[chat-
|
|
23
|
+
throw new Error("[chat-react] ChatNameResolverProvider is required. Wrap your ChatShell tree with <ChatNameResolverProvider>.");
|
|
24
24
|
}
|
|
25
25
|
return ctx;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Optional variant — returns null instead of throwing when no provider is
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* Optional variant — returns null instead of throwing when no provider is wrapped.
|
|
29
|
+
* Used internally by the message hooks so headless callers (tests, data-only consumers
|
|
30
|
+
* that render no UI) can still use them.
|
|
31
31
|
*/
|
|
32
32
|
export function useOptionalChatNameResolver() {
|
|
33
33
|
return React.useContext(ChatNameResolverContext);
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
36
|
-
|
|
37
|
-
* by falling back to "User" when the cache hasn't filled yet. Re-renders
|
|
38
|
-
* automatically once the upstream cache settles.
|
|
39
|
-
*/
|
|
40
|
-
export function useResolvedSenderName(senderId) {
|
|
35
|
+
/** What the app knows about a sender's name right now. Re-renders as the app's cache settles. */
|
|
36
|
+
export function useSenderNameResolution(senderId) {
|
|
41
37
|
const { resolveName } = useChatNameResolver();
|
|
42
|
-
return resolveName(senderId)
|
|
38
|
+
return resolveName(senderId);
|
|
43
39
|
}
|
|
44
40
|
//# sourceMappingURL=ChatNameResolverContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatNameResolverContext.js","sourceRoot":"","sources":["../../src/context/ChatNameResolverContext.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ChatNameResolverContext.js","sourceRoot":"","sources":["../../src/context/ChatNameResolverContext.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAgB/B,MAAM,uBAAuB,GAAG,KAAK,CAAC,aAAa,CAAsC,IAAI,CAAC,CAAC;AAe/F;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAoC;IAC3E,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACvE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CACzB,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC,EACtD,CAAC,WAAW,EAAE,OAAO,EAAE,oBAAoB,CAAC,CAC7C,CAAC;IACF,OAAO,CACL,KAAC,uBAAuB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAC3C,QAAQ,GACwB,CACpC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC;IACtD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,8GAA8G,CAC/G,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,KAAK,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC;AACnD,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,MAAM,EAAE,WAAW,EAAE,GAAG,mBAAmB,EAAE,CAAC;IAC9C,OAAO,WAAW,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport type {\n ChatNameResolution,\n ChatNameResolver,\n ChatPrewarmSenders,\n} from \"@ttt-productions/chat-core\";\n\n/** A sender name the app could not resolve: pending, unavailable, or failed. */\nexport type UnresolvedChatName = Exclude<ChatNameResolution, { status: \"resolved\" }>;\n\ntype ChatNameResolverContextValue = {\n resolveName: ChatNameResolver;\n prewarm?: ChatPrewarmSenders;\n renderUnresolvedName?: (resolution: UnresolvedChatName) => React.ReactNode;\n};\n\nconst ChatNameResolverContext = React.createContext<ChatNameResolverContextValue | null>(null);\n\nexport type ChatNameResolverProviderProps = {\n resolveName: ChatNameResolver;\n prewarm?: ChatPrewarmSenders;\n /**\n * Renders a sender whose name is not resolved — the app's own placeholder while the\n * read is pending, its unavailable state when there is no person to name, and its\n * load-error state (with `retry`) when the read failed. The chat UI never writes a\n * stand-in name of its own; without this slot an unresolved sender renders nothing.\n */\n renderUnresolvedName?: (resolution: UnresolvedChatName) => React.ReactNode;\n children: React.ReactNode;\n};\n\n/**\n * Wraps any chat-react consumer (typically the whole app shell) and provides the name\n * resolver. Required for any tree that renders <ChatShell>, <MessageList>, or\n * <MessageItemDefault>.\n */\nexport function ChatNameResolverProvider(props: ChatNameResolverProviderProps) {\n const { resolveName, prewarm, renderUnresolvedName, children } = props;\n const value = React.useMemo(\n () => ({ resolveName, prewarm, renderUnresolvedName }),\n [resolveName, prewarm, renderUnresolvedName],\n );\n return (\n <ChatNameResolverContext.Provider value={value}>\n {children}\n </ChatNameResolverContext.Provider>\n );\n}\n\n/**\n * Strict hook — throws if no provider is wrapped. Used inside this package's own\n * renderers so a missing setup surfaces on first render instead of rendering a sender\n * with no name.\n */\nexport function useChatNameResolver(): ChatNameResolverContextValue {\n const ctx = React.useContext(ChatNameResolverContext);\n if (!ctx) {\n throw new Error(\n \"[chat-react] ChatNameResolverProvider is required. Wrap your ChatShell tree with <ChatNameResolverProvider>.\"\n );\n }\n return ctx;\n}\n\n/**\n * Optional variant — returns null instead of throwing when no provider is wrapped.\n * Used internally by the message hooks so headless callers (tests, data-only consumers\n * that render no UI) can still use them.\n */\nexport function useOptionalChatNameResolver(): ChatNameResolverContextValue | null {\n return React.useContext(ChatNameResolverContext);\n}\n\n/** What the app knows about a sender's name right now. Re-renders as the app's cache settles. */\nexport function useSenderNameResolution(senderId: string): ChatNameResolution {\n const { resolveName } = useChatNameResolver();\n return resolveName(senderId);\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FirestoreSourceState } from "@ttt-productions/query-core";
|
|
1
2
|
import type { ChatMessageV1 } from "@ttt-productions/chat-core";
|
|
2
3
|
import type { ChatCoreConfig } from "../types.js";
|
|
3
4
|
export type UseChatMessagesResult = {
|
|
@@ -7,6 +8,14 @@ export type UseChatMessagesResult = {
|
|
|
7
8
|
fetchOlder: () => Promise<void>;
|
|
8
9
|
hasOlder: boolean;
|
|
9
10
|
isFetchingOlder: boolean;
|
|
11
|
+
/** The live listener's state: `connecting` while it (re)subscribes, `error` once it failed. */
|
|
12
|
+
sourceState: FirestoreSourceState;
|
|
13
|
+
/** The live listener's failure; the messages already shown stay in `messages`. */
|
|
14
|
+
error: Error | null;
|
|
15
|
+
/** The last older-page read failed; the list stops asking for older pages until `retry`. */
|
|
16
|
+
olderError: Error | null;
|
|
17
|
+
/** Re-run what failed: resubscribe a failed listener, re-read a failed older page. */
|
|
18
|
+
retry: () => void;
|
|
10
19
|
};
|
|
11
20
|
export declare function useChatMessages(config: ChatCoreConfig): UseChatMessagesResult;
|
|
12
21
|
//# sourceMappingURL=useChatMessages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatMessages.d.ts","sourceRoot":"","sources":["../../src/hooks/useChatMessages.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"useChatMessages.d.ts","sourceRoot":"","sources":["../../src/hooks/useChatMessages.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAOlD,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,+FAA+F;IAC/F,WAAW,EAAE,oBAAoB,CAAC;IAClC,kFAAkF;IAClF,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,4FAA4F;IAC5F,UAAU,EAAE,KAAK,GAAG,IAAI,CAAC;IACzB,sFAAsF;IACtF,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAiCF,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,qBAAqB,CA8E7E"}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { toMillis } from "@ttt-productions/firebase-helpers";
|
|
4
4
|
import { useFirestoreLiveInfinite } from "@ttt-productions/query-core/react";
|
|
5
|
-
import { canAccessThread } from "./useChatThreadAccess.js";
|
|
6
5
|
import { messagesColPath } from "../firestore/queries.js";
|
|
7
6
|
import { useOptionalChatNameResolver } from "../context/ChatNameResolverContext.js";
|
|
8
7
|
// Safety limit to prevent memory exhaustion
|
|
@@ -24,6 +23,7 @@ function mapMsg(data, threadId) {
|
|
|
24
23
|
text: d.text ?? "",
|
|
25
24
|
type: d.type,
|
|
26
25
|
isSystemMessage: d.isSystemMessage ?? undefined,
|
|
26
|
+
referencedUids: Array.isArray(d.referencedUids) ? d.referencedUids : undefined,
|
|
27
27
|
// Moderation tombstone flag (backend-written) — carried through so renderers
|
|
28
28
|
// can tombstone the content.
|
|
29
29
|
hidden: d.hidden ?? undefined,
|
|
@@ -31,24 +31,18 @@ function mapMsg(data, threadId) {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
export function useChatMessages(config) {
|
|
34
|
-
const { chatCollectionPath, messagesSubcollection = "messages", threadId, pageSize: requestedPageSize = 20, currentUserId,
|
|
34
|
+
const { chatCollectionPath, messagesSubcollection = "messages", threadId, pageSize: requestedPageSize = 20, currentUserId, allowed, createdAtField = "createdAt", } = config;
|
|
35
35
|
const pageSize = Math.min(requestedPageSize, MAX_PAGE_SIZE);
|
|
36
36
|
if (requestedPageSize > MAX_PAGE_SIZE) {
|
|
37
37
|
console.warn(`[useChatMessages] Requested pageSize ${requestedPageSize} exceeds maximum ${MAX_PAGE_SIZE}. Using ${MAX_PAGE_SIZE}.`);
|
|
38
38
|
}
|
|
39
|
-
const allowed = React.useMemo(() => canAccessThread({
|
|
40
|
-
accessMode,
|
|
41
|
-
isAdmin,
|
|
42
|
-
currentUserId,
|
|
43
|
-
allowedUserIds: threadAllowedUserIds,
|
|
44
|
-
}), [accessMode, isAdmin, currentUserId, threadAllowedUserIds]);
|
|
45
39
|
// Stable key segment for the message collection path (string | string[]).
|
|
46
40
|
const pathKey = React.useMemo(() => JSON.stringify(Array.isArray(chatCollectionPath) ? chatCollectionPath : [chatCollectionPath]), [chatCollectionPath]);
|
|
47
41
|
// Slash-joined collection path for the generic hook (handles nested paths).
|
|
48
42
|
const collectionPath = React.useMemo(() => messagesColPath(chatCollectionPath, threadId, messagesSubcollection).join("/"), [chatCollectionPath, threadId, messagesSubcollection]);
|
|
49
|
-
const { items, isInitialLoading, fetchOlder, hasOlder, isFetchingOlder } = useFirestoreLiveInfinite({
|
|
43
|
+
const { items, isInitialLoading, fetchOlder, hasOlder, isFetchingOlder, sourceState, error, olderError, retry } = useFirestoreLiveInfinite({
|
|
50
44
|
collectionPath,
|
|
51
|
-
queryKey: ["chat-core", "messages", pathKey, threadId, messagesSubcollection, pageSize],
|
|
45
|
+
queryKey: ["chat-core", "messages", pathKey, threadId, messagesSubcollection, pageSize, currentUserId],
|
|
52
46
|
orderByField: createdAtField,
|
|
53
47
|
pageSize,
|
|
54
48
|
enabled: allowed,
|
|
@@ -64,6 +58,8 @@ export function useChatMessages(config) {
|
|
|
64
58
|
const set = new Set();
|
|
65
59
|
for (const m of messages) {
|
|
66
60
|
set.add(m.senderId);
|
|
61
|
+
for (const uid of m.referencedUids ?? [])
|
|
62
|
+
set.add(uid);
|
|
67
63
|
}
|
|
68
64
|
return Array.from(set);
|
|
69
65
|
}, [messages]);
|
|
@@ -79,6 +75,10 @@ export function useChatMessages(config) {
|
|
|
79
75
|
fetchOlder,
|
|
80
76
|
hasOlder,
|
|
81
77
|
isFetchingOlder,
|
|
78
|
+
sourceState,
|
|
79
|
+
error: allowed ? error : null,
|
|
80
|
+
olderError: allowed ? olderError : null,
|
|
81
|
+
retry,
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
84
|
//# sourceMappingURL=useChatMessages.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatMessages.js","sourceRoot":"","sources":["../../src/hooks/useChatMessages.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"useChatMessages.js","sourceRoot":"","sources":["../../src/hooks/useChatMessages.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport type { DocumentData } from \"firebase/firestore\";\nimport { toMillis } from \"@ttt-productions/firebase-helpers\";\nimport { useFirestoreLiveInfinite } from \"@ttt-productions/query-core/react\";\nimport type { FirestoreSourceState } from \"@ttt-productions/query-core\";\nimport type { ChatMessageV1 } from \"@ttt-productions/chat-core\";\nimport type { ChatCoreConfig } from \"../types.js\";\nimport { messagesColPath } from \"../firestore/queries.js\";\nimport { useOptionalChatNameResolver } from \"../context/ChatNameResolverContext.js\";\n\n// Safety limit to prevent memory exhaustion\nconst MAX_PAGE_SIZE = 100;\n\nexport type UseChatMessagesResult = {\n allowed: boolean;\n isInitialLoading: boolean;\n messages: ChatMessageV1[];\n fetchOlder: () => Promise<void>;\n hasOlder: boolean;\n isFetchingOlder: boolean;\n /** The live listener's state: `connecting` while it (re)subscribes, `error` once it failed. */\n sourceState: FirestoreSourceState;\n /** The live listener's failure; the messages already shown stay in `messages`. */\n error: Error | null;\n /** The last older-page read failed; the list stops asking for older pages until `retry`. */\n olderError: Error | null;\n /** Re-run what failed: resubscribe a failed listener, re-read a failed older page. */\n retry: () => void;\n};\n\nfunction mapMsg(\n data: DocumentData & { id: string },\n threadId: string\n): ChatMessageV1 {\n const d = data as any;\n\n const createdAt = toMillis(d.createdAt);\n\n if (!createdAt) {\n console.error('[useChatMessages] Message missing valid createdAt:', data.id, d.createdAt);\n }\n\n // A stored `replyTo` (if any legacy doc still carries one) is deliberately NOT\n // mapped: chat has no reply-authoring affordance, so the UI has no reply\n // renderer to feed (DJ ruling 2026-07-29).\n return {\n messageId: data.id,\n threadId,\n createdAt: createdAt || 0,\n senderId: d.senderId,\n text: d.text ?? \"\",\n type: d.type,\n isSystemMessage: d.isSystemMessage ?? undefined,\n referencedUids: Array.isArray(d.referencedUids) ? d.referencedUids : undefined,\n // Moderation tombstone flag (backend-written) — carried through so renderers\n // can tombstone the content.\n hidden: d.hidden ?? undefined,\n meta: d.meta,\n };\n}\n\nexport function useChatMessages(config: ChatCoreConfig): UseChatMessagesResult {\n const {\n chatCollectionPath,\n messagesSubcollection = \"messages\",\n threadId,\n pageSize: requestedPageSize = 20,\n currentUserId,\n allowed,\n createdAtField = \"createdAt\",\n } = config;\n\n const pageSize = Math.min(requestedPageSize, MAX_PAGE_SIZE);\n\n if (requestedPageSize > MAX_PAGE_SIZE) {\n console.warn(\n `[useChatMessages] Requested pageSize ${requestedPageSize} exceeds maximum ${MAX_PAGE_SIZE}. Using ${MAX_PAGE_SIZE}.`\n );\n }\n\n // Stable key segment for the message collection path (string | string[]).\n const pathKey = React.useMemo(\n () =>\n JSON.stringify(\n Array.isArray(chatCollectionPath) ? chatCollectionPath : [chatCollectionPath]\n ),\n [chatCollectionPath]\n );\n\n // Slash-joined collection path for the generic hook (handles nested paths).\n const collectionPath = React.useMemo(\n () => messagesColPath(chatCollectionPath, threadId, messagesSubcollection).join(\"/\"),\n [chatCollectionPath, threadId, messagesSubcollection]\n );\n\n const { items, isInitialLoading, fetchOlder, hasOlder, isFetchingOlder, sourceState, error, olderError, retry } =\n useFirestoreLiveInfinite<ChatMessageV1>({\n collectionPath,\n queryKey: [\"chat-core\", \"messages\", pathKey, threadId, messagesSubcollection, pageSize, currentUserId],\n orderByField: createdAtField,\n pageSize,\n enabled: allowed,\n sort: \"asc\",\n select: (data) => mapMsg(data, threadId),\n getSortValue: (data) => toMillis(data.createdAt) ?? 0,\n });\n\n const messages = React.useMemo(() => (allowed ? items : []), [allowed, items]);\n\n // Pre-warm name cache for all visible senders.\n // Optional resolver: silent no-op if no provider is wrapped.\n const resolverCtx = useOptionalChatNameResolver();\n const senderIds = React.useMemo(() => {\n const set = new Set<string>();\n for (const m of messages) {\n set.add(m.senderId);\n for (const uid of m.referencedUids ?? []) set.add(uid);\n }\n return Array.from(set);\n }, [messages]);\n\n React.useEffect(() => {\n if (resolverCtx?.prewarm && senderIds.length > 0) {\n resolverCtx.prewarm(senderIds);\n }\n }, [resolverCtx, senderIds]);\n\n return {\n allowed,\n isInitialLoading: allowed ? isInitialLoading : false,\n messages,\n fetchOlder,\n hasOlder,\n isFetchingOlder,\n sourceState,\n error: allowed ? error : null,\n olderError: allowed ? olderError : null,\n retry,\n };\n}"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export type { ChatCoreConfig, ChatTransportMode, ChatRealtimeTransportConfig, MessageRenderer, MessageRendererRegistry, } from "./types.js";
|
|
2
|
-
export type { ChatNameResolverProviderProps } from "./context/ChatNameResolverContext.js";
|
|
3
|
-
export { ChatNameResolverProvider, useChatNameResolver, useOptionalChatNameResolver,
|
|
2
|
+
export type { ChatNameResolverProviderProps, UnresolvedChatName, } from "./context/ChatNameResolverContext.js";
|
|
3
|
+
export { ChatNameResolverProvider, useChatNameResolver, useOptionalChatNameResolver, useSenderNameResolution, } from "./context/ChatNameResolverContext.js";
|
|
4
|
+
export { SenderName } from "./ui/SenderName.js";
|
|
4
5
|
export type { UseChatMessagesResult } from "./hooks/useChatMessages.js";
|
|
5
6
|
export { useChatMessages } from "./hooks/useChatMessages.js";
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export type {
|
|
9
|
-
export type { ChatShellProps } from "./ui/ChatShell.js";
|
|
7
|
+
export { createRealtimeChatClient, createInboxClient, ChannelClient, InboxClient, useRealtimeChatMessages, browserSocketFactory, ChatAccessDeniedError, isChatAccessDeniedError, CHAT_INITIAL_LOAD_FAILURE_BUDGET_MS, CHAT_SUBPROTOCOL, CHAT_CLOSE_CODES, CLIENT_FRAME, SERVER_FRAME, buildFrame, parseFrame, CHAT_CLIENT_DIAGNOSTIC_EVENTS, } from "./realtime/index.js";
|
|
8
|
+
export type { RealtimeChatClient, RealtimeTransportConfig, ChatClientDiagnosticsOption, ChatClientDiagnosticsSink, ChatClientDiagnosticEventName, ChannelClientState, ChannelClientConfig, InboxClientState, InboxClientConfig, ChatMarkReadOutcome, UseRealtimeChatMessagesResult, GrantProvider, TransportTimers, RealtimeStatus, RealtimeSocket, SocketFactory, SocketHandlers, WireMessageRow, WireInboxSnapshot, WireRegistryEntry, ServerFrame, } from "./realtime/index.js";
|
|
9
|
+
export type { ChatShellProps, ChatLoadFailure } from "./ui/ChatShell.js";
|
|
10
10
|
export { ChatShell } from "./ui/ChatShell.js";
|
|
11
11
|
export { MessageList } from "./ui/MessageList.js";
|
|
12
12
|
export type { ComposerProps } from "./ui/Composer.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,EACf,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAGpB,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,EACf,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,6BAA6B,EAC7B,kBAAkB,GACnB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,YAAY,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAK7D,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,mCAAmC,EACnC,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,6BAA6B,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,6BAA6B,EAC7B,aAAa,EACb,eAAe,EACf,cAAc,EACd,cAAc,EACd,aAAa,EACb,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAU7B,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,YAAY,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { ChatNameResolverProvider, useChatNameResolver, useOptionalChatNameResolver,
|
|
2
|
+
export { ChatNameResolverProvider, useChatNameResolver, useOptionalChatNameResolver, useSenderNameResolution, } from "./context/ChatNameResolverContext.js";
|
|
3
|
+
export { SenderName } from "./ui/SenderName.js";
|
|
3
4
|
export { useChatMessages } from "./hooks/useChatMessages.js";
|
|
4
|
-
export { canAccessThread } from "./hooks/useChatThreadAccess.js";
|
|
5
5
|
// Realtime (Cloudflare Durable Object) transport — the client half of the chat
|
|
6
6
|
// worker wire protocol. Opt-in via `ChatCoreConfig.transport === 'realtime'`; the
|
|
7
7
|
// firestore transport stays the unchanged default. See docs/packages/chat-react.md.
|
|
8
|
-
export { createRealtimeChatClient, createInboxClient, ChannelClient, InboxClient, useRealtimeChatMessages, browserSocketFactory, ChatAccessDeniedError, isChatAccessDeniedError, CHAT_SUBPROTOCOL, CHAT_CLOSE_CODES, CLIENT_FRAME, SERVER_FRAME, buildFrame, parseFrame, CHAT_CLIENT_DIAGNOSTIC_EVENTS, } from "./realtime/index.js";
|
|
8
|
+
export { createRealtimeChatClient, createInboxClient, ChannelClient, InboxClient, useRealtimeChatMessages, browserSocketFactory, ChatAccessDeniedError, isChatAccessDeniedError, CHAT_INITIAL_LOAD_FAILURE_BUDGET_MS, CHAT_SUBPROTOCOL, CHAT_CLOSE_CODES, CLIENT_FRAME, SERVER_FRAME, buildFrame, parseFrame, CHAT_CLIENT_DIAGNOSTIC_EVENTS, } from "./realtime/index.js";
|
|
9
9
|
export { ChatShell } from "./ui/ChatShell.js";
|
|
10
10
|
export { MessageList } from "./ui/MessageList.js";
|
|
11
11
|
export { Composer } from "./ui/Composer.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAsBb,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,+EAA+E;AAC/E,kFAAkF;AAClF,oFAAoF;AACpF,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,mCAAmC,EACnC,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,6BAA6B,GAC9B,MAAM,qBAAqB,CAAC;AAkC7B,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAyB,MAAM,qBAAqB,CAAC","sourcesContent":["\"use client\";\n\n// @ttt-productions/chat-react — chat React UI, hooks, the Firebase-client\n// adapter config types, and React render types. Depends on the pure\n// @ttt-productions/chat-core for contracts, parser, and grouping.\n//\n// Apps import chat CSS via \"@ttt-productions/chat-react/styles\".\n\n// React-coupled config + render types (previously on chat-core root).\nexport type {\n ChatCoreConfig,\n ChatTransportMode,\n ChatRealtimeTransportConfig,\n MessageRenderer,\n MessageRendererRegistry,\n} from \"./types.js\";\n\n// Name-resolver context.\nexport type {\n ChatNameResolverProviderProps,\n UnresolvedChatName,\n} from \"./context/ChatNameResolverContext.js\";\nexport {\n ChatNameResolverProvider,\n useChatNameResolver,\n useOptionalChatNameResolver,\n useSenderNameResolution,\n} from \"./context/ChatNameResolverContext.js\";\nexport { SenderName } from \"./ui/SenderName.js\";\n\nexport type { UseChatMessagesResult } from \"./hooks/useChatMessages.js\";\nexport { useChatMessages } from \"./hooks/useChatMessages.js\";\n\n// Realtime (Cloudflare Durable Object) transport — the client half of the chat\n// worker wire protocol. Opt-in via `ChatCoreConfig.transport === 'realtime'`; the\n// firestore transport stays the unchanged default. See docs/packages/chat-react.md.\nexport {\n createRealtimeChatClient,\n createInboxClient,\n ChannelClient,\n InboxClient,\n useRealtimeChatMessages,\n browserSocketFactory,\n ChatAccessDeniedError,\n isChatAccessDeniedError,\n CHAT_INITIAL_LOAD_FAILURE_BUDGET_MS,\n CHAT_SUBPROTOCOL,\n CHAT_CLOSE_CODES,\n CLIENT_FRAME,\n SERVER_FRAME,\n buildFrame,\n parseFrame,\n CHAT_CLIENT_DIAGNOSTIC_EVENTS,\n} from \"./realtime/index.js\";\nexport type {\n RealtimeChatClient,\n RealtimeTransportConfig,\n ChatClientDiagnosticsOption,\n ChatClientDiagnosticsSink,\n ChatClientDiagnosticEventName,\n ChannelClientState,\n ChannelClientConfig,\n InboxClientState,\n InboxClientConfig,\n ChatMarkReadOutcome,\n UseRealtimeChatMessagesResult,\n GrantProvider,\n TransportTimers,\n RealtimeStatus,\n RealtimeSocket,\n SocketFactory,\n SocketHandlers,\n WireMessageRow,\n WireInboxSnapshot,\n WireRegistryEntry,\n ServerFrame,\n} from \"./realtime/index.js\";\n\n// TODO (re-export when a consumer needs them): the moderation-overlay helpers\n// `RevisionKind`, `ModerationOverlay`, `applyModerationOverlay`, `overlayFromRow`,\n// and `MODERATION_REDACTED_TEXT` live in `./realtime` but are intentionally NOT\n// re-exported from this package root yet — the consuming app's renderer reads moderation\n// state off `message.meta` (the realtime client applies the overlay internally), so\n// nothing imports them from here today. Add them to the block above when a consumer\n// genuinely needs to apply the overlay directly. (Comment-only; rides the next publish.)\n\nexport type { ChatShellProps, ChatLoadFailure } from \"./ui/ChatShell.js\";\nexport { ChatShell } from \"./ui/ChatShell.js\";\nexport { MessageList } from \"./ui/MessageList.js\";\nexport type { ComposerProps } from \"./ui/Composer.js\";\nexport { Composer } from \"./ui/Composer.js\";\nexport type { MessageItemDefaultProps } from \"./ui/MessageItemDefault.js\";\nexport { MessageItemDefault } from \"./ui/MessageItemDefault.js\";\nexport { MessageActions, ThreadActions } from \"./ui/menus.js\";\nexport { MessageText, type MessageTextProps } from \"./ui/MessageText.js\";\n"]}
|
|
@@ -27,6 +27,15 @@ export interface ChannelClientState {
|
|
|
27
27
|
* A grant retry / socket open before any snapshot leaves it false.
|
|
28
28
|
*/
|
|
29
29
|
hasLoadedInitialData: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* True once the first open has failed for good enough to say so: attempts have kept
|
|
32
|
+
* failing for {@link CHAT_INITIAL_LOAD_FAILURE_BUDGET_MS} without any initial data, or
|
|
33
|
+
* reconnecting stopped (gave up, or the socket was revoked) before any. The client keeps
|
|
34
|
+
* retrying in the background; the first authoritative data, or a manual `retryNow()`,
|
|
35
|
+
* clears it. Never true once initial data has loaded — a later outage keeps the loaded
|
|
36
|
+
* messages under the reconnect banner instead.
|
|
37
|
+
*/
|
|
38
|
+
initialLoadFailed: boolean;
|
|
30
39
|
}
|
|
31
40
|
export interface ChannelClientConfig {
|
|
32
41
|
/** WebSocket endpoint base, e.g. `wss://chat.example.com`. The client appends `/channel`. */
|
|
@@ -86,6 +95,15 @@ export declare class ChannelClient {
|
|
|
86
95
|
/** Single scheduled re-send for the membership-pending window (never stacks). */
|
|
87
96
|
private membershipRetryTimer;
|
|
88
97
|
private closedByUs;
|
|
98
|
+
/**
|
|
99
|
+
* The current lifecycle's number, advanced by every `connect()` and `close()`. A grant
|
|
100
|
+
* that resolves, or a timer that fires, for an older lifecycle is dropped — so a
|
|
101
|
+
* close → connect while an earlier grant is still minting can never open a second
|
|
102
|
+
* socket or touch the new lifecycle's state (FRONTEND-108).
|
|
103
|
+
*/
|
|
104
|
+
private lifecycle;
|
|
105
|
+
/** Reports the first open as failed once its attempts have failed for the budget. */
|
|
106
|
+
private readonly initialLoad;
|
|
89
107
|
/**
|
|
90
108
|
* Per-seq moderation overlay (the max-revision wins). A `revision` frame writes
|
|
91
109
|
* here keyed by `messageSeq` so it applies whether it arrives BEFORE its base
|
|
@@ -125,6 +143,20 @@ export declare class ChannelClient {
|
|
|
125
143
|
subscribe(fn: (s: ChannelClientState) => void): () => void;
|
|
126
144
|
private setState;
|
|
127
145
|
connect(): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Retry now (the first-open failure's Retry). While a reconnect is waiting out its
|
|
148
|
+
* backoff, the wait is cancelled and a socket opens at once; a lifecycle that stopped
|
|
149
|
+
* (reconnect gave up, or the socket was revoked) starts again; an attempt already in
|
|
150
|
+
* flight is left to finish. Either way the first-open failure clears, so the opening state
|
|
151
|
+
* shows while the retry runs. The spent budget stays spent: a retry that fails is reported
|
|
152
|
+
* again at once, and one that hangs a full budget later.
|
|
153
|
+
*/
|
|
154
|
+
retryNow(): void;
|
|
155
|
+
private startLifecycle;
|
|
156
|
+
/** The first open has failed for long enough to say so (see `initialLoadFailed`). */
|
|
157
|
+
private reportInitialLoadFailed;
|
|
158
|
+
/** The first authoritative data is applied; it ends any first-open failure. */
|
|
159
|
+
private initialDataLoaded;
|
|
128
160
|
private openSocket;
|
|
129
161
|
private onOpen;
|
|
130
162
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-client.d.ts","sourceRoot":"","sources":["../../src/realtime/channel-client.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAahE,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,aAAa,CAAC;AASjE,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAKL,KAAK,2BAA2B,EACjC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"channel-client.d.ts","sourceRoot":"","sources":["../../src/realtime/channel-client.ts"],"names":[],"mappings":"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"}
|