@parity/product-sdk-host 0.11.0 → 0.12.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/src/chat.ts CHANGED
@@ -1,72 +1,99 @@
1
1
  // Copyright 2026 Parity Technologies (UK) Ltd.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  /**
4
- * Wrapper for the host's chat surface (`host_chat_*` family).
4
+ * Wrapper for the host's chat surface, backed by `truApi.chat.*`.
5
5
  *
6
- * Shipped flat-in-host rather than as `getTruApi().chat.*` (the shape
7
- * sketched in issue #93) because the upstream JS `hostApi` is itself a
8
- * flat object - there is no `.chat` accessor to mirror. A flat
9
- * `getChatManager()` matches the pattern already used by
10
- * {@link getThemeProvider}, {@link getAccountsProvider}, and
11
- * {@link getStatementStore}; if a namespaced view is desirable later, it
12
- * can be layered on top without breaking this surface.
6
+ * `getChatManager()` returns a manager for room/bot registration, message
7
+ * sending, and subscription to the room list and incoming actions.
13
8
  *
14
9
  * @module
15
10
  */
16
11
 
17
- import { createLogger } from "@parity/product-sdk-logger";
18
-
19
12
  import type {
20
- ChatBotRegistrationResult as NovasamaChatBotRegistrationResult,
21
- ChatCustomMessageRenderer as NovasamaChatCustomMessageRenderer,
22
- ChatCustomMessageRendererParams as NovasamaChatCustomMessageRendererParams,
23
- ChatMessageContent as NovasamaChatMessageContent,
24
- ChatReceivedAction as NovasamaChatReceivedAction,
25
- ChatRoom as NovasamaChatRoom,
26
- ChatRoomRegistrationResult as NovasamaChatRoomRegistrationResult,
27
- createProductChatManager,
28
- } from "@novasamatech/host-api-wrapper";
29
-
30
- const log = createLogger("host:chat");
31
-
32
- /** Chat message payload variants. Re-exported from `@novasamatech/host-api-wrapper`. */
33
- export type ChatMessageContent = NovasamaChatMessageContent;
13
+ ChatBotRegistrationStatus,
14
+ ChatRoomRegistrationStatus,
15
+ HostChatActionSubscribeItem,
16
+ HostChatCreateRoomRequest,
17
+ HostChatRegisterBotRequest,
18
+ TrUApiClient,
19
+ } from "@parity/truapi";
34
20
 
35
- /** Action received via {@link ChatManager.subscribeAction}. Re-exported from `@novasamatech/host-api-wrapper`. */
36
- export type ChatReceivedAction = NovasamaChatReceivedAction;
21
+ import { getClient, subscribeWithInterrupt } from "./transport.js";
22
+ import { unwrapHostResult } from "./truapi.js";
23
+ import type { HostSubscription } from "./types.js";
37
24
 
38
- /** Room metadata delivered to {@link ChatManager.subscribeChatList}. Re-exported from `@novasamatech/host-api-wrapper`. */
39
- export type ChatRoom = NovasamaChatRoom;
25
+ /** Chat message payload variants and room metadata. Re-exported from `@parity/truapi`. */
26
+ export type { ChatMessageContent, ChatRoom } from "@parity/truapi";
27
+ import type { ChatMessageContent, ChatRoom } from "@parity/truapi";
40
28
 
41
- /** Result of registering a chat room (`"New" | "Exists"`). Re-exported from `@novasamatech/host-api-wrapper`. */
42
- export type ChatRoomRegistrationResult = NovasamaChatRoomRegistrationResult;
29
+ /** Action received via {@link ChatManager.subscribeAction} (`{ roomId, peer, payload }`). Re-exported from `@parity/truapi`. */
30
+ export type ChatReceivedAction = HostChatActionSubscribeItem;
43
31
 
44
- /** Result of registering a bot (`"New" | "Exists"`). Re-exported from `@novasamatech/host-api-wrapper`. */
45
- export type ChatBotRegistrationResult = NovasamaChatBotRegistrationResult;
32
+ /** Result of registering a chat room (`"New" | "Exists"`). Re-exported from `@parity/truapi`. */
33
+ export type ChatRoomRegistrationResult = ChatRoomRegistrationStatus;
46
34
 
47
- /** Renderer callback for custom message types. Re-exported from `@novasamatech/host-api-wrapper`. */
48
- export type ChatCustomMessageRenderer = NovasamaChatCustomMessageRenderer;
49
-
50
- /** Parameters passed to a {@link ChatCustomMessageRenderer}. Re-exported from `@novasamatech/host-api-wrapper`. */
51
- export type ChatCustomMessageRendererParams<T = Uint8Array> =
52
- NovasamaChatCustomMessageRendererParams<T>;
35
+ /** Result of registering a bot (`"New" | "Exists"`). Re-exported from `@parity/truapi`. */
36
+ export type ChatBotRegistrationResult = ChatBotRegistrationStatus;
53
37
 
54
38
  /**
55
- * Chat manager handle. Exposes room/bot registration, message sending,
56
- * subscription to room list and incoming actions, and custom-renderer
57
- * registration.
58
- *
59
- * Type identical to `createProductChatManager()` from
60
- * `@novasamatech/host-api-wrapper`.
39
+ * Chat manager handle. Exposes room/bot registration, message sending, and
40
+ * subscription to the room list and incoming actions.
61
41
  */
62
- export type ChatManager = ReturnType<typeof createProductChatManager>;
42
+ export interface ChatManager {
43
+ registerRoom(request: HostChatCreateRoomRequest): Promise<ChatRoomRegistrationResult>;
44
+ registerBot(request: HostChatRegisterBotRequest): Promise<ChatBotRegistrationResult>;
45
+ sendMessage(roomId: string, payload: ChatMessageContent): Promise<{ messageId: string }>;
46
+ subscribeChatList(callback: (rooms: ChatRoom[]) => void): HostSubscription;
47
+ subscribeAction(callback: (action: ChatReceivedAction) => void): HostSubscription;
48
+ }
49
+
50
+ /** Build a {@link ChatManager} over a TruAPI client's `chat` domain. */
51
+ function adaptChatManager(client: TrUApiClient): ChatManager {
52
+ const chat = client.chat;
53
+ // Cache registration status by id so repeat calls don't re-prompt the host.
54
+ const roomStatus = new Map<string, ChatRoomRegistrationResult>();
55
+ const botStatus = new Map<string, ChatBotRegistrationResult>();
56
+
57
+ return {
58
+ async registerRoom(request) {
59
+ const cached = roomStatus.get(request.roomId);
60
+ if (cached) return cached;
61
+ const response = await unwrapHostResult(
62
+ chat.createRoom(request),
63
+ "chat registerRoom failed",
64
+ );
65
+ roomStatus.set(request.roomId, response.status);
66
+ return response.status;
67
+ },
68
+ async registerBot(request) {
69
+ const cached = botStatus.get(request.botId);
70
+ if (cached) return cached;
71
+ const response = await unwrapHostResult(
72
+ chat.registerBot(request),
73
+ "chat registerBot failed",
74
+ );
75
+ botStatus.set(request.botId, response.status);
76
+ return response.status;
77
+ },
78
+ async sendMessage(roomId, payload) {
79
+ const response = await unwrapHostResult(
80
+ chat.postMessage({ roomId, payload }),
81
+ "chat sendMessage failed",
82
+ );
83
+ return { messageId: response.messageId };
84
+ },
85
+ subscribeChatList(callback) {
86
+ return subscribeWithInterrupt(chat.listSubscribe(), (item) => callback(item.rooms));
87
+ },
88
+ subscribeAction(callback) {
89
+ return subscribeWithInterrupt(chat.actionSubscribe(), callback);
90
+ },
91
+ };
92
+ }
63
93
 
64
94
  /**
65
- * Get the host chat manager.
66
- *
67
- * Returns the chat manager from `@novasamatech/host-api-wrapper`, or `null` if
68
- * the package is unavailable (running outside a host container or the
69
- * optional peer dep isn't installed).
95
+ * Get the host chat manager, backed by `truApi.chat.*`. Returns `null` when
96
+ * running outside a host container.
70
97
  *
71
98
  * @returns The chat manager, or `null` if unavailable.
72
99
  *
@@ -82,45 +109,14 @@ export type ChatManager = ReturnType<typeof createProductChatManager>;
82
109
  * ```
83
110
  */
84
111
  export async function getChatManager(): Promise<ChatManager | null> {
85
- try {
86
- const sdk = await import("@novasamatech/host-api-wrapper");
87
- return sdk.createProductChatManager();
88
- } catch (err) {
89
- log.debug("getChatManager unavailable", err);
90
- return null;
91
- }
92
- }
93
-
94
- /**
95
- * Dispatch helper that composes multiple custom-message renderers into a
96
- * single {@link ChatCustomMessageRenderer} keyed by `messageType`.
97
- *
98
- * Mirrors `matchChatCustomRenderers` from `@novasamatech/host-api-wrapper`
99
- * inline (the upstream implementation is pure dispatch logic with no
100
- * transport / runtime dependency on Novasama), so callers get the same
101
- * sync signature instead of an async-with-null wrapper.
102
- *
103
- * @param map - Object mapping `messageType` strings to renderers.
104
- * @returns A composed renderer that dispatches to the entry matching
105
- * `params.messageType`, or throws if no renderer is registered.
106
- */
107
- export function matchChatCustomRenderers(
108
- map: Record<string, ChatCustomMessageRenderer>,
109
- ): ChatCustomMessageRenderer {
110
- return (params, render) => {
111
- const renderer = map[params.messageType];
112
- if (!renderer) {
113
- throw new Error(`Renderer for message type ${params.messageType} is not defined`);
114
- }
115
- return renderer(params, render);
116
- };
112
+ const client = await getClient();
113
+ return client ? adaptChatManager(client) : null;
117
114
  }
118
115
 
119
116
  if (import.meta.vitest) {
120
117
  const { test, expect } = import.meta.vitest;
121
118
 
122
- test("getChatManager returns manager when SDK is available", async () => {
123
- const chat = await getChatManager();
124
- expect(chat === null || typeof chat === "object").toBe(true);
119
+ test("getChatManager returns null outside a container", async () => {
120
+ expect(await getChatManager()).toBeNull();
125
121
  });
126
122
  }